summaryrefslogtreecommitdiffstats
path: root/third_party/rust/sfv/src/ref_serializer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/sfv/src/ref_serializer.rs')
-rw-r--r--third_party/rust/sfv/src/ref_serializer.rs310
1 files changed, 310 insertions, 0 deletions
diff --git a/third_party/rust/sfv/src/ref_serializer.rs b/third_party/rust/sfv/src/ref_serializer.rs
new file mode 100644
index 0000000000..4bcd29ff3a
--- /dev/null
+++ b/third_party/rust/sfv/src/ref_serializer.rs
@@ -0,0 +1,310 @@
+use crate::serializer::Serializer;
+use crate::{RefBareItem, SFVResult};
+use std::marker::PhantomData;
+
+/// Serializes `Item` field value components incrementally.
+/// ```
+/// use sfv::{RefBareItem, RefItemSerializer};
+///
+/// let mut serialized_item = String::new();
+/// let serializer = RefItemSerializer::new(&mut serialized_item);
+/// serializer
+/// .bare_item(&RefBareItem::Integer(11))
+/// .unwrap()
+/// .parameter("foo", &RefBareItem::Boolean(true))
+/// .unwrap();
+/// assert_eq!(serialized_item, "11;foo");
+/// ```
+#[derive(Debug)]
+pub struct RefItemSerializer<'a> {
+ pub buffer: &'a mut String,
+}
+
+impl<'a> RefItemSerializer<'a> {
+ pub fn new(buffer: &'a mut String) -> Self {
+ RefItemSerializer { buffer }
+ }
+
+ pub fn bare_item(self, bare_item: &RefBareItem) -> SFVResult<RefParameterSerializer<'a>> {
+ Serializer::serialize_ref_bare_item(bare_item, self.buffer)?;
+ Ok(RefParameterSerializer {
+ buffer: self.buffer,
+ })
+ }
+}
+
+/// Used by `RefItemSerializer`, `RefListSerializer`, `RefDictSerializer` to serialize a single `Parameter`.
+#[derive(Debug)]
+pub struct RefParameterSerializer<'a> {
+ buffer: &'a mut String,
+}
+
+impl<'a> RefParameterSerializer<'a> {
+ pub fn parameter(self, name: &str, value: &RefBareItem) -> SFVResult<Self> {
+ Serializer::serialize_ref_parameter(name, value, self.buffer)?;
+ Ok(self)
+ }
+}
+
+/// Serializes `List` field value components incrementally.
+/// ```
+/// use sfv::{RefBareItem, RefListSerializer};
+///
+/// let mut serialized_item = String::new();
+/// let serializer = RefListSerializer::new(&mut serialized_item);
+/// serializer
+/// .bare_item(&RefBareItem::Integer(11))
+/// .unwrap()
+/// .parameter("foo", &RefBareItem::Boolean(true))
+/// .unwrap()
+/// .open_inner_list()
+/// .inner_list_bare_item(&RefBareItem::Token("abc"))
+/// .unwrap()
+/// .inner_list_parameter("abc_param", &RefBareItem::Boolean(false))
+/// .unwrap()
+/// .inner_list_bare_item(&RefBareItem::Token("def"))
+/// .unwrap()
+/// .close_inner_list()
+/// .parameter("bar", &RefBareItem::String("val"))
+/// .unwrap();
+/// assert_eq!(
+/// serialized_item,
+/// "11;foo, (abc;abc_param=?0 def);bar=\"val\""
+/// );
+/// ```
+#[derive(Debug)]
+pub struct RefListSerializer<'a> {
+ buffer: &'a mut String,
+}
+
+impl<'a> RefListSerializer<'a> {
+ pub fn new(buffer: &'a mut String) -> Self {
+ RefListSerializer { buffer }
+ }
+
+ pub fn bare_item(self, bare_item: &RefBareItem) -> SFVResult<Self> {
+ if !self.buffer.is_empty() {
+ self.buffer.push_str(", ");
+ }
+ Serializer::serialize_ref_bare_item(bare_item, self.buffer)?;
+ Ok(RefListSerializer {
+ buffer: self.buffer,
+ })
+ }
+
+ pub fn parameter(self, name: &str, value: &RefBareItem) -> SFVResult<Self> {
+ if self.buffer.is_empty() {
+ return Err("parameters must be serialized after bare item or inner list");
+ }
+ Serializer::serialize_ref_parameter(name, value, self.buffer)?;
+ Ok(RefListSerializer {
+ buffer: self.buffer,
+ })
+ }
+ pub fn open_inner_list(self) -> RefInnerListSerializer<'a, Self> {
+ if !self.buffer.is_empty() {
+ self.buffer.push_str(", ");
+ }
+ self.buffer.push('(');
+ RefInnerListSerializer::<RefListSerializer> {
+ buffer: self.buffer,
+ caller_type: PhantomData,
+ }
+ }
+}
+
+/// Serializes `Dictionary` field value components incrementally.
+/// ```
+/// use sfv::{RefBareItem, RefDictSerializer, Decimal, FromPrimitive};
+///
+/// let mut serialized_item = String::new();
+/// let serializer = RefDictSerializer::new(&mut serialized_item);
+/// serializer
+/// .bare_item_member("member1", &RefBareItem::Integer(11))
+/// .unwrap()
+/// .parameter("foo", &RefBareItem::Boolean(true))
+/// .unwrap()
+/// .open_inner_list("member2")
+/// .unwrap()
+/// .inner_list_bare_item(&RefBareItem::Token("abc"))
+/// .unwrap()
+/// .inner_list_parameter("abc_param", &RefBareItem::Boolean(false))
+/// .unwrap()
+/// .inner_list_bare_item(&RefBareItem::Token("def"))
+/// .unwrap()
+/// .close_inner_list()
+/// .parameter("bar", &RefBareItem::String("val"))
+/// .unwrap()
+/// .bare_item_member(
+/// "member3",
+/// &RefBareItem::Decimal(Decimal::from_f64(12.34566).unwrap()),
+/// )
+/// .unwrap();
+/// assert_eq!(
+/// serialized_item,
+/// "member1=11;foo, member2=(abc;abc_param=?0 def);bar=\"val\", member3=12.346"
+/// );
+/// ```
+#[derive(Debug)]
+pub struct RefDictSerializer<'a> {
+ buffer: &'a mut String,
+}
+
+impl<'a> RefDictSerializer<'a> {
+ pub fn new(buffer: &'a mut String) -> Self {
+ RefDictSerializer { buffer }
+ }
+
+ pub fn bare_item_member(self, name: &str, value: &RefBareItem) -> SFVResult<Self> {
+ if !self.buffer.is_empty() {
+ self.buffer.push_str(", ");
+ }
+ Serializer::serialize_key(name, self.buffer)?;
+ if value != &RefBareItem::Boolean(true) {
+ self.buffer.push('=');
+ Serializer::serialize_ref_bare_item(value, self.buffer)?;
+ }
+ Ok(self)
+ }
+
+ pub fn parameter(self, name: &str, value: &RefBareItem) -> SFVResult<Self> {
+ if self.buffer.is_empty() {
+ return Err("parameters must be serialized after bare item or inner list");
+ }
+ Serializer::serialize_ref_parameter(name, value, self.buffer)?;
+ Ok(RefDictSerializer {
+ buffer: self.buffer,
+ })
+ }
+
+ pub fn open_inner_list(self, name: &str) -> SFVResult<RefInnerListSerializer<'a, Self>> {
+ if !self.buffer.is_empty() {
+ self.buffer.push_str(", ");
+ }
+ Serializer::serialize_key(name, self.buffer)?;
+ self.buffer.push_str("=(");
+ Ok(RefInnerListSerializer::<RefDictSerializer> {
+ buffer: self.buffer,
+ caller_type: PhantomData,
+ })
+ }
+}
+
+/// Used by `RefItemSerializer`, `RefListSerializer`, `RefDictSerializer` to serialize `InnerList`.
+#[derive(Debug)]
+pub struct RefInnerListSerializer<'a, T> {
+ buffer: &'a mut String,
+ caller_type: PhantomData<T>,
+}
+
+impl<'a, T: Container<'a>> RefInnerListSerializer<'a, T> {
+ pub fn inner_list_bare_item(self, bare_item: &RefBareItem) -> SFVResult<Self> {
+ if !self.buffer.is_empty() & !self.buffer.ends_with('(') {
+ self.buffer.push(' ');
+ }
+ Serializer::serialize_ref_bare_item(bare_item, self.buffer)?;
+ Ok(RefInnerListSerializer {
+ buffer: self.buffer,
+ caller_type: PhantomData,
+ })
+ }
+
+ pub fn inner_list_parameter(self, name: &str, value: &RefBareItem) -> SFVResult<Self> {
+ if self.buffer.is_empty() {
+ return Err("parameters must be serialized after bare item or inner list");
+ }
+ Serializer::serialize_ref_parameter(name, value, self.buffer)?;
+ Ok(RefInnerListSerializer {
+ buffer: self.buffer,
+ caller_type: PhantomData,
+ })
+ }
+
+ pub fn close_inner_list(self) -> T {
+ self.buffer.push(')');
+ T::new(self.buffer)
+ }
+}
+
+pub trait Container<'a> {
+ fn new(buffer: &'a mut String) -> Self;
+}
+
+impl<'a> Container<'a> for RefListSerializer<'a> {
+ fn new(buffer: &mut String) -> RefListSerializer {
+ RefListSerializer { buffer }
+ }
+}
+
+impl<'a> Container<'a> for RefDictSerializer<'a> {
+ fn new(buffer: &mut String) -> RefDictSerializer {
+ RefDictSerializer { buffer }
+ }
+}
+
+#[cfg(test)]
+mod alternative_serializer_tests {
+ use super::*;
+ use crate::{Decimal, FromPrimitive};
+
+ #[test]
+ fn test_fast_serialize_item() -> SFVResult<()> {
+ let mut output = String::new();
+ let ser = RefItemSerializer::new(&mut output);
+ ser.bare_item(&RefBareItem::Token("hello"))?
+ .parameter("abc", &RefBareItem::Boolean(true))?;
+ assert_eq!("hello;abc", output);
+ Ok(())
+ }
+
+ #[test]
+ fn test_fast_serialize_list() -> SFVResult<()> {
+ let mut output = String::new();
+ let ser = RefListSerializer::new(&mut output);
+ ser.bare_item(&RefBareItem::Token("hello"))?
+ .parameter("key1", &RefBareItem::Boolean(true))?
+ .parameter("key2", &RefBareItem::Boolean(false))?
+ .open_inner_list()
+ .inner_list_bare_item(&RefBareItem::String("some_string"))?
+ .inner_list_bare_item(&RefBareItem::Integer(12))?
+ .inner_list_parameter("inner-member-key", &RefBareItem::Boolean(true))?
+ .close_inner_list()
+ .parameter("inner-list-param", &RefBareItem::Token("*"))?;
+ assert_eq!(
+ "hello;key1;key2=?0, (\"some_string\" 12;inner-member-key);inner-list-param=*",
+ output
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn test_fast_serialize_dict() -> SFVResult<()> {
+ let mut output = String::new();
+ let ser = RefDictSerializer::new(&mut output);
+ ser.bare_item_member("member1", &RefBareItem::Token("hello"))?
+ .parameter("key1", &RefBareItem::Boolean(true))?
+ .parameter("key2", &RefBareItem::Boolean(false))?
+ .bare_item_member("member2", &RefBareItem::Boolean(true))?
+ .parameter(
+ "key3",
+ &RefBareItem::Decimal(Decimal::from_f64(45.4586).unwrap()),
+ )?
+ .parameter("key4", &RefBareItem::String("str"))?
+ .open_inner_list("key5")?
+ .inner_list_bare_item(&RefBareItem::Integer(45))?
+ .inner_list_bare_item(&RefBareItem::Integer(0))?
+ .close_inner_list()
+ .bare_item_member("key6", &RefBareItem::String("foo"))?
+ .open_inner_list("key7")?
+ .inner_list_bare_item(&RefBareItem::ByteSeq("some_string".as_bytes()))?
+ .inner_list_bare_item(&RefBareItem::ByteSeq("other_string".as_bytes()))?
+ .close_inner_list()
+ .parameter("lparam", &RefBareItem::Integer(10))?
+ .bare_item_member("key8", &RefBareItem::Boolean(true))?;
+ assert_eq!(
+ "member1=hello;key1;key2=?0, member2;key3=45.459;key4=\"str\", key5=(45 0), key6=\"foo\", key7=(:c29tZV9zdHJpbmc=: :b3RoZXJfc3RyaW5n:);lparam=10, key8",
+ output
+ );
+ Ok(())
+ }
+}