1use crate::{Utf8Path, Utf8PathBuf};
10use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
11use std::fmt;
12
13struct Utf8PathVisitor;
14
15impl<'a> de::Visitor<'a> for Utf8PathVisitor {
16 type Value = &'a Utf8Path;
17
18 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
19 formatter.write_str("a borrowed path")
20 }
21
22 fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
23 where
24 E: de::Error,
25 {
26 Ok(v.as_ref())
27 }
28
29 fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
30 where
31 E: de::Error,
32 {
33 std::str::from_utf8(v)
34 .map(AsRef::as_ref)
35 .map_err(|_| de::Error::invalid_value(de::Unexpected::Bytes(v), &self))
36 }
37}
38
39impl<'de: 'a, 'a> Deserialize<'de> for &'a Utf8Path {
40 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
41 where
42 D: Deserializer<'de>,
43 {
44 deserializer.deserialize_str(Utf8PathVisitor)
45 }
46}
47
48impl Serialize for Utf8Path {
49 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50 where
51 S: Serializer,
52 {
53 self.as_str().serialize(serializer)
54 }
55}
56
57impl<'de> Deserialize<'de> for Box<Utf8Path> {
58 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59 where
60 D: Deserializer<'de>,
61 {
62 Ok(Utf8PathBuf::deserialize(deserializer)?.into())
63 }
64}
65
66#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::Utf8PathBuf;
75 use serde_bytes::ByteBuf;
76
77 #[test]
78 fn valid_utf8() {
79 let valid_utf8 = &["", "bar", "💩"];
80 for input in valid_utf8 {
81 let encode = Encode {
82 path: ByteBuf::from(*input),
83 };
84 let encoded = bincode::serialize(&encode).expect("encoded correctly");
85
86 assert_valid_utf8::<DecodeOwned>(input, &encoded);
87 assert_valid_utf8::<DecodeBorrowed>(input, &encoded);
88 assert_valid_utf8::<DecodeBoxed>(input, &encoded);
89 }
90 }
91
92 fn assert_valid_utf8<'de, T: TestTrait<'de>>(input: &str, encoded: &'de [u8]) {
93 let output = bincode::deserialize::<T>(encoded).expect("valid UTF-8 should be fine");
94 assert_eq!(
95 output.path(),
96 input,
97 "for input, with {}, paths should match",
98 T::description()
99 );
100 let roundtrip = bincode::serialize(&output).expect("message should roundtrip");
101 assert_eq!(roundtrip, encoded, "encoded path matches");
102 }
103
104 #[test]
105 fn invalid_utf8() {
106 let invalid_utf8: &[(&[u8], _, _)] = &[
107 (b"\xff", 0, 1),
108 (b"foo\xfe", 3, 1),
109 (b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9", 4, 1),
110 ];
111
112 for (input, valid_up_to, error_len) in invalid_utf8 {
113 let encode = Encode {
114 path: ByteBuf::from(*input),
115 };
116 let encoded = bincode::serialize(&encode).expect("encoded correctly");
117
118 assert_invalid_utf8::<DecodeOwned>(input, &encoded, *valid_up_to, *error_len);
119 assert_invalid_utf8::<DecodeBorrowed>(input, &encoded, *valid_up_to, *error_len);
120 assert_invalid_utf8::<DecodeBoxed>(input, &encoded, *valid_up_to, *error_len);
121 }
122 }
123
124 fn assert_invalid_utf8<'de, T: TestTrait<'de>>(
125 input: &[u8],
126 encoded: &'de [u8],
127 valid_up_to: usize,
128 error_len: usize,
129 ) {
130 let error = bincode::deserialize::<T>(encoded).expect_err("invalid UTF-8 should error out");
131 let utf8_error = match *error {
132 bincode::ErrorKind::InvalidUtf8Encoding(utf8_error) => utf8_error,
133 other => panic!(
134 "for input {:?}, with {}, expected ErrorKind::InvalidUtf8Encoding, found: {}",
135 input,
136 T::description(),
137 other
138 ),
139 };
140 assert_eq!(
141 utf8_error.valid_up_to(),
142 valid_up_to,
143 "for input {:?}, with {}, valid_up_to didn't match",
144 input,
145 T::description(),
146 );
147 assert_eq!(
148 utf8_error.error_len(),
149 Some(error_len),
150 "for input {:?}, with {}, error_len didn't match",
151 input,
152 T::description(),
153 );
154 }
155
156 #[derive(Serialize, Debug)]
157 struct Encode {
158 path: ByteBuf,
159 }
160
161 trait TestTrait<'de>: Serialize + Deserialize<'de> + fmt::Debug {
162 fn description() -> &'static str;
163 fn path(&self) -> &Utf8Path;
164 }
165
166 #[derive(Serialize, Deserialize, Debug)]
167 #[allow(unused)]
168 struct DecodeOwned {
169 path: Utf8PathBuf,
170 }
171
172 impl<'de> TestTrait<'de> for DecodeOwned {
173 fn description() -> &'static str {
174 "DecodeOwned"
175 }
176
177 fn path(&self) -> &Utf8Path {
178 &self.path
179 }
180 }
181
182 #[derive(Serialize, Deserialize, Debug)]
183 #[allow(unused)]
184 struct DecodeBorrowed<'a> {
185 #[serde(borrow)]
186 path: &'a Utf8Path,
187 }
188
189 impl<'de> TestTrait<'de> for DecodeBorrowed<'de> {
190 fn description() -> &'static str {
191 "DecodeBorrowed"
192 }
193
194 fn path(&self) -> &Utf8Path {
195 self.path
196 }
197 }
198
199 #[derive(Serialize, Deserialize, Debug)]
200 #[allow(unused)]
201 struct DecodeBoxed {
202 path: Box<Utf8Path>,
203 }
204
205 impl<'de> TestTrait<'de> for DecodeBoxed {
206 fn description() -> &'static str {
207 "DecodeBoxed"
208 }
209
210 fn path(&self) -> &Utf8Path {
211 &self.path
212 }
213 }
214}