1use crate::value::de::{MapRefDeserializer, SeqRefDeserializer};
2use crate::value::Value;
3use crate::Error;
4use serde::de::value::{BorrowedStrDeserializer, StrDeserializer};
5use serde::de::{
6 Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, VariantAccess, Visitor,
7};
8use serde::forward_to_deserialize_any;
9use serde::ser::{Serialize, SerializeMap, Serializer};
10use std::cmp::Ordering;
11use std::fmt::{self, Debug, Display};
12use std::hash::{Hash, Hasher};
13use std::mem;
14
15use super::de::ValueDeserializer;
16
17#[derive(Clone)]
22pub struct Tag {
23 pub(crate) string: String,
24}
25
26#[derive(Clone, PartialEq, PartialOrd, Hash, Debug)]
53pub struct TaggedValue {
54 #[allow(missing_docs)]
55 pub tag: Tag,
56 #[allow(missing_docs)]
57 pub value: Value,
58}
59
60impl Tag {
61 pub fn new(string: impl Into<String>) -> Self {
90 let tag: String = string.into();
91 assert!(!tag.is_empty(), "empty YAML tag is not allowed");
92 Tag { string: tag }
93 }
94}
95
96impl Value {
97 pub(crate) fn untag(self) -> Self {
98 let mut cur = self;
99 while let Value::Tagged(tagged, ..) = cur {
100 cur = tagged.value;
101 }
102 cur
103 }
104
105 pub(crate) fn untag_ref(&self) -> &Self {
106 let mut cur = self;
107 while let Value::Tagged(tagged, ..) = cur {
108 cur = &tagged.value;
109 }
110 cur
111 }
112
113 pub(crate) fn untag_mut(&mut self) -> &mut Self {
114 let mut cur = self;
115 while let Value::Tagged(tagged, ..) = cur {
116 cur = &mut tagged.value;
117 }
118 cur
119 }
120}
121
122pub(crate) fn nobang(maybe_banged: &str) -> &str {
123 match maybe_banged.strip_prefix('!') {
124 Some("") | None => maybe_banged,
125 Some(unbanged) => unbanged,
126 }
127}
128
129impl Eq for Tag {}
130
131impl PartialEq for Tag {
132 fn eq(&self, other: &Tag) -> bool {
133 PartialEq::eq(nobang(&self.string), nobang(&other.string))
134 }
135}
136
137impl<T> PartialEq<T> for Tag
138where
139 T: ?Sized + AsRef<str>,
140{
141 fn eq(&self, other: &T) -> bool {
142 PartialEq::eq(nobang(&self.string), nobang(other.as_ref()))
143 }
144}
145
146impl Ord for Tag {
147 fn cmp(&self, other: &Self) -> Ordering {
148 Ord::cmp(nobang(&self.string), nobang(&other.string))
149 }
150}
151
152impl PartialOrd for Tag {
153 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
154 Some(self.cmp(other))
155 }
156}
157
158impl Hash for Tag {
159 fn hash<H: Hasher>(&self, hasher: &mut H) {
160 nobang(&self.string).hash(hasher);
161 }
162}
163
164impl Display for Tag {
165 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
166 write!(formatter, "!{}", nobang(&self.string))
167 }
168}
169
170impl Debug for Tag {
171 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
172 Display::fmt(self, formatter)
173 }
174}
175
176impl Serialize for TaggedValue {
177 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
178 where
179 S: Serializer,
180 {
181 struct SerializeTag<'a>(&'a Tag);
182
183 impl Serialize for SerializeTag<'_> {
184 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
185 where
186 S: Serializer,
187 {
188 serializer.collect_str(self.0)
189 }
190 }
191
192 let mut map = serializer.serialize_map(Some(1))?;
193 map.serialize_entry(&SerializeTag(&self.tag), &self.value)?;
194 map.end()
195 }
196}
197
198impl<'de> Deserialize<'de> for TaggedValue {
199 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
200 where
201 D: Deserializer<'de>,
202 {
203 struct TaggedValueVisitor;
204
205 impl<'de> Visitor<'de> for TaggedValueVisitor {
206 type Value = TaggedValue;
207
208 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
209 formatter.write_str("a YAML value with a !Tag")
210 }
211
212 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
213 where
214 A: EnumAccess<'de>,
215 {
216 let (tag, contents) = data.variant_seed(TagStringVisitor)?;
217 let value = contents.newtype_variant()?;
218 Ok(TaggedValue { tag, value })
219 }
220 }
221
222 deserializer.deserialize_any(TaggedValueVisitor)
223 }
224}
225
226impl<'de> Deserializer<'de> for TaggedValue {
227 type Error = Error;
228
229 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
230 where
231 V: Visitor<'de>,
232 {
233 visitor.visit_enum(self)
234 }
235
236 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
237 where
238 V: Visitor<'de>,
239 {
240 drop(self);
241 visitor.visit_unit()
242 }
243
244 forward_to_deserialize_any! {
245 bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
246 byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
247 map struct enum identifier
248 }
249}
250
251impl<'de> EnumAccess<'de> for TaggedValue {
252 type Error = Error;
253 type Variant = ValueDeserializer<'static, 'static, 'static>;
254
255 fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
256 where
257 V: DeserializeSeed<'de>,
258 {
259 let tag = StrDeserializer::<Error>::new(nobang(&self.tag.string));
260 let value = seed.deserialize(tag)?;
261 Ok((value, ValueDeserializer::new(self.value)))
262 }
263}
264
265impl<'de> Deserializer<'de> for &'de TaggedValue {
266 type Error = Error;
267
268 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
269 where
270 V: Visitor<'de>,
271 {
272 visitor.visit_enum(self)
273 }
274
275 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
276 where
277 V: Visitor<'de>,
278 {
279 visitor.visit_unit()
280 }
281
282 forward_to_deserialize_any! {
283 bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
284 byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
285 map struct enum identifier
286 }
287}
288
289impl<'de> EnumAccess<'de> for &'de TaggedValue {
290 type Error = Error;
291 type Variant = &'de Value;
292
293 fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
294 where
295 V: DeserializeSeed<'de>,
296 {
297 let tag = BorrowedStrDeserializer::<Error>::new(nobang(&self.tag.string));
298 let value = seed.deserialize(tag)?;
299 Ok((value, &self.value))
300 }
301}
302
303impl<'de> VariantAccess<'de> for &'de Value {
304 type Error = Error;
305
306 fn unit_variant(self) -> Result<(), Error> {
307 Deserialize::deserialize(self)
308 }
309
310 fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
311 where
312 T: DeserializeSeed<'de>,
313 {
314 seed.deserialize(self)
315 }
316
317 fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
318 where
319 V: Visitor<'de>,
320 {
321 if let Value::Sequence(v, ..) = self {
322 Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
323 } else {
324 Err(Error::invalid_type(self.unexpected(), &"tuple variant"))
325 }
326 }
327
328 fn struct_variant<V>(
329 self,
330 _fields: &'static [&'static str],
331 visitor: V,
332 ) -> Result<V::Value, Error>
333 where
334 V: Visitor<'de>,
335 {
336 if let Value::Mapping(v, ..) = self {
337 Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
338 } else {
339 Err(Error::invalid_type(self.unexpected(), &"struct variant"))
340 }
341 }
342}
343
344pub(crate) struct TagStringVisitor;
345
346impl Visitor<'_> for TagStringVisitor {
347 type Value = Tag;
348
349 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
350 formatter.write_str("a YAML tag string")
351 }
352
353 fn visit_str<E>(self, string: &str) -> Result<Self::Value, E>
354 where
355 E: serde::de::Error,
356 {
357 self.visit_string(string.to_owned())
358 }
359
360 fn visit_string<E>(self, string: String) -> Result<Self::Value, E>
361 where
362 E: serde::de::Error,
363 {
364 if string.is_empty() {
365 return Err(E::custom("empty YAML tag is not allowed"));
366 }
367 Ok(Tag::new(string))
368 }
369}
370
371impl<'de> DeserializeSeed<'de> for TagStringVisitor {
372 type Value = Tag;
373
374 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
375 where
376 D: Deserializer<'de>,
377 {
378 deserializer.deserialize_string(self)
379 }
380}
381
382pub(crate) enum MaybeTag<T> {
383 Tag(String),
384 NotTag(T),
385}
386
387pub(crate) fn check_for_tag<T>(value: &T) -> MaybeTag<String>
388where
389 T: ?Sized + Display,
390{
391 enum CheckForTag {
392 Empty,
393 Bang,
394 Tag(String),
395 NotTag(String),
396 }
397
398 impl fmt::Write for CheckForTag {
399 fn write_str(&mut self, s: &str) -> fmt::Result {
400 if s.is_empty() {
401 return Ok(());
402 }
403 match self {
404 CheckForTag::Empty => {
405 if s == "!" {
406 *self = CheckForTag::Bang;
407 } else {
408 *self = CheckForTag::NotTag(s.to_owned());
409 }
410 }
411 CheckForTag::Bang => {
412 *self = CheckForTag::Tag(s.to_owned());
413 }
414 CheckForTag::Tag(string) => {
415 let mut string = mem::take(string);
416 string.push_str(s);
417 *self = CheckForTag::NotTag(string);
418 }
419 CheckForTag::NotTag(string) => {
420 string.push_str(s);
421 }
422 }
423 Ok(())
424 }
425 }
426
427 let mut check_for_tag = CheckForTag::Empty;
428 fmt::write(&mut check_for_tag, format_args!("{}", value)).unwrap();
429 match check_for_tag {
430 CheckForTag::Empty => MaybeTag::NotTag(String::new()),
431 CheckForTag::Bang => MaybeTag::NotTag("!".to_owned()),
432 CheckForTag::Tag(string) => MaybeTag::Tag(string),
433 CheckForTag::NotTag(string) => MaybeTag::NotTag(string),
434 }
435}