idm/
util.rs

1use std::{
2    marker::PhantomData,
3    ops::{Deref, DerefMut},
4};
5
6use crate::{from_str, to_string};
7use serde::{de, de::DeserializeOwned, ser, Deserialize, Serialize};
8
9/// Try to convert a value of one type into a value of a different type that
10/// has the same IDM serialization.
11pub fn transmute<T: Serialize, U: DeserializeOwned>(e: &T) -> crate::Result<U> {
12    let s = crate::to_string(e)?;
13    crate::from_str(&s)
14}
15
16/// Wrapper that represents `Default` values with `"-"`, allowing them in
17/// contexts that cannot represent an empty value.
18///
19/// ```
20/// use idm::DefaultDash;
21///
22/// assert_eq!(
23///     idm::from_str::<DefaultDash<String>>("-").unwrap(),
24///     DefaultDash(String::default())
25/// );
26/// assert_eq!(
27///     idm::from_str::<DefaultDash<String>>("xyzzy").unwrap(),
28///     DefaultDash("xyzzy".to_string())
29/// );
30///
31/// assert_eq!(
32///     idm::to_string(&DefaultDash("xyzzy".to_string())).unwrap(),
33///     "xyzzy"
34/// );
35/// assert_eq!(
36///     idm::to_string(&DefaultDash(String::default())).unwrap(),
37///     "-"
38/// );
39/// ```
40#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
41pub struct DefaultDash<T: Default>(pub T);
42
43impl<'de, T: DeserializeOwned + Default> Deserialize<'de> for DefaultDash<T> {
44    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
45    where
46        D: serde::Deserializer<'de>,
47    {
48        let ret = String::deserialize(deserializer)?;
49        if ret == "-" {
50            Ok(DefaultDash(Default::default()))
51        } else {
52            from_str(&ret).map(DefaultDash).map_err(de::Error::custom)
53        }
54    }
55}
56
57impl<T: Serialize + Default + PartialEq> Serialize for DefaultDash<T> {
58    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: serde::Serializer,
61    {
62        if self.0 == Default::default() {
63            "-".serialize(serializer)
64        } else {
65            // XXX: It's up to the user to worry about non-default values of
66            // the type serializing as a literal "-". Could serialize to
67            // string here, error out on "-" and reserialize the string
68            // otherwise, but this is simpler and probably faster.
69            self.0.serialize(serializer)
70        }
71    }
72}
73
74impl<T: Default> Deref for DefaultDash<T> {
75    type Target = T;
76
77    fn deref(&self) -> &Self::Target {
78        &self.0
79    }
80}
81
82impl<T: Default> DerefMut for DefaultDash<T> {
83    fn deref_mut(&mut self) -> &mut Self::Target {
84        &mut self.0
85    }
86}
87
88/// Wrapper type that replaces spaces with underscores when serializing.
89///
90/// Use this to make multi-word strings look like single words so they can be
91/// used as items in a horizontal IDM sequence. Do not use with an inner type
92/// that has actual underscores in its string representation, these will be
93/// turned into spaces during the roundtrip. Do not use with strings that have
94/// newlines in them.
95#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
96pub struct UnderlineSpaces<T>(pub T);
97
98impl<'de, T: DeserializeOwned> Deserialize<'de> for UnderlineSpaces<T> {
99    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100    where
101        D: serde::Deserializer<'de>,
102    {
103        let ret = String::deserialize(deserializer)?.replace('_', " ");
104        Ok(UnderlineSpaces(from_str(&ret).map_err(de::Error::custom)?))
105    }
106}
107
108impl<T: Serialize> Serialize for UnderlineSpaces<T> {
109    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110    where
111        S: serde::Serializer,
112    {
113        to_string(&self.0)
114            .map_err(ser::Error::custom)?
115            .replace(' ', "_")
116            .serialize(serializer)
117    }
118}
119
120impl<T: Default> Deref for UnderlineSpaces<T> {
121    type Target = T;
122
123    fn deref(&self) -> &Self::Target {
124        &self.0
125    }
126}
127
128impl<T: Default> DerefMut for UnderlineSpaces<T> {
129    fn deref_mut(&mut self) -> &mut Self::Target {
130        &mut self.0
131    }
132}
133
134/// A wrapper that causes the wrapped container to be serialized as a `Vec`
135/// collected from its iterated values.
136///
137/// The item type of the container needs to be given as the second type
138/// parameter.
139#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
140pub struct AsVec<T, U, SU>(pub T, pub PhantomData<U>, pub PhantomData<SU>);
141
142impl<T, U, SU> AsVec<T, U, SU> {
143    pub fn new(t: T) -> Self {
144        AsVec(t, PhantomData, PhantomData)
145    }
146}
147
148impl<'de, T: FromIterator<U>, U, SU: Into<U> + DeserializeOwned>
149    Deserialize<'de> for AsVec<T, U, SU>
150{
151    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
152    where
153        D: serde::Deserializer<'de>,
154    {
155        Ok(AsVec(
156            Vec::<SU>::deserialize(deserializer)?
157                .into_iter()
158                .map(Into::into)
159                .collect(),
160            PhantomData,
161            PhantomData,
162        ))
163    }
164}
165
166impl<T: Clone + IntoIterator<Item = U>, U, SU: Serialize + From<U>> Serialize
167    for AsVec<T, U, SU>
168{
169    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
170    where
171        S: serde::Serializer,
172    {
173        self.0
174            .clone()
175            .into_iter()
176            .map(From::from)
177            .collect::<Vec<SU>>()
178            .serialize(serializer)
179    }
180}
181
182impl<T, U, SU> Deref for AsVec<T, U, SU> {
183    type Target = T;
184
185    fn deref(&self) -> &Self::Target {
186        &self.0
187    }
188}
189
190impl<T, U, SU> DerefMut for AsVec<T, U, SU> {
191    fn deref_mut(&mut self) -> &mut Self::Target {
192        &mut self.0
193    }
194}