summaryrefslogtreecommitdiff
path: root/dhall/src/syntax
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dhall/src/syntax/binary/decode.rs174
-rw-r--r--dhall/src/syntax/binary/encode.rs80
2 files changed, 202 insertions, 52 deletions
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))),
+ ),
}
}
}