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}