hcl/de/
mod.rs

1//! Deserialize HCL data to a Rust data structure.
2//!
3//! The `Deserializer` implementation tries to follow the [HCL JSON Specification][hcl-json-spec]
4//! as close as possible.
5//!
6//! [hcl-json-spec]: https://github.com/hashicorp/hcl/blob/main/json/spec.md
7
8use crate::structure::IntoJsonSpec;
9use crate::{Body, Error, Identifier, Result};
10use serde::de::value::StringDeserializer;
11use serde::de::{self, Deserializer as _, IntoDeserializer};
12use serde::forward_to_deserialize_any;
13use std::fmt;
14use std::marker::PhantomData;
15
16/// A structure that deserializes HCL into Rust values.
17pub struct Deserializer {
18    body: Body,
19}
20
21impl Deserializer {
22    /// Creates a HCL deserializer from a `&str`.
23    ///
24    /// # Errors
25    ///
26    /// An [`Error`][Error] is returned when the input is not valid HCL.
27    ///
28    /// [Error]: ../error/enum.Error.html
29    pub fn from_str(input: &str) -> Result<Self> {
30        let body: Body = input.parse()?;
31        Ok(Deserializer { body })
32    }
33
34    /// Creates a HCL deserializer from a HCL body
35    pub fn from_body(body: Body) -> Self {
36        Self { body }
37    }
38}
39
40/// Deserialize an instance of type `T` from a string of HCL text.
41///
42/// By default, the deserialization will follow the [HCL JSON Specification][hcl-json-spec].
43///
44/// If preserving HCL semantics is required consider deserializing into a [`Body`][Body] instead or
45/// use [`hcl::parse`][parse] to directly parse the input into a [`Body`][Body].
46///
47/// [hcl-json-spec]: https://github.com/hashicorp/hcl/blob/main/json/spec.md
48/// [parse]: ../fn.parse.html
49/// [Body]: ../struct.Body.html
50///
51/// # Example
52///
53/// ```
54/// use serde_json::{json, Value};
55///
56/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
57/// let input = r#"
58///     some_attr = {
59///       foo = [1, 2]
60///       bar = true
61///     }
62///
63///     some_block "some_block_label" {
64///       attr = "value"
65///     }
66/// "#;
67///
68/// let expected = json!({
69///     "some_attr": {
70///         "foo": [1, 2],
71///         "bar": true
72///     },
73///     "some_block": {
74///         "some_block_label": {
75///             "attr": "value"
76///         }
77///     }
78/// });
79///
80/// let value: Value = hcl::from_str(input)?;
81///
82/// assert_eq!(value, expected);
83/// #   Ok(())
84/// # }
85/// ```
86///
87/// # Errors
88///
89/// This functions fails with an error if the data does not match the structure of `T`.
90pub fn from_str<'de, T>(s: &'de str) -> Result<T>
91where
92    T: de::Deserialize<'de>,
93{
94    let deserializer = Deserializer::from_str(s)?;
95    T::deserialize(deserializer)
96}
97
98/// Deserialize an instance of type `T` from an IO stream of HCL.
99///
100/// See the documentation of [`from_str`] for more information.
101///
102/// # Example
103///
104/// ```
105/// use hcl::Value;
106///
107/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
108/// let input = r#"
109///     some_attr = {
110///       foo = [1, 2]
111///       bar = true
112///     }
113///
114///     some_block "some_block_label" {
115///       attr = "value"
116///     }
117/// "#;
118///
119/// let expected = hcl::value!({
120///     some_attr = {
121///         foo = [1, 2]
122///         bar = true
123///     }
124///     some_block = {
125///         some_block_label = {
126///             attr = "value"
127///         }
128///     }
129/// });
130///
131/// let value: Value = hcl::from_reader(input.as_bytes())?;
132///
133/// assert_eq!(value, expected);
134/// #   Ok(())
135/// # }
136/// ```
137///
138/// # Errors
139///
140/// This functions fails with an error if reading from the reader fails or if the data does not
141/// match the structure of `T`.
142pub fn from_reader<T, R>(mut reader: R) -> Result<T>
143where
144    T: de::DeserializeOwned,
145    R: std::io::Read,
146{
147    let mut s = String::new();
148    reader.read_to_string(&mut s)?;
149
150    from_str(&s)
151}
152
153/// Deserialize an instance of type `T` from a byte slice.
154///
155/// See the documentation of [`from_str`] for more information.
156///
157/// # Errors
158///
159/// This functions fails with an error if `buf` does not contain valid UTF-8 or if the data does
160/// not match the structure of `T`.
161pub fn from_slice<'de, T>(buf: &'de [u8]) -> Result<T>
162where
163    T: de::Deserialize<'de>,
164{
165    let s = std::str::from_utf8(buf)?;
166    from_str(s)
167}
168
169/// Interpret a `hcl::Body` as an instance of type `T`.
170///
171/// # Example
172///
173/// ```
174/// use serde::Deserialize;
175/// use hcl::{Block, Body};
176///
177/// # use std::error::Error;
178/// #
179/// # fn main() -> Result<(), Box<dyn Error>> {
180/// #[derive(Deserialize, Debug)]
181/// struct User {
182///     name: String,
183///     email: String,
184/// }
185///
186/// #[derive(Deserialize, Debug)]
187/// struct Config {
188///     user: User,
189/// }
190///
191/// let body = Body::builder()
192///     .add_block(
193///         Block::builder("user")
194///             .add_attribute(("name", "John Doe"))
195///             .add_attribute(("email", "john@doe.tld"))
196///             .build()
197///     )
198///     .build();
199///
200/// let config: Config = hcl::from_body(body)?;
201/// println!("{:#?}", config);
202/// #   Ok(())
203/// # }
204/// ```
205///
206/// # Errors
207///
208/// This functions fails with an error if the data does not match the structure of `T`.
209pub fn from_body<T>(body: Body) -> Result<T>
210where
211    T: de::DeserializeOwned,
212{
213    T::deserialize(Deserializer { body })
214}
215
216impl<'de> de::Deserializer<'de> for Deserializer {
217    type Error = Error;
218
219    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
220    where
221        V: de::Visitor<'de>,
222    {
223        self.body.into_json_spec().deserialize_any(visitor)
224    }
225
226    fn deserialize_newtype_struct<V>(
227        self,
228        name: &'static str,
229        visitor: V,
230    ) -> Result<V::Value, Self::Error>
231    where
232        V: de::Visitor<'de>,
233    {
234        if name == "$hcl::Body" {
235            // Specialized handling of `hcl::Body`.
236            self.body.into_deserializer().deserialize_any(visitor)
237        } else {
238            // Generic deserialization according to the HCL JSON spec.
239            self.body
240                .into_json_spec()
241                .deserialize_newtype_struct(name, visitor)
242        }
243    }
244
245    fn deserialize_enum<V>(
246        self,
247        name: &'static str,
248        variants: &'static [&'static str],
249        visitor: V,
250    ) -> Result<V::Value>
251    where
252        V: de::Visitor<'de>,
253    {
254        self.body
255            .into_json_spec()
256            .deserialize_enum(name, variants, visitor)
257    }
258
259    forward_to_deserialize_any! {
260        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
261        bytes byte_buf option unit unit_struct seq tuple
262        tuple_struct map struct identifier ignored_any
263    }
264}
265
266// A trait that allows enum types to report the name of their variant.
267pub(crate) trait VariantName {
268    fn variant_name(&self) -> &'static str;
269}
270
271// Not public API.
272#[doc(hidden)]
273pub struct NewtypeStructDeserializer<T, E = Error> {
274    value: T,
275    marker: PhantomData<E>,
276}
277
278impl<T, E> NewtypeStructDeserializer<T, E> {
279    pub(crate) fn new(value: T) -> Self {
280        NewtypeStructDeserializer {
281            value,
282            marker: PhantomData,
283        }
284    }
285}
286
287impl<'de, T, E> de::Deserializer<'de> for NewtypeStructDeserializer<T, E>
288where
289    T: IntoDeserializer<'de, E>,
290    E: de::Error,
291{
292    type Error = E;
293
294    forward_to_deserialize_any! {
295        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str
296        string bytes byte_buf option unit unit_struct newtype_struct seq
297        tuple tuple_struct map struct enum identifier ignored_any
298    }
299
300    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
301    where
302        V: de::Visitor<'de>,
303    {
304        visitor.visit_newtype_struct(self.value.into_deserializer())
305    }
306}
307
308pub(crate) struct OptionDeserializer<T, E = Error> {
309    value: Option<T>,
310    marker: PhantomData<E>,
311}
312
313impl<T, E> OptionDeserializer<T, E> {
314    pub(crate) fn new(value: Option<T>) -> Self {
315        OptionDeserializer {
316            value,
317            marker: PhantomData,
318        }
319    }
320}
321
322impl<'de, T, E> de::Deserializer<'de> for OptionDeserializer<T, E>
323where
324    T: IntoDeserializer<'de, E>,
325    E: de::Error,
326{
327    type Error = E;
328
329    forward_to_deserialize_any! {
330        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str
331        string bytes byte_buf option unit unit_struct newtype_struct seq
332        tuple tuple_struct map struct enum identifier ignored_any
333    }
334
335    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
336    where
337        V: de::Visitor<'de>,
338    {
339        match self.value {
340            Some(value) => visitor.visit_some(value.into_deserializer()),
341            None => visitor.visit_none(),
342        }
343    }
344}
345
346pub(crate) struct EnumAccess<T, E = Error> {
347    value: T,
348    marker: PhantomData<E>,
349}
350
351impl<T, E> EnumAccess<T, E> {
352    pub(crate) fn new(value: T) -> Self {
353        EnumAccess {
354            value,
355            marker: PhantomData,
356        }
357    }
358}
359
360impl<'de, T, E> de::EnumAccess<'de> for EnumAccess<T, E>
361where
362    T: IntoDeserializer<'de, E> + VariantName,
363    E: de::Error,
364{
365    type Error = E;
366    type Variant = VariantAccess<T, E>;
367
368    fn variant_seed<S>(self, seed: S) -> Result<(S::Value, Self::Variant), Self::Error>
369    where
370        S: de::DeserializeSeed<'de>,
371    {
372        let variant_name = self.value.variant_name();
373
374        seed.deserialize(variant_name.into_deserializer())
375            .map(|variant| (variant, VariantAccess::new(self.value)))
376    }
377}
378
379// Not public API.
380#[doc(hidden)]
381pub struct VariantAccess<T, E = Error> {
382    value: T,
383    marker: PhantomData<E>,
384}
385
386impl<T, E> VariantAccess<T, E> {
387    fn new(value: T) -> Self {
388        VariantAccess {
389            value,
390            marker: PhantomData,
391        }
392    }
393}
394
395impl<'de, T, E> de::VariantAccess<'de> for VariantAccess<T, E>
396where
397    T: IntoDeserializer<'de, E>,
398    E: de::Error,
399{
400    type Error = E;
401
402    fn unit_variant(self) -> Result<(), Self::Error> {
403        de::Deserialize::deserialize(self.value.into_deserializer())
404    }
405
406    fn newtype_variant_seed<S>(self, seed: S) -> Result<S::Value, Self::Error>
407    where
408        S: de::DeserializeSeed<'de>,
409    {
410        seed.deserialize(self.value.into_deserializer())
411    }
412
413    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
414    where
415        V: de::Visitor<'de>,
416    {
417        self.value.into_deserializer().deserialize_seq(visitor)
418    }
419
420    fn struct_variant<V>(
421        self,
422        _fields: &'static [&'static str],
423        visitor: V,
424    ) -> Result<V::Value, Self::Error>
425    where
426        V: de::Visitor<'de>,
427    {
428        self.value.into_deserializer().deserialize_map(visitor)
429    }
430}
431
432pub(crate) struct FromStrVisitor<T> {
433    expecting: &'static str,
434    marker: PhantomData<T>,
435}
436
437impl<T> FromStrVisitor<T> {
438    pub(crate) fn new(expecting: &'static str) -> FromStrVisitor<T> {
439        FromStrVisitor {
440            expecting,
441            marker: PhantomData,
442        }
443    }
444}
445
446impl<T> de::Visitor<'_> for FromStrVisitor<T>
447where
448    T: std::str::FromStr,
449    T::Err: fmt::Display,
450{
451    type Value = T;
452
453    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
454        formatter.write_str(self.expecting)
455    }
456
457    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
458    where
459        E: de::Error,
460    {
461        T::from_str(value).map_err(de::Error::custom)
462    }
463}
464
465impl IntoDeserializer<'_, Error> for Identifier {
466    type Deserializer = StringDeserializer<Error>;
467
468    fn into_deserializer(self) -> Self::Deserializer {
469        self.into_inner().into_deserializer()
470    }
471}