1use crate::code_page::CodePage;
2use crate::serde_helpers::StringSerde;
3use std::fmt::{self, Debug, Formatter};
4use std::iter::{self};
5use serde::{Serialize, Deserialize, Serializer, Deserializer};
6use serde::ser::SerializeSeq;
7use serde::ser::Error as ser_Error;
8use serde::de::{self, DeserializeSeed};
9use serde_serialize_seed::{SerializeSeed, ValueWithSeed};
10
11#[derive(Clone, Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
12pub struct StringZ {
13 pub string: String,
14 pub has_tail_zero: bool
15}
16
17impl Default for StringZ {
18 fn default() -> StringZ { StringZ { string: String::default(), has_tail_zero: true } }
19}
20
21impl<T: Into<String>> From<T> for StringZ {
22 fn from(t: T) -> StringZ { StringZ { string: t.into(), has_tail_zero: true } }
23}
24
25#[derive(Clone)]
26pub struct StringZSerde {
27 pub code_page: Option<CodePage>,
28}
29
30impl SerializeSeed for StringZSerde {
31 type Value = StringZ;
32
33 fn serialize<S>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
34 if serializer.is_human_readable() {
35 let mut carets = value.string.len() - value.string.rfind(|x| x != '^')
36 .map_or(0, |i| i + value.string[i..].chars().next().unwrap().len_utf8());
37 if !value.has_tail_zero {
38 carets += 1;
39 }
40 let mut s = String::with_capacity(value.string.len() + carets);
41 s.push_str(&value.string);
42 s.extend(iter::repeat('^').take(carets));
43 s.serialize(serializer)
44 } else {
45 if !value.has_tail_zero && value.string.as_bytes().last() == Some(&0) {
46 return Err(S::Error::custom("zero-terminated string value has tail zero"));
47 }
48 let mut s = String::with_capacity(value.string.len() + if value.has_tail_zero { 1 } else { 0 });
49 s.push_str(&value.string);
50 if value.has_tail_zero {
51 s.push('\0');
52 }
53 ValueWithSeed(s.as_str(), StringSerde { code_page: self.code_page, len: None }).serialize(serializer)
54 }
55 }
56}
57
58impl<'de> DeserializeSeed<'de> for StringZSerde {
59 type Value = StringZ;
60
61 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where D: Deserializer<'de> {
62 if deserializer.is_human_readable() {
63 let mut string = String::deserialize(deserializer)?;
64 let carets = string.len() - string.rfind(|x| x != '^').map_or(0, |i| i + string[i..].chars().next().unwrap().len_utf8());
65 let has_tail_zero = carets % 2 == 0;
66 let carets = (carets + 1) / 2;
67 string.truncate(string.len() - carets);
68 Ok(StringZ { string, has_tail_zero })
69 } else {
70 let mut string = StringSerde { code_page: self.code_page, len: None }.deserialize(deserializer)?;
71 let has_tail_zero = string.as_bytes().last() == Some(&0);
72 if has_tail_zero {
73 string.truncate(string.len() - 1);
74 }
75 Ok(StringZ { string, has_tail_zero })
76 }
77 }
78}
79
80#[derive(Clone, Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
81pub struct StringZList {
82 pub vec: Vec<String>,
83 pub has_tail_zero: bool
84}
85
86impl Default for StringZList {
87 fn default() -> StringZList { StringZList { vec: Vec::default(), has_tail_zero: true } }
88}
89
90impl<T: Into<Vec<String>>> From<T> for StringZList {
91 fn from(t: T) -> StringZList { StringZList { vec: t.into(), has_tail_zero: true } }
92}
93
94#[derive(Clone)]
95pub struct StringZListSerde {
96 pub code_page: Option<CodePage>
97}
98
99impl SerializeSeed for StringZListSerde {
100 type Value = StringZList;
101
102 fn serialize<S>(&self, value: &Self::Value, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
103 if serializer.is_human_readable() {
104 let mut carets = value.vec.len() - value.vec.iter().rposition(|x| x != "^").map_or(0, |i| i + 1);
105 if !value.has_tail_zero {
106 carets += 1;
107 }
108 let mut serializer = serializer.serialize_seq(Some(value.vec.len() + carets))?;
109 for s in &value.vec {
110 serializer.serialize_element(s)?;
111 }
112 for _ in 0..carets {
113 serializer.serialize_element("^")?;
114 }
115 serializer.end()
116 } else {
117 let mut capacity = 0;
118 for s in &value.vec {
119 if s.contains('\0') {
120 return Err(S::Error::custom("zero-terminated string list item contains zero byte"));
121 }
122 capacity += s.len() + 1;
123 }
124 let mut text = String::with_capacity(capacity);
125 for s in &value.vec {
126 text.push_str(s);
127 text.push('\0');
128 }
129 if !value.has_tail_zero {
130 text.truncate(text.len() - 1);
131 }
132 ValueWithSeed(text.as_str(), StringSerde { code_page: self.code_page, len: None }).serialize(serializer)
133 }
134 }
135}
136
137struct StringZListHRDeVisitor;
138
139impl<'de> de::Visitor<'de> for StringZListHRDeVisitor {
140 type Value = StringZList;
141
142 fn expecting(&self, f: &mut Formatter) -> fmt::Result {
143 write!(f, "string sequence")
144 }
145
146 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: de::SeqAccess<'de> {
147 let mut vec: Vec<String> = seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);
148 while let Some(line) = seq.next_element()? {
149 vec.push(line);
150 }
151 let carets = vec.len() - vec.iter().rposition(|x| x != "^").map_or(0, |i| i + 1);
152 let has_tail_zero = carets % 2 == 0;
153 let carets = (carets + 1) / 2;
154 vec.truncate(vec.len() - carets);
155 Ok(StringZList { vec, has_tail_zero })
156 }
157}
158
159impl<'de> DeserializeSeed<'de> for StringZListSerde {
160 type Value = StringZList;
161
162 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where D: Deserializer<'de> {
163 if deserializer.is_human_readable() {
164 deserializer.deserialize_seq(StringZListHRDeVisitor)
165 } else {
166 let v = StringSerde { code_page: self.code_page, len: None }.deserialize(deserializer)?;
167 let has_tail_zero = v.as_bytes().last() == Some(&0);
168 let v = if has_tail_zero { &v[.. v.len() - 1] } else { &v };
169 Ok(StringZList { vec: v.split('\0').map(|x| x.into()).collect(), has_tail_zero })
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use crate::*;
177
178 #[test]
179 fn string_into_string_z() {
180 let z = Field::StringZ(String::from("Y").into());
181 if let Field::StringZ(z) = z {
182 assert_eq!(z.string, "Y");
183 } else {
184 panic!()
185 }
186 let z = Field::StringZ("Y".into());
187 if let Field::StringZ(z) = z {
188 assert_eq!(z.string, "Y");
189 } else {
190 panic!()
191 }
192 }
193}