diff options
Diffstat (limited to 'dhall')
-rw-r--r-- | dhall/Cargo.toml | 4 | ||||
-rw-r--r-- | dhall/src/error/builder.rs | 25 | ||||
-rw-r--r-- | dhall/src/syntax/binary/decode.rs | 174 | ||||
-rw-r--r-- | dhall/src/syntax/binary/encode.rs | 80 |
4 files changed, 217 insertions, 66 deletions
diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml index 111a7ea..7923009 100644 --- a/dhall/Cargo.toml +++ b/dhall/Cargo.toml @@ -20,7 +20,7 @@ harness = false path = "tests/spec.rs" [dependencies] -annotate-snippets = "0.7.0" +annotate-snippets = "0.9.0" hex = "0.4.2" itertools = "0.9.0" lazy_static = "1.4.0" @@ -29,7 +29,7 @@ percent-encoding = "2.1.0" pest = "2.1" pest_consume = "1.0" serde = "1.0" -serde_cbor = "0.9.0" +serde_cbor = "0.11.0" sha2 = "0.9.0" url = "2.1" diff --git a/dhall/src/error/builder.rs b/dhall/src/error/builder.rs index 3ee65fb..b659230 100644 --- a/dhall/src/error/builder.rs +++ b/dhall/src/error/builder.rs @@ -29,9 +29,9 @@ struct FreeAnnotation { } impl SpannedAnnotation { - fn into_annotation(self) -> SourceAnnotation { + fn to_annotation(&self) -> SourceAnnotation<'_> { SourceAnnotation { - label: self.message, + label: &self.message, annotation_type: self.annotation_type, range: self.span.as_char_range(), } @@ -39,9 +39,9 @@ impl SpannedAnnotation { } impl FreeAnnotation { - fn into_annotation(self) -> Annotation { + fn to_annotation(&self) -> Annotation<'_> { Annotation { - label: Some(self.message), + label: Some(&self.message), id: None, annotation_type: self.annotation_type, } @@ -124,31 +124,32 @@ impl ErrorBuilder { self.consumed = true; drop(self); // Get rid of the self reference so we don't use it by mistake. + let input; let slices = if this.annotations.is_empty() { Vec::new() } else { - let input = this.annotations[0].span.to_input(); + input = this.annotations[0].span.to_input(); let annotations = this .annotations - .into_iter() - .map(|annot| annot.into_annotation()) + .iter() + .map(|annot| annot.to_annotation()) .collect(); vec![Slice { - source: input, + source: &input, line_start: 1, // TODO - origin: Some("<current file>".to_string()), + origin: Some("<current file>"), fold: true, annotations, }] }; let footer = this .footer - .into_iter() - .map(|annot| annot.into_annotation()) + .iter() + .map(|annot| annot.to_annotation()) .collect(); let snippet = Snippet { - title: Some(this.title.into_annotation()), + title: Some(this.title.to_annotation()), slices, footer, opt: Default::default(), diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs index d360949..f4747d3 100644 --- a/dhall/src/syntax/binary/decode.rs +++ b/dhall/src/syntax/binary/decode.rs @@ -1,5 +1,7 @@ use itertools::Itertools; -use serde_cbor::value::value as cbor; +use serde::de; +use std::collections::BTreeMap; +use std::fmt; use std::iter::FromIterator; use crate::error::DecodeError; @@ -19,18 +21,32 @@ pub fn decode(data: &[u8]) -> Result<DecodedExpr, DecodeError> { } } +/// An enum that can encode most CBOR values. +#[derive(Clone, Debug, PartialEq)] +pub enum Value { + Null, + Bool(bool), + U64(u64), + I64(i64), + F64(f64), + String(String), + Array(Vec<Value>), + Object(BTreeMap<String, Value>), + Bytes(Vec<u8>), +} + // Should probably rename this fn rc(x: UnspannedExpr) -> Expr { Expr::new(x, Span::Decoded) } -fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { +fn cbor_value_to_dhall(data: &Value) -> Result<DecodedExpr, DecodeError> { use crate::builtins::Builtin; use crate::operations::BinOp; - use cbor::Value::*; use syntax::Const; use ExprKind::*; use OpKind::*; + use Value::*; Ok(rc(match data { String(s) => match Builtin::parse(s) { Some(b) => ExprKind::Builtin(b), @@ -467,16 +483,13 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { } fn cbor_map_to_dhall_map<'a, T>( - map: impl IntoIterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>, + map: impl IntoIterator<Item = (&'a String, &'a Value)>, ) -> Result<T, DecodeError> where T: FromIterator<(Label, DecodedExpr)>, { map.into_iter() .map(|(k, v)| -> Result<(_, _), _> { - let k = k.as_string().ok_or_else(|| { - DecodeError::WrongFormatError("map/key".to_owned()) - })?; let v = cbor_value_to_dhall(v)?; Ok((Label::from(k.as_ref()), v)) }) @@ -484,21 +497,158 @@ where } fn cbor_map_to_dhall_opt_map<'a, T>( - map: impl IntoIterator<Item = (&'a cbor::ObjectKey, &'a cbor::Value)>, + map: impl IntoIterator<Item = (&'a String, &'a Value)>, ) -> Result<T, DecodeError> where T: FromIterator<(Label, Option<DecodedExpr>)>, { map.into_iter() .map(|(k, v)| -> Result<(_, _), _> { - let k = k.as_string().ok_or_else(|| { - DecodeError::WrongFormatError("map/key".to_owned()) - })?; let v = match v { - cbor::Value::Null => None, + Value::Null => None, _ => Some(cbor_value_to_dhall(v)?), }; Ok((Label::from(k.as_ref()), v)) }) .collect::<Result<_, _>>() } + +impl Value { + pub fn as_string(&self) -> Option<&String> { + if let Value::String(v) = self { + Some(v) + } else { + None + } + } +} + +impl<'de> de::Deserialize<'de> for Value { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> + where + D: de::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("any valid CBOR value") + } + + #[inline] + fn visit_str<E>(self, value: &str) -> Result<Value, E> + where + E: de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string<E>(self, value: String) -> Result<Value, E> + where + E: de::Error, + { + Ok(Value::String(value)) + } + #[inline] + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: de::Error, + { + self.visit_byte_buf(v.to_owned()) + } + + #[inline] + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Bytes(v)) + } + + #[inline] + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::U64(v)) + } + + #[inline] + fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::I64(v)) + } + + #[inline] + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Bool(v)) + } + + #[inline] + fn visit_none<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + self.visit_unit() + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::Null) + } + + #[inline] + fn visit_seq<V>( + self, + mut visitor: V, + ) -> Result<Self::Value, V::Error> + where + V: de::SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(elem) = visitor.next_element()? { + vec.push(elem); + } + + Ok(Value::Array(vec)) + } + + #[inline] + fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error> + where + V: de::MapAccess<'de>, + { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = visitor.next_entry()? { + values.insert(key, value); + } + + Ok(Value::Object(values)) + } + + #[inline] + fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Value::F64(v)) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs index 33c7fa5..cf2e112 100644 --- a/dhall/src/syntax/binary/encode.rs +++ b/dhall/src/syntax/binary/encode.rs @@ -1,4 +1,3 @@ -use serde_cbor::value::value as cbor; use std::collections::BTreeMap; use std::vec; @@ -17,8 +16,13 @@ pub fn encode(expr: &Expr) -> Result<Vec<u8>, EncodeError> { } enum Serialize<'a> { + Null, + Tag(u64), + Label(&'a Label), + Text(String), + Bytes(Vec<u8>), + Expr(&'a Expr), - CBOR(cbor::Value), RecordMap(&'a BTreeMap<Label, Expr>), UnionMap(&'a BTreeMap<Label, Option<Expr>>), } @@ -44,7 +48,6 @@ fn serialize_subexpr<S>(ser: S, e: &Expr) -> Result<S::Ok, S::Error> where S: serde::ser::Serializer, { - use cbor::Value::{String, I64, U64}; use std::iter::once; use syntax::ExprKind::*; use syntax::NumKind::*; @@ -54,18 +57,18 @@ where fn expr(x: &Expr) -> self::Serialize<'_> { self::Serialize::Expr(x) } - let cbor = - |v: cbor::Value| -> self::Serialize<'_> { self::Serialize::CBOR(v) }; - let tag = |x: u64| cbor(U64(x)); - let null = || cbor(cbor::Value::Null); - let label = |l: &Label| cbor(cbor::Value::String(l.into())); + fn label(x: &Label) -> self::Serialize<'_> { + self::Serialize::Label(x) + } + let tag = |x: u64| Serialize::Tag(x); + let null = || Serialize::Null; match e.as_ref() { Const(c) => ser.serialize_str(&c.to_string()), Builtin(b) => ser.serialize_str(&b.to_string()), Num(Bool(b)) => ser.serialize_bool(*b), - Num(Natural(n)) => ser_seq!(ser; tag(15), U64(*n as u64)), - Num(Integer(n)) => ser_seq!(ser; tag(16), I64(*n as i64)), + Num(Natural(n)) => ser_seq!(ser; tag(15), n), + Num(Integer(n)) => ser_seq!(ser; tag(16), n), Num(Double(n)) => { let n: f64 = (*n).into(); ser.serialize_f64(n) @@ -73,13 +76,13 @@ where Op(BoolIf(x, y, z)) => { ser_seq!(ser; tag(14), expr(x), expr(y), expr(z)) } - Var(V(l, n)) if l == &"_".into() => ser.serialize_u64(*n as u64), - Var(V(l, n)) => ser_seq!(ser; label(l), U64(*n as u64)), - Lam(l, x, y) if l == &"_".into() => { + Var(V(l, n)) if l.as_ref() == "_" => ser.serialize_u64(*n as u64), + Var(V(l, n)) => ser_seq!(ser; label(l), (*n as u64)), + Lam(l, x, y) if l.as_ref() == "_" => { ser_seq!(ser; tag(1), expr(x), expr(y)) } Lam(l, x, y) => ser_seq!(ser; tag(1), label(l), expr(x), expr(y)), - Pi(l, x, y) if l == &"_".into() => { + Pi(l, x, y) if l.as_ref() == "_" => { ser_seq!(ser; tag(2), expr(x), expr(y)) } Pi(l, x, y) => ser_seq!(ser; tag(2), label(l), expr(x), expr(y)), @@ -128,7 +131,7 @@ where use syntax::InterpolatedTextContents::{Expr, Text}; ser.collect_seq(once(tag(18)).chain(xs.iter().map(|x| match x { Expr(x) => expr(x), - Text(x) => cbor(String(x)), + Text(x) => Serialize::Text(x), }))) } RecordType(map) => ser_seq!(ser; tag(7), RecordMap(map)), @@ -152,7 +155,7 @@ where ImportAlt => 11, Equivalence => 12, }; - ser_seq!(ser; tag(3), U64(op), expr(x), expr(y)) + ser_seq!(ser; tag(3), op, expr(x), expr(y)) } Op(Merge(x, y, None)) => ser_seq!(ser; tag(6), expr(x), expr(y)), Op(Merge(x, y, Some(z))) => { @@ -183,8 +186,8 @@ fn serialize_import<S>(ser: S, import: &Import<Expr>) -> Result<S::Ok, S::Error> where S: serde::ser::Serializer, { - use cbor::Value::{Bytes, Null, U64}; use serde::ser::SerializeSeq; + use Serialize::Null; let count = 4 + match &import.location { ImportTarget::Remote(url) => 3 + url.path.file_path.len(), @@ -194,24 +197,23 @@ where }; let mut ser_seq = ser.serialize_seq(Some(count))?; - ser_seq.serialize_element(&U64(24))?; + ser_seq.serialize_element(&24)?; - let hash = match &import.hash { - None => Null, + match &import.hash { + None => ser_seq.serialize_element(&Null)?, Some(Hash::SHA256(h)) => { let mut bytes = vec![18, 32]; bytes.extend_from_slice(h); - Bytes(bytes) + ser_seq.serialize_element(&Serialize::Bytes(bytes))?; } - }; - ser_seq.serialize_element(&hash)?; + } let mode = match import.mode { ImportMode::Code => 0, ImportMode::RawText => 1, ImportMode::Location => 2, }; - ser_seq.serialize_element(&U64(mode))?; + ser_seq.serialize_element(&mode)?; let scheme = match &import.location { ImportTarget::Remote(url) => match url.scheme { @@ -227,7 +229,7 @@ where ImportTarget::Env(_) => 6, ImportTarget::Missing => 7, }; - ser_seq.serialize_element(&U64(scheme))?; + ser_seq.serialize_element(&scheme)?; match &import.location { ImportTarget::Remote(url) => { @@ -265,23 +267,21 @@ impl<'a> serde::ser::Serialize for Serialize<'a> { where S: serde::ser::Serializer, { + use Serialize::*; match self { - Serialize::Expr(e) => serialize_subexpr(ser, e), - Serialize::CBOR(v) => v.serialize(ser), - Serialize::RecordMap(map) => { - ser.collect_map(map.iter().map(|(k, v)| { - (cbor::Value::String(k.into()), Serialize::Expr(v)) - })) - } - Serialize::UnionMap(map) => { - ser.collect_map(map.iter().map(|(k, v)| { - let v = match v { - Some(x) => Serialize::Expr(x), - None => Serialize::CBOR(cbor::Value::Null), - }; - (cbor::Value::String(k.into()), v) - })) + Null => ser.serialize_unit(), + Tag(v) => ser.serialize_u64(*v), + Label(v) => ser.serialize_str(v.as_ref()), + Text(v) => ser.serialize_str(v), + Bytes(v) => ser.serialize_bytes(v), + + Expr(e) => serialize_subexpr(ser, e), + RecordMap(map) => { + ser.collect_map(map.iter().map(|(k, v)| (Label(k), Expr(v)))) } + UnionMap(map) => ser.collect_map( + map.iter().map(|(k, v)| (Label(k), v.as_ref().map(Expr))), + ), } } } |