Skip to main content

nickel_lang_core/
deserialize.rs

1//! Deserialization of an evaluated program to plain Rust types.
2
3use malachite::base::{num::conversion::traits::RoundingFrom, rounding_modes::RoundingMode};
4use nickel_lang_parser::ast::InputFormat;
5use std::{ffi::OsString, io::Cursor, iter::ExactSizeIterator};
6
7use serde::de::{
8    Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
9    VariantAccess, Visitor,
10};
11
12use crate::{
13    error::{self, NullReporter},
14    eval::{
15        cache::CacheImpl,
16        value::{
17            Array, ArrayData, Container, InlineValue, NickelValue, RecordData, ValueContent,
18            ValueContentRef,
19        },
20    },
21    identifier::LocIdent,
22    program::{Input, Program},
23    term::{IndexMap, record::Field},
24};
25
26macro_rules! deserialize_number {
27    ($method:ident, $type:tt, $visit:ident) => {
28        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
29        where
30            V: Visitor<'de>,
31        {
32            match self.content_ref() {
33                ValueContentRef::Number(n) => {
34                    return visitor.$visit($type::rounding_from(n, RoundingMode::Nearest).0);
35                }
36                _ => Err(RustDeserializationError::InvalidType {
37                    expected: "Number".to_string(),
38                    occurred: self.type_of().unwrap_or("Other").to_owned(),
39                }),
40            }
41        }
42    };
43}
44
45// TODO: revisit this lint once the large errors have been dealt with.
46#[allow(clippy::large_enum_variant)]
47pub enum EvalOrDeserError {
48    Nickel {
49        error: error::Error,
50        files: Option<crate::files::Files>,
51    },
52    Deser(RustDeserializationError),
53}
54
55impl std::error::Error for EvalOrDeserError {}
56
57impl std::fmt::Debug for EvalOrDeserError {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        match self {
60            Self::Nickel { error, files } => {
61                let filenames = files.as_ref().map(|f| f.filenames().collect::<Vec<_>>());
62                f.debug_struct("Nickel")
63                    .field("error", error)
64                    .field("files", &filenames)
65                    .finish()
66            }
67            Self::Deser(arg0) => f.debug_tuple("Deser").field(arg0).finish(),
68        }
69    }
70}
71
72impl std::fmt::Display for EvalOrDeserError {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        match self {
75            EvalOrDeserError::Nickel { error, files } => {
76                let mut files = files.clone().unwrap_or_default();
77                write!(
78                    f,
79                    "{}",
80                    crate::error::report::report_as_str(
81                        &mut files,
82                        error.clone(),
83                        error::report::ColorOpt::Never
84                    )
85                )
86            }
87            EvalOrDeserError::Deser(e) => e.fmt(f),
88        }
89    }
90}
91
92impl EvalOrDeserError {
93    fn new<E>(error: E, files: crate::files::Files) -> Self
94    where
95        E: Into<error::Error>,
96    {
97        Self::Nickel {
98            error: error.into(),
99            files: Some(files),
100        }
101    }
102}
103
104impl<E: Into<error::Error>> From<E> for EvalOrDeserError {
105    fn from(err: E) -> Self {
106        Self::Nickel {
107            error: err.into(),
108            files: None,
109        }
110    }
111}
112
113impl From<RustDeserializationError> for EvalOrDeserError {
114    fn from(err: RustDeserializationError) -> Self {
115        Self::Deser(err)
116    }
117}
118
119fn from_input<'a, T, Content, Source>(input: Input<Content, Source>) -> Result<T, EvalOrDeserError>
120where
121    T: serde::Deserialize<'a>,
122    Content: std::io::Read,
123    Source: Into<OsString>,
124{
125    let mut program =
126        Program::<CacheImpl>::new_from_input(input, std::io::stderr(), NullReporter {})
127            .map_err(error::IOError::from)?;
128
129    Ok(T::deserialize(program.eval_full_for_export().map_err(
130        |err| EvalOrDeserError::new(err, program.files()),
131    )?)?)
132}
133
134pub fn from_str<'a, T>(s: &'a str) -> Result<T, EvalOrDeserError>
135where
136    T: serde::Deserialize<'a>,
137{
138    from_input(Input::Source(Cursor::new(s), "string", InputFormat::Nickel))
139}
140
141pub fn from_slice<'a, T>(v: &'a [u8]) -> Result<T, EvalOrDeserError>
142where
143    T: serde::Deserialize<'a>,
144{
145    from_input(Input::Source(Cursor::new(v), "slice", InputFormat::Nickel))
146}
147
148pub fn from_path<T>(path: impl Into<OsString>) -> Result<T, EvalOrDeserError>
149where
150    T: serde::de::DeserializeOwned,
151{
152    from_input(Input::<std::fs::File, _>::Path(path))
153}
154
155pub fn from_reader<R, T>(rdr: R) -> Result<T, EvalOrDeserError>
156where
157    R: std::io::Read,
158    T: serde::de::DeserializeOwned,
159{
160    from_input(Input::Source(rdr, "reader", InputFormat::Nickel))
161}
162
163/// An error occurred during deserialization to Rust.
164#[derive(Debug, PartialEq, Eq, Clone)]
165pub enum RustDeserializationError {
166    InvalidType { expected: String, occurred: String },
167    MissingValue,
168    EmptyRecordField,
169    UnimplementedType { occurred: String },
170    InvalidRecordLength(usize),
171    InvalidArrayLength(usize),
172    Other(String),
173}
174
175impl<'de> serde::Deserializer<'de> for NickelValue {
176    type Error = RustDeserializationError;
177
178    /// Catch-all deserialization
179    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
180    where
181        V: Visitor<'de>,
182    {
183        match self.content() {
184            ValueContent::Null(_) => visitor.visit_unit(),
185            ValueContent::Bool(lens) => visitor.visit_bool(lens.take()),
186            ValueContent::Number(lens) => {
187                visitor.visit_f64(f64::rounding_from(lens.take(), RoundingMode::Nearest).0)
188            }
189            ValueContent::String(lens) => visitor.visit_string(lens.take().into_inner()),
190            ValueContent::EnumVariant(lens) => {
191                let enum_variant = lens.take();
192
193                visitor.visit_enum(EnumDeserializer {
194                    tag: enum_variant.tag.into_label(),
195                    value: enum_variant.arg,
196                })
197            }
198            ValueContent::Record(lens) => visit_record_container(lens.take(), visitor),
199            ValueContent::Array(lens) => visit_array_container(lens.take(), visitor),
200            lens => Err(RustDeserializationError::UnimplementedType {
201                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
202            }),
203        }
204    }
205
206    deserialize_number!(deserialize_i8, i8, visit_i8);
207    deserialize_number!(deserialize_i16, i16, visit_i16);
208    deserialize_number!(deserialize_i32, i32, visit_i32);
209    deserialize_number!(deserialize_i64, i64, visit_i64);
210    deserialize_number!(deserialize_i128, i128, visit_i128);
211    deserialize_number!(deserialize_u8, u8, visit_u8);
212    deserialize_number!(deserialize_u16, u16, visit_u16);
213    deserialize_number!(deserialize_u32, u32, visit_u32);
214    deserialize_number!(deserialize_u64, u64, visit_u64);
215    deserialize_number!(deserialize_u128, u128, visit_u128);
216    deserialize_number!(deserialize_f32, f32, visit_f32);
217    deserialize_number!(deserialize_f64, f64, visit_f64);
218
219    /// Deserialize nullable field.
220    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
221    where
222        V: Visitor<'de>,
223    {
224        if self.is_null() {
225            visitor.visit_none()
226        } else {
227            visitor.visit_some(self)
228        }
229    }
230
231    /// deserialize an enum variant or a record with a single item.
232    fn deserialize_enum<V>(
233        self,
234        _name: &str,
235        _variants: &'static [&'static str],
236        visitor: V,
237    ) -> Result<V::Value, Self::Error>
238    where
239        V: Visitor<'de>,
240    {
241        let (tag, arg) = match self.content() {
242            ValueContent::EnumVariant(lens) => {
243                let enum_var = lens.take();
244
245                (enum_var.tag.into_label(), enum_var.arg)
246            }
247            ValueContent::Record(lens) => {
248                let record = lens.take().unwrap_or_alloc();
249
250                let mut iter = record.fields.into_iter();
251                let (tag, arg) = match iter.next() {
252                    Some((id, Field { value, .. })) => (id, value),
253                    None => {
254                        return Err(RustDeserializationError::InvalidType {
255                            expected: "Record with single key".to_string(),
256                            occurred: "Record without keys".to_string(),
257                        });
258                    }
259                };
260
261                if iter.next().is_some() {
262                    return Err(RustDeserializationError::InvalidType {
263                        expected: "Record with single key".to_string(),
264                        occurred: "Record with multiple keys".to_string(),
265                    });
266                }
267
268                (tag.into_label(), arg)
269            }
270            lens => {
271                let value = lens.restore();
272
273                return Err(RustDeserializationError::InvalidType {
274                    expected: "Enum or Record".to_string(),
275                    occurred: value.type_of().unwrap_or("Other").to_owned(),
276                });
277            }
278        };
279
280        visitor.visit_enum(EnumDeserializer { tag, value: arg })
281    }
282
283    /// Deserialize pass-through tuples/structs.
284    fn deserialize_newtype_struct<V>(
285        self,
286        _name: &'static str,
287        visitor: V,
288    ) -> Result<V::Value, Self::Error>
289    where
290        V: Visitor<'de>,
291    {
292        visitor.visit_newtype_struct(self)
293    }
294
295    /// Deserialize a boolean value.
296    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
297    where
298        V: Visitor<'de>,
299    {
300        match self.as_inline() {
301            Some(InlineValue::True) => visitor.visit_bool(true),
302            Some(InlineValue::False) => visitor.visit_bool(false),
303            _ => Err(RustDeserializationError::InvalidType {
304                expected: "Bool".to_string(),
305                occurred: self.type_of().unwrap_or("Other").to_owned(),
306            }),
307        }
308    }
309
310    /// Deserialize a string as a char.
311    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
312    where
313        V: Visitor<'de>,
314    {
315        self.deserialize_string(visitor)
316    }
317
318    /// Deserialize a string (borrowed).
319    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
320    where
321        V: Visitor<'de>,
322    {
323        match self.as_string() {
324            Some(s) => visitor.visit_str(s),
325            _ => Err(RustDeserializationError::InvalidType {
326                expected: "String".to_string(),
327                occurred: self.type_of().unwrap_or("Other").to_owned(),
328            }),
329        }
330    }
331
332    /// Deserialize a string (owned).
333    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
334    where
335        V: Visitor<'de>,
336    {
337        match self.content() {
338            ValueContent::String(lens) => visitor.visit_string(lens.take().into_inner()),
339            lens => Err(RustDeserializationError::InvalidType {
340                expected: "String".to_string(),
341                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
342            }),
343        }
344    }
345
346    /// Deserialize a string value or an array as bytes.
347    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
348    where
349        V: Visitor<'de>,
350    {
351        self.deserialize_byte_buf(visitor)
352    }
353
354    /// Deserialize a string value or an array as bytes.
355    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
356    where
357        V: Visitor<'de>,
358    {
359        match self.content() {
360            ValueContent::String(lens) => visitor.visit_string(lens.take().into_inner()),
361            ValueContent::Array(lens) => visit_array(lens.take().unwrap_or_alloc().array, visitor),
362            lens => {
363                let value = lens.restore();
364
365                Err(RustDeserializationError::InvalidType {
366                    expected: "Str or Array".to_string(),
367                    occurred: value.type_of().unwrap_or("Other").to_owned(),
368                })
369            }
370        }
371    }
372
373    /// Deserialize `null` as `()`.
374    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
375    where
376        V: Visitor<'de>,
377    {
378        match self.as_inline() {
379            Some(InlineValue::Null) => visitor.visit_unit(),
380            _ => Err(RustDeserializationError::InvalidType {
381                expected: "Null".to_string(),
382                occurred: self.type_of().unwrap_or("Other").to_owned(),
383            }),
384        }
385    }
386
387    /// Deserialize `null` as a unit struct.
388    fn deserialize_unit_struct<V>(
389        self,
390        _name: &'static str,
391        visitor: V,
392    ) -> Result<V::Value, Self::Error>
393    where
394        V: Visitor<'de>,
395    {
396        self.deserialize_unit(visitor)
397    }
398
399    /// Deserialize an array as `Vec<T>`.
400    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
401    where
402        V: Visitor<'de>,
403    {
404        match self.content() {
405            ValueContent::Array(lens) => visit_array_container(lens.take(), visitor),
406            lens => Err(RustDeserializationError::InvalidType {
407                expected: "Array".to_string(),
408                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
409            }),
410        }
411    }
412
413    /// Deserialize an array as a tuple.
414    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
415    where
416        V: Visitor<'de>,
417    {
418        self.deserialize_seq(visitor)
419    }
420
421    /// Deserialize an array as a tuple struct.
422    fn deserialize_tuple_struct<V>(
423        self,
424        _name: &'static str,
425        _len: usize,
426        visitor: V,
427    ) -> Result<V::Value, Self::Error>
428    where
429        V: Visitor<'de>,
430    {
431        self.deserialize_seq(visitor)
432    }
433
434    /// Deserialize a record as a map.
435    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
436    where
437        V: Visitor<'de>,
438    {
439        match self.content() {
440            ValueContent::Record(lens) => visit_record_container(lens.take(), visitor),
441            lens => Err(RustDeserializationError::InvalidType {
442                expected: "Record".to_string(),
443                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
444            }),
445        }
446    }
447
448    /// Deserialize a record as a struct.
449    fn deserialize_struct<V>(
450        self,
451        _name: &'static str,
452        _fields: &'static [&'static str],
453        visitor: V,
454    ) -> Result<V::Value, Self::Error>
455    where
456        V: Visitor<'de>,
457    {
458        match self.content() {
459            ValueContent::Array(lens) => visit_array_container(lens.take(), visitor),
460            ValueContent::Record(lens) => visit_record_container(lens.take(), visitor),
461            lens => {
462                let value = lens.restore();
463
464                Err(RustDeserializationError::InvalidType {
465                    expected: "Record".to_string(),
466                    occurred: value.type_of().unwrap_or("Other").to_owned(),
467                })
468            }
469        }
470    }
471
472    /// Deserialize an indentifier as a string.
473    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
474    where
475        V: Visitor<'de>,
476    {
477        self.deserialize_string(visitor)
478    }
479
480    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
481    where
482        V: Visitor<'de>,
483    {
484        drop(self);
485        visitor.visit_unit()
486    }
487}
488
489struct ArrayDeserializer {
490    iter: <Array as IntoIterator>::IntoIter,
491}
492
493impl ArrayDeserializer {
494    fn new(array: Array) -> Self {
495        ArrayDeserializer {
496            iter: array.into_iter(),
497        }
498    }
499}
500
501impl<'de> SeqAccess<'de> for ArrayDeserializer {
502    type Error = RustDeserializationError;
503
504    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
505    where
506        T: DeserializeSeed<'de>,
507    {
508        match self.iter.next() {
509            Some(value) => seed.deserialize(value).map(Some),
510            None => Ok(None),
511        }
512    }
513
514    fn size_hint(&self) -> Option<usize> {
515        match self.iter.size_hint() {
516            (lower, Some(upper)) if lower == upper => Some(upper),
517            _ => None,
518        }
519    }
520}
521
522fn visit_array_container<'de, V>(
523    container: Container<ArrayData>,
524    visitor: V,
525) -> Result<V::Value, RustDeserializationError>
526where
527    V: Visitor<'de>,
528{
529    visit_array(container.unwrap_or_alloc().array, visitor)
530}
531
532fn visit_array<'de, V>(array: Array, visitor: V) -> Result<V::Value, RustDeserializationError>
533where
534    V: Visitor<'de>,
535{
536    let len = array.len();
537    let mut deserializer = ArrayDeserializer::new(array);
538    let seq = visitor.visit_seq(&mut deserializer)?;
539    if deserializer.iter.next().is_none() {
540        Ok(seq)
541    } else {
542        Err(RustDeserializationError::InvalidArrayLength(len))
543    }
544}
545
546struct RecordDeserializer {
547    iter: <IndexMap<LocIdent, Field> as IntoIterator>::IntoIter,
548    field: Option<Field>,
549}
550
551impl RecordDeserializer {
552    fn new(map: IndexMap<LocIdent, Field>) -> Self {
553        RecordDeserializer {
554            iter: map.into_iter(),
555            field: None,
556        }
557    }
558}
559
560impl<'de> MapAccess<'de> for RecordDeserializer {
561    type Error = RustDeserializationError;
562
563    fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
564    where
565        T: DeserializeSeed<'de>,
566    {
567        match self.iter.next() {
568            Some((key, value)) => {
569                self.field = Some(value);
570                seed.deserialize(key.label().into_deserializer()).map(Some)
571            }
572            None => Ok(None),
573        }
574    }
575
576    fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
577    where
578        T: DeserializeSeed<'de>,
579    {
580        match self.field.take() {
581            Some(Field {
582                value: Some(value), ..
583            }) => seed.deserialize(value),
584            // TODO: what to do about fields without definition is not totally clear (should an
585            // empty optional be considered as `None` or just disappear from the serialization?
586            // Probably the former). For now, we implement the same behavior as before the
587            // implementation of RFC005, which is to always fail on a field without definition.
588            //
589            // This should be relaxed in the future.
590            Some(Field { value: None, .. }) => Err(RustDeserializationError::EmptyRecordField),
591            _ => Err(RustDeserializationError::MissingValue),
592        }
593    }
594
595    fn size_hint(&self) -> Option<usize> {
596        match self.iter.size_hint() {
597            (lower, Some(upper)) if lower == upper => Some(upper),
598            _ => None,
599        }
600    }
601}
602
603fn visit_record_container<'de, V>(
604    container: Container<RecordData>,
605    visitor: V,
606) -> Result<V::Value, RustDeserializationError>
607where
608    V: Visitor<'de>,
609{
610    visit_record(container.unwrap_or_alloc().fields, visitor)
611}
612
613fn visit_record<'de, V>(
614    record: IndexMap<LocIdent, Field>,
615    visitor: V,
616) -> Result<V::Value, RustDeserializationError>
617where
618    V: Visitor<'de>,
619{
620    let len = record.len();
621    let mut deserializer = RecordDeserializer::new(record);
622    let map = visitor.visit_map(&mut deserializer)?;
623    let remaining = deserializer.iter.len();
624    if remaining == 0 {
625        Ok(map)
626    } else {
627        Err(RustDeserializationError::InvalidRecordLength(len))
628    }
629}
630
631struct VariantDeserializer {
632    value: Option<NickelValue>,
633}
634
635impl<'de> VariantAccess<'de> for VariantDeserializer {
636    type Error = RustDeserializationError;
637
638    fn unit_variant(self) -> Result<(), Self::Error> {
639        match self.value {
640            Some(value) => Deserialize::deserialize(value),
641            None => Ok(()),
642        }
643    }
644
645    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
646    where
647        T: DeserializeSeed<'de>,
648    {
649        match self.value {
650            Some(value) => seed.deserialize(value),
651            None => Err(RustDeserializationError::MissingValue),
652        }
653    }
654
655    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
656    where
657        V: Visitor<'de>,
658    {
659        match self.value.map(|v| v.content()) {
660            Some(ValueContent::Array(lens)) => {
661                let v = lens.take().unwrap_or_alloc().array;
662
663                if v.is_empty() {
664                    visitor.visit_unit()
665                } else {
666                    visit_array(v, visitor)
667                }
668            }
669            Some(lens) => Err(RustDeserializationError::InvalidType {
670                expected: "Array variant".to_string(),
671                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
672            }),
673            None => Err(RustDeserializationError::MissingValue),
674        }
675    }
676
677    fn struct_variant<V>(
678        self,
679        _fields: &'static [&'static str],
680        visitor: V,
681    ) -> Result<V::Value, Self::Error>
682    where
683        V: Visitor<'de>,
684    {
685        match self.value.map(|v| v.content()) {
686            Some(ValueContent::Record(lens)) => visit_record_container(lens.take(), visitor),
687            Some(lens) => Err(RustDeserializationError::InvalidType {
688                expected: "Array variant".to_string(),
689                occurred: lens.restore().type_of().unwrap_or("Other").to_owned(),
690            }),
691            None => Err(RustDeserializationError::MissingValue),
692        }
693    }
694}
695
696struct EnumDeserializer {
697    tag: String,
698    value: Option<NickelValue>,
699}
700
701impl<'de> EnumAccess<'de> for EnumDeserializer {
702    type Error = RustDeserializationError;
703    type Variant = VariantDeserializer;
704
705    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer), Self::Error>
706    where
707        V: DeserializeSeed<'de>,
708    {
709        let variant = self.tag.into_deserializer();
710        let visitor = VariantDeserializer { value: self.value };
711        seed.deserialize(variant).map(|v| (v, visitor))
712    }
713}
714
715impl std::fmt::Display for RustDeserializationError {
716    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
717        match self {
718            RustDeserializationError::InvalidType { expected, occurred } => {
719                write!(f, "invalid type: {occurred}, expected: {expected}")
720            }
721            RustDeserializationError::MissingValue => write!(f, "missing value"),
722            RustDeserializationError::EmptyRecordField => write!(f, "empty Metavalue"),
723            RustDeserializationError::InvalidRecordLength(len) => {
724                write!(f, "invalid record length, expected {len}")
725            }
726            RustDeserializationError::InvalidArrayLength(len) => {
727                write!(f, "invalid array length, expected {len}")
728            }
729            RustDeserializationError::UnimplementedType { occurred } => {
730                write!(f, "unimplemented conversion from type: {occurred}")
731            }
732            RustDeserializationError::Other(err) => write!(f, "{err}"),
733        }
734    }
735}
736
737impl std::error::Error for RustDeserializationError {}
738
739impl serde::de::Error for RustDeserializationError {
740    fn custom<T>(msg: T) -> Self
741    where
742        T: std::fmt::Display,
743    {
744        RustDeserializationError::Other(msg.to_string())
745    }
746}
747
748#[cfg(test)]
749mod tests {
750    use super::{from_path, from_reader, from_slice, from_str};
751    use std::io::Cursor;
752
753    use nickel_lang_utils::{
754        nickel_lang_core::{
755            deserialize::RustDeserializationError, error::NullReporter, eval::value::NickelValue,
756        },
757        test_program::TestProgram,
758    };
759    use serde::Deserialize;
760
761    fn eval(source: &str) -> NickelValue {
762        TestProgram::new_from_source(
763            Cursor::new(source),
764            "source",
765            std::io::stderr(),
766            NullReporter {},
767        )
768        .expect("program shouldn't fail")
769        .eval_full()
770        .expect("evaluation shouldn't fail")
771    }
772
773    #[test]
774    fn rust_deserialize_struct_with_fields() {
775        #[derive(Debug, PartialEq, Deserialize)]
776        #[serde(rename_all = "lowercase")]
777        enum E {
778            Foo,
779            Bar,
780        }
781
782        #[derive(Debug, PartialEq, Deserialize)]
783        #[serde(rename_all = "lowercase")]
784        enum H {
785            Foo(u16),
786            Bar(String),
787        }
788
789        #[derive(Debug, PartialEq, Deserialize)]
790        struct A {
791            a: f64,
792            b: String,
793            c: (),
794            d: bool,
795            e: E,
796            f: Option<bool>,
797            g: i16,
798            h: H,
799        }
800
801        assert_eq!(
802            A::deserialize(eval(
803                r#"{ a = 10, b = "test string", c = null, d = true, e = 'foo, f = null,
804                g = -10, h = { bar = "some other string" } }"#
805            ))
806            .expect("deserialization shouldn't fail"),
807            A {
808                a: 10.0,
809                b: "test string".to_string(),
810                c: (),
811                d: true,
812                e: E::Foo,
813                f: None,
814                g: -10,
815                h: H::Bar("some other string".to_string())
816            }
817        )
818    }
819
820    #[test]
821    fn rust_deserialize_array_of_numbers() {
822        assert_eq!(
823            Vec::<f64>::deserialize(eval(r#"[1, 2, 3, 4]"#))
824                .expect("deserialization shouldn't fail"),
825            vec![1.0, 2.0, 3.0, 4.0]
826        )
827    }
828
829    #[test]
830    fn rust_deserialize_fail_non_data() {
831        #[derive(Debug, PartialEq, Deserialize)]
832        struct A;
833
834        assert_eq!(
835            A::deserialize(eval(r#"fun a b => a + b"#)),
836            Err(RustDeserializationError::InvalidType {
837                expected: "Null".to_string(),
838                occurred: "Function".to_string()
839            })
840        )
841    }
842
843    #[test]
844    fn rust_deserialize_ignore_annotation() {
845        #[derive(Debug, PartialEq, Deserialize)]
846        struct A {
847            a: f64,
848        }
849
850        assert_eq!(
851            A::deserialize(eval(r#"{ a = (10 | Number) }"#))
852                .expect("deserialization shouldn't fail"),
853            A { a: 10.0 }
854        )
855    }
856
857    #[test]
858    fn rust_deserialize_wrappers() {
859        #[derive(Debug, Clone, PartialEq, Deserialize)]
860        struct A {
861            a: f64,
862            b: Vec<String>,
863        }
864
865        let a = A {
866            a: 10.0,
867            b: vec!["a".into(), "b".into()],
868        };
869
870        assert_eq!(
871            from_str::<A>(r#"{ a = (10 | Number), b = ["a", "b"] }"#).unwrap(),
872            a.clone()
873        );
874
875        assert_eq!(
876            from_slice::<A>(br#"{ a = (10 | Number), b = ["a", "b"] }"#).unwrap(),
877            a.clone()
878        );
879
880        assert_eq!(
881            from_reader::<_, A>(Cursor::new(r#"{ a = (10 | Number), b = ["a", "b"] }"#)).unwrap(),
882            a.clone()
883        );
884
885        assert_eq!(
886            from_reader::<_, A>(Cursor::new(br#"{ a = (10 | Number), b = ["a", "b"] }"#)).unwrap(),
887            a.clone()
888        );
889
890        assert_eq!(
891            from_path::<f64>(
892                nickel_lang_utils::project_root::project_root()
893                    .join("examples/fibonacci/fibonacci.ncl")
894            )
895            .unwrap(),
896            55.0
897        );
898
899        assert!(from_str::<String>("will not parse").is_err());
900        assert!(from_str::<String>("1 | String").is_err());
901    }
902}