| 1 | use crate::errors::serialize::DeError;
|
| 2 | use serde::ser::{Impossible, Serialize, Serializer};
|
| 3 | use serde::serde_if_integer128;
|
| 4 | use std::fmt::Write;
|
| 5 |
|
| 6 | /// A serializer, that ensures, that only plain types can be serialized,
|
| 7 | /// so result can be used as an XML tag or attribute name.
|
| 8 | ///
|
| 9 | /// This serializer does not check that name does not contain characters that
|
| 10 | /// [not allowed] in XML names, because in some cases it should pass names
|
| 11 | /// that would be filtered on higher level.
|
| 12 | ///
|
| 13 | /// [not allowed]: https://www.w3.org/TR/xml11/#sec-common-syn
|
| 14 | pub struct QNameSerializer<W: Write> {
|
| 15 | /// Writer to which this serializer writes content
|
| 16 | pub writer: W,
|
| 17 | }
|
| 18 |
|
| 19 | impl<W: Write> QNameSerializer<W> {
|
| 20 | #[inline ]
|
| 21 | fn write_str(&mut self, value: &str) -> Result<(), DeError> {
|
| 22 | Ok(self.writer.write_str(value)?)
|
| 23 | }
|
| 24 | }
|
| 25 |
|
| 26 | impl<W: Write> Serializer for QNameSerializer<W> {
|
| 27 | type Ok = W;
|
| 28 | type Error = DeError;
|
| 29 |
|
| 30 | type SerializeSeq = Impossible<Self::Ok, Self::Error>;
|
| 31 | type SerializeTuple = Impossible<Self::Ok, Self::Error>;
|
| 32 | type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
|
| 33 | type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
| 34 | type SerializeMap = Impossible<Self::Ok, Self::Error>;
|
| 35 | type SerializeStruct = Impossible<Self::Ok, Self::Error>;
|
| 36 | type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
|
| 37 |
|
| 38 | write_primitive!();
|
| 39 |
|
| 40 | fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
|
| 41 | self.write_str(value)?;
|
| 42 | Ok(self.writer)
|
| 43 | }
|
| 44 |
|
| 45 | /// Because unit type can be represented only by empty string which is not
|
| 46 | /// a valid XML name, serialization of unit returns `Err(Unsupported)`
|
| 47 | fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
| 48 | Err(DeError::Unsupported(
|
| 49 | "unit type `()` cannot be serialized as an XML tag name" .into(),
|
| 50 | ))
|
| 51 | }
|
| 52 |
|
| 53 | /// Because unit struct can be represented only by empty string which is not
|
| 54 | /// a valid XML name, serialization of unit struct returns `Err(Unsupported)`
|
| 55 | fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
|
| 56 | Err(DeError::Unsupported(
|
| 57 | format!(
|
| 58 | "unit struct ` {}` cannot be serialized as an XML tag name" ,
|
| 59 | name
|
| 60 | )
|
| 61 | .into(),
|
| 62 | ))
|
| 63 | }
|
| 64 |
|
| 65 | /// We cannot store both a variant discriminant and a variant value,
|
| 66 | /// so serialization of enum newtype variant returns `Err(Unsupported)`
|
| 67 | fn serialize_newtype_variant<T: ?Sized + Serialize>(
|
| 68 | self,
|
| 69 | name: &'static str,
|
| 70 | _variant_index: u32,
|
| 71 | variant: &'static str,
|
| 72 | _value: &T,
|
| 73 | ) -> Result<Self::Ok, DeError> {
|
| 74 | Err(DeError::Unsupported(
|
| 75 | format!(
|
| 76 | "enum newtype variant ` {}:: {}` cannot be serialized as an XML tag name" ,
|
| 77 | name, variant
|
| 78 | )
|
| 79 | .into(),
|
| 80 | ))
|
| 81 | }
|
| 82 |
|
| 83 | fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
| 84 | Err(DeError::Unsupported(
|
| 85 | "sequence cannot be serialized as an XML tag name" .into(),
|
| 86 | ))
|
| 87 | }
|
| 88 |
|
| 89 | fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
| 90 | Err(DeError::Unsupported(
|
| 91 | "tuple cannot be serialized as an XML tag name" .into(),
|
| 92 | ))
|
| 93 | }
|
| 94 |
|
| 95 | fn serialize_tuple_struct(
|
| 96 | self,
|
| 97 | name: &'static str,
|
| 98 | _len: usize,
|
| 99 | ) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
| 100 | Err(DeError::Unsupported(
|
| 101 | format!(
|
| 102 | "tuple struct ` {}` cannot be serialized as an XML tag name" ,
|
| 103 | name
|
| 104 | )
|
| 105 | .into(),
|
| 106 | ))
|
| 107 | }
|
| 108 |
|
| 109 | fn serialize_tuple_variant(
|
| 110 | self,
|
| 111 | name: &'static str,
|
| 112 | _variant_index: u32,
|
| 113 | variant: &'static str,
|
| 114 | _len: usize,
|
| 115 | ) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
| 116 | Err(DeError::Unsupported(
|
| 117 | format!(
|
| 118 | "enum tuple variant ` {}:: {}` cannot be serialized as an XML tag name" ,
|
| 119 | name, variant
|
| 120 | )
|
| 121 | .into(),
|
| 122 | ))
|
| 123 | }
|
| 124 |
|
| 125 | fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
| 126 | Err(DeError::Unsupported(
|
| 127 | "map cannot be serialized as an XML tag name" .into(),
|
| 128 | ))
|
| 129 | }
|
| 130 |
|
| 131 | fn serialize_struct(
|
| 132 | self,
|
| 133 | name: &'static str,
|
| 134 | _len: usize,
|
| 135 | ) -> Result<Self::SerializeStruct, Self::Error> {
|
| 136 | Err(DeError::Unsupported(
|
| 137 | format!("struct ` {}` cannot be serialized as an XML tag name" , name).into(),
|
| 138 | ))
|
| 139 | }
|
| 140 |
|
| 141 | fn serialize_struct_variant(
|
| 142 | self,
|
| 143 | name: &'static str,
|
| 144 | _variant_index: u32,
|
| 145 | variant: &'static str,
|
| 146 | _len: usize,
|
| 147 | ) -> Result<Self::SerializeStructVariant, Self::Error> {
|
| 148 | Err(DeError::Unsupported(
|
| 149 | format!(
|
| 150 | "enum struct variant ` {}:: {}` cannot be serialized as an XML tag name" ,
|
| 151 | name, variant
|
| 152 | )
|
| 153 | .into(),
|
| 154 | ))
|
| 155 | }
|
| 156 | }
|
| 157 |
|
| 158 | #[cfg (test)]
|
| 159 | mod tests {
|
| 160 | use super::*;
|
| 161 | use crate::utils::Bytes;
|
| 162 | use pretty_assertions::assert_eq;
|
| 163 | use serde::Serialize;
|
| 164 | use std::collections::BTreeMap;
|
| 165 |
|
| 166 | #[derive (Debug, Serialize, PartialEq)]
|
| 167 | struct Unit;
|
| 168 |
|
| 169 | #[derive (Debug, Serialize, PartialEq)]
|
| 170 | struct Newtype(bool);
|
| 171 |
|
| 172 | #[derive (Debug, Serialize, PartialEq)]
|
| 173 | struct Tuple(&'static str, usize);
|
| 174 |
|
| 175 | #[derive (Debug, Serialize, PartialEq)]
|
| 176 | struct Struct {
|
| 177 | key: &'static str,
|
| 178 | val: usize,
|
| 179 | }
|
| 180 |
|
| 181 | #[derive (Debug, Serialize, PartialEq)]
|
| 182 | enum Enum {
|
| 183 | Unit,
|
| 184 | #[serde(rename = "< \"&'>" )]
|
| 185 | UnitEscaped,
|
| 186 | Newtype(bool),
|
| 187 | Tuple(&'static str, usize),
|
| 188 | Struct {
|
| 189 | key: &'static str,
|
| 190 | val: usize,
|
| 191 | },
|
| 192 | }
|
| 193 |
|
| 194 | /// Checks that given `$data` successfully serialized as `$expected`
|
| 195 | macro_rules! serialize_as {
|
| 196 | ($name:ident: $data:expr => $expected:literal) => {
|
| 197 | #[test]
|
| 198 | fn $name() {
|
| 199 | let ser = QNameSerializer {
|
| 200 | writer: String::new(),
|
| 201 | };
|
| 202 |
|
| 203 | let buffer = $data.serialize(ser).unwrap();
|
| 204 | assert_eq!(buffer, $expected);
|
| 205 | }
|
| 206 | };
|
| 207 | }
|
| 208 |
|
| 209 | /// Checks that attempt to serialize given `$data` results to a
|
| 210 | /// serialization error `$kind` with `$reason`
|
| 211 | macro_rules! err {
|
| 212 | ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
|
| 213 | #[test]
|
| 214 | fn $name() {
|
| 215 | let mut buffer = String::new();
|
| 216 | let ser = QNameSerializer {
|
| 217 | writer: &mut buffer,
|
| 218 | };
|
| 219 |
|
| 220 | match $data.serialize(ser).unwrap_err() {
|
| 221 | DeError::$kind(e) => assert_eq!(e, $reason),
|
| 222 | e => panic!(
|
| 223 | "Expected `{}({})`, found `{:?}`" ,
|
| 224 | stringify!($kind),
|
| 225 | $reason,
|
| 226 | e
|
| 227 | ),
|
| 228 | }
|
| 229 | assert_eq!(buffer, "" );
|
| 230 | }
|
| 231 | };
|
| 232 | }
|
| 233 |
|
| 234 | serialize_as!(false_: false => "false" );
|
| 235 | serialize_as!(true_: true => "true" );
|
| 236 |
|
| 237 | serialize_as!(i8_: -42i8 => "-42" );
|
| 238 | serialize_as!(i16_: -4200i16 => "-4200" );
|
| 239 | serialize_as!(i32_: -42000000i32 => "-42000000" );
|
| 240 | serialize_as!(i64_: -42000000000000i64 => "-42000000000000" );
|
| 241 | serialize_as!(isize_: -42000000000000isize => "-42000000000000" );
|
| 242 |
|
| 243 | serialize_as!(u8_: 42u8 => "42" );
|
| 244 | serialize_as!(u16_: 4200u16 => "4200" );
|
| 245 | serialize_as!(u32_: 42000000u32 => "42000000" );
|
| 246 | serialize_as!(u64_: 42000000000000u64 => "42000000000000" );
|
| 247 | serialize_as!(usize_: 42000000000000usize => "42000000000000" );
|
| 248 |
|
| 249 | serde_if_integer128! {
|
| 250 | serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000" );
|
| 251 | serialize_as!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000" );
|
| 252 | }
|
| 253 |
|
| 254 | serialize_as!(f32_: 4.2f32 => "4.2" );
|
| 255 | serialize_as!(f64_: 4.2f64 => "4.2" );
|
| 256 |
|
| 257 | serialize_as!(char_non_escaped: 'h' => "h" );
|
| 258 | serialize_as!(char_lt: '<' => "<" );
|
| 259 | serialize_as!(char_gt: '>' => ">" );
|
| 260 | serialize_as!(char_amp: '&' => "&" );
|
| 261 | serialize_as!(char_apos: ' \'' => "'" );
|
| 262 | serialize_as!(char_quot: '"' => " \"" );
|
| 263 |
|
| 264 | serialize_as!(str_valid_name: "valid-name" => "valid-name" );
|
| 265 | serialize_as!(str_space: "string with spaces" => "string with spaces" );
|
| 266 | serialize_as!(str_lt: "string<" => "string<" );
|
| 267 | serialize_as!(str_gt: "string>" => "string>" );
|
| 268 | serialize_as!(str_amp: "string&" => "string&" );
|
| 269 | serialize_as!(str_apos: "string'" => "string'" );
|
| 270 | serialize_as!(str_quot: "string \"" => "string \"" );
|
| 271 |
|
| 272 | err!(bytes: Bytes(b"< \"escaped & bytes'>" )
|
| 273 | => Unsupported("`serialize_bytes` not supported yet" ));
|
| 274 |
|
| 275 | serialize_as!(option_none: Option::<&str>::None => "" );
|
| 276 | serialize_as!(option_some: Some("non-escaped-string" ) => "non-escaped-string" );
|
| 277 |
|
| 278 | err!(unit: ()
|
| 279 | => Unsupported("unit type `()` cannot be serialized as an XML tag name" ));
|
| 280 | err!(unit_struct: Unit
|
| 281 | => Unsupported("unit struct `Unit` cannot be serialized as an XML tag name" ));
|
| 282 |
|
| 283 | serialize_as!(enum_unit: Enum::Unit => "Unit" );
|
| 284 | serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "< \"&'>" );
|
| 285 |
|
| 286 | serialize_as!(newtype: Newtype(true) => "true" );
|
| 287 | err!(enum_newtype: Enum::Newtype(false)
|
| 288 | => Unsupported("enum newtype variant `Enum::Newtype` cannot be serialized as an XML tag name" ));
|
| 289 |
|
| 290 | err!(seq: vec![1, 2, 3]
|
| 291 | => Unsupported("sequence cannot be serialized as an XML tag name" ));
|
| 292 | err!(tuple: ("< \"&'>" , "with \t\r\n spaces" , 3usize)
|
| 293 | => Unsupported("tuple cannot be serialized as an XML tag name" ));
|
| 294 | err!(tuple_struct: Tuple("first" , 42)
|
| 295 | => Unsupported("tuple struct `Tuple` cannot be serialized as an XML tag name" ));
|
| 296 | err!(enum_tuple: Enum::Tuple("first" , 42)
|
| 297 | => Unsupported("enum tuple variant `Enum::Tuple` cannot be serialized as an XML tag name" ));
|
| 298 |
|
| 299 | err!(map: BTreeMap::from([("_1" , 2), ("_3" , 4)])
|
| 300 | => Unsupported("map cannot be serialized as an XML tag name" ));
|
| 301 | err!(struct_: Struct { key: "answer" , val: 42 }
|
| 302 | => Unsupported("struct `Struct` cannot be serialized as an XML tag name" ));
|
| 303 | err!(enum_struct: Enum::Struct { key: "answer" , val: 42 }
|
| 304 | => Unsupported("enum struct variant `Enum::Struct` cannot be serialized as an XML tag name" ));
|
| 305 | }
|
| 306 | |