serde_dhall/options/
ser.rs

1use crate::options::{HasAnnot, ManualAnnot, NoAnnot, StaticAnnot, TypeAnnot};
2use crate::{Result, SimpleType, ToDhall};
3
4/// Controls how a Dhall value is written.
5///
6/// This builder exposes the ability to configure how a value is serialized, and to set type
7/// annotations.
8///
9/// When using [`Serializer`], you'll create it with [`serialize()`], then chain calls to methods
10/// to set each option, then call [`to_string()`]. This will give you a [`Result`] containing the
11/// input serialized to Dhall.
12///
13/// Note that if you do not provide a type annotation, some values may not be convertible to Dhall,
14/// like empty lists or enums.
15///
16/// [`to_string()`]: Serializer::to_string()
17///
18/// # Examples
19///
20/// Serializing without a type annotation:
21///
22/// ```rust
23/// # fn main() -> serde_dhall::Result<()> {
24/// use serde_dhall::serialize;
25///
26/// let string = serialize(&1i64).to_string()?;
27/// assert_eq!(string, "+1".to_string());
28/// # Ok(())
29/// # }
30/// ```
31///
32/// Serializing with an automatic type annotation:
33///
34/// ```rust
35/// # fn main() -> serde_dhall::Result<()> {
36/// use serde_dhall::serialize;
37///
38/// let data: Option<u64> = None;
39/// let string = serialize(&data).static_type_annotation().to_string()?;
40/// assert_eq!(string, "None Natural".to_string());
41/// # Ok(())
42/// # }
43/// ```
44#[derive(Debug, Clone)]
45pub struct Serializer<'a, T, A> {
46    data: &'a T,
47    annot: A,
48}
49
50impl<'a, T> Serializer<'a, T, NoAnnot> {
51    /// Provides a type to the serialization process. The provided value will be checked against
52    /// that type, and the type will be used when Dhall needs it, like for empty lists or for
53    /// unions.
54    ///
55    /// In many cases the Dhall type that corresponds to a Rust type can be inferred automatically.
56    /// See the [`StaticType`] trait and the [`static_type_annotation()`] method for that.
57    ///
58    /// # Example
59    ///
60    /// ```
61    /// # fn main() -> serde_dhall::Result<()> {
62    /// use serde_dhall::{serialize, from_str, SimpleType, SimpleValue};
63    ///
64    /// let ty = from_str("< A | B: Bool >").parse()?;
65    /// let data = SimpleValue::Union("A".to_string(), None);
66    /// let string = serialize(&data)
67    ///     .type_annotation(&ty)
68    ///     .to_string()?;
69    /// assert_eq!(string, "< A | B: Bool >.A".to_string());
70    ///
71    /// // Invalid data fails the type validation; serialization would have succeeded otherwise.
72    /// let ty = SimpleType::Integer;
73    /// assert!(
74    ///     serialize(&Some(0u64))
75    ///         .type_annotation(&ty)
76    ///         .to_string()
77    ///         .is_err()
78    /// );
79    /// # Ok(())
80    /// # }
81    /// ```
82    ///
83    /// [`StaticType`]: crate::StaticType
84    /// [`static_type_annotation()`]: Serializer::static_type_annotation()
85    pub fn type_annotation<'ty>(
86        self,
87        ty: &'ty SimpleType,
88    ) -> Serializer<'a, T, ManualAnnot<'ty>> {
89        Serializer {
90            annot: ManualAnnot(ty),
91            data: self.data,
92        }
93    }
94
95    /// Uses the type of `T` in the serialization process. This will be used when Dhall needs it,
96    /// like for empty lists or for unions.
97    ///
98    /// `T` must implement the [`StaticType`] trait. If it doesn't, you can use [`type_annotation()`]
99    ///
100    /// # Example
101    ///
102    /// ```
103    /// # fn main() -> serde_dhall::Result<()> {
104    /// use serde::Serialize;
105    /// use serde_dhall::{serialize, StaticType};
106    ///
107    /// #[derive(Serialize, StaticType)]
108    /// enum MyOption {
109    ///     MyNone,
110    ///     MySome(u64),
111    /// }
112    ///
113    /// let data = MyOption::MySome(0);
114    /// let string = serialize(&data)
115    ///     .static_type_annotation()
116    ///     .to_string()?;
117    /// // The resulting Dhall string depends on the type annotation; it could not have been
118    /// // printed without it.
119    /// assert_eq!(string, "< MyNone | MySome: Natural >.MySome 0".to_string());
120    /// # Ok(())
121    /// # }
122    /// ```
123    ///
124    /// [`StaticType`]: crate::StaticType
125    /// [`type_annotation()`]: Serializer::type_annotation()
126    pub fn static_type_annotation(self) -> Serializer<'a, T, StaticAnnot> {
127        Serializer {
128            annot: StaticAnnot,
129            data: self.data,
130        }
131    }
132}
133
134impl<'a, T, A> Serializer<'a, T, A>
135where
136    A: TypeAnnot,
137{
138    /// Prints the chosen value with the options provided.
139    ///
140    /// If you enabled static annotations, `T` is required to implement [`StaticType`].
141    ///
142    /// Note that if you do not provide a type annotation, some values may not be convertible to
143    /// Dhall, like empty lists or enums.
144    ///
145    ///
146    /// # Example
147    ///
148    /// ```rust
149    /// # fn main() -> serde_dhall::Result<()> {
150    /// use serde_dhall::serialize;
151    ///
152    /// let string = serialize(&1i64).static_type_annotation().to_string()?;
153    /// assert_eq!(string, "+1".to_string());
154    /// # Ok(())
155    /// # }
156    /// ```
157    ///
158    /// [`StaticType`]: crate::StaticType
159    pub fn to_string(&self) -> Result<String>
160    where
161        T: ToDhall + HasAnnot<A>,
162    {
163        let val = self.data.to_dhall(T::get_annot(self.annot).as_ref())?;
164        Ok(val.to_string())
165    }
166}
167
168/// Serialize a value to a string of Dhall text.
169///
170/// This returns a [`Serializer`] object. Call the [`to_string()`] method to get the serialized
171/// value, or use other [`Serializer`] methods to control the serialization process.
172///
173/// In order to process certain values (like unions or empty lists) correctly, it is necessary to
174/// add a type annotation (with [`static_type_annotation()`] or [`type_annotation()`]).
175///
176/// # Examples
177///
178/// ```rust
179/// # fn main() -> serde_dhall::Result<()> {
180/// use serde::Serialize;
181/// use serde_dhall::{serialize, StaticType};
182///
183/// #[derive(Serialize)]
184/// struct Point {
185///     x: u64,
186///     y: u64,
187/// }
188///
189///
190/// let data = Point { x: 0, y: 0 };
191/// let string = serialize(&data).to_string()?;
192/// assert_eq!(string, "{ x = 0, y = 0 }");
193/// # Ok(())
194/// # }
195/// ```
196///
197/// ```rust
198/// # fn main() -> serde_dhall::Result<()> {
199/// use serde::Serialize;
200/// use serde_dhall::{serialize, StaticType};
201///
202/// #[derive(Serialize, StaticType)]
203/// enum MyOption {
204///     MyNone,
205///     MySome(u64),
206/// }
207///
208/// let data = MyOption::MySome(0);
209/// let string = serialize(&data)
210///     .static_type_annotation()
211///     .to_string()?;
212/// // The resulting Dhall string depends on the type annotation; it could not have been
213/// // printed without it.
214/// assert_eq!(string, "< MyNone | MySome: Natural >.MySome 0".to_string());
215/// # Ok(())
216/// # }
217/// ```
218///
219/// [`type_annotation()`]: Serializer::type_annotation()
220/// [`static_type_annotation()`]: Serializer::static_type_annotation()
221/// [`to_string()`]: Serializer::to_string()
222pub fn serialize<T>(data: &T) -> Serializer<'_, T, NoAnnot>
223where
224    T: ToDhall,
225{
226    Serializer {
227        data,
228        annot: NoAnnot,
229    }
230}