Optimize CBOR decoding (#3723)

This commit is contained in:
Micha de Vries 2024-03-19 16:00:30 +00:00 committed by GitHub
parent da483716c5
commit 00bc9db496
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,7 +1,6 @@
use ciborium::Value as Data; use ciborium::Value as Data;
use geo::{LineString, Point, Polygon}; use geo::{LineString, Point, Polygon};
use geo_types::{MultiLineString, MultiPoint, MultiPolygon}; use geo_types::{MultiLineString, MultiPoint, MultiPolygon};
use std::collections::BTreeMap;
use std::iter::once; use std::iter::once;
use std::ops::Deref; use std::ops::Deref;
use surrealdb::sql::Datetime; use surrealdb::sql::Datetime;
@ -94,36 +93,31 @@ impl TryFrom<Cbor> for Value {
Ok(v) => Ok(v.into()), Ok(v) => Ok(v.into()),
_ => Err("Expected a valid RecordID value"), _ => Err("Expected a valid RecordID value"),
}, },
Data::Array(mut v) if v.len() == 2 => match (v.remove(0), v.remove(0)) { Data::Array(mut v) if v.len() == 2 => {
(Data::Text(tb), Data::Text(id)) => { let tb = match Value::try_from(Cbor(v.remove(0))) {
Ok(Value::from(Thing::from((tb, id)))) Ok(Value::Strand(tb)) => tb.0,
} Ok(Value::Table(tb)) => tb.0,
(Data::Text(tb), Data::Integer(id)) => { _ => return Err(
Ok(Value::from(Thing::from((tb, Id::from(i128::from(id) as i64))))) "Expected the tb of a Record Id to be a String or Table value",
}
(Data::Text(tb), Data::Array(id)) => Ok(Value::from(Thing::from((
tb,
Id::from(
id.into_iter()
.map(|v| Value::try_from(Cbor(v)))
.collect::<Result<Vec<Value>, &str>>()?,
), ),
)))), };
(Data::Text(tb), Data::Map(id)) => Ok(Value::from(Thing::from((
tb, match Value::try_from(Cbor(v.remove(0))) {
Id::from( Ok(Value::Strand(id)) => {
id.into_iter() Ok(Value::from(Thing::from((tb, Id::from(id)))))
.map(|(k, v)| { }
let k = Ok(Value::Number(Number::Int(id))) => {
Value::try_from(Cbor(k)).map(|k| k.as_raw_string()); Ok(Value::from(Thing::from((tb, Id::from(id)))))
let v = Value::try_from(Cbor(v)); }
Ok((k?, v?)) Ok(Value::Array(id)) => {
}) Ok(Value::from(Thing::from((tb, Id::from(id)))))
.collect::<Result<BTreeMap<String, Value>, &str>>()?, }
), Ok(Value::Object(id)) => {
)))), Ok(Value::from(Thing::from((tb, Id::from(id)))))
_ => Err("Expected a CBOR array with 2 elements, a text data type, and a valid ID type"), }
}, _ => Err("Expected the id of a Record Id to be a String, Integer, Array or Object value"),
}
}
_ => Err("Expected a CBOR text data type, or a CBOR array with 2 elements"), _ => Err("Expected a CBOR text data type, or a CBOR array with 2 elements"),
}, },
// A literal table // A literal table
@ -131,18 +125,18 @@ impl TryFrom<Cbor> for Value {
Data::Text(v) => Ok(Value::Table(v.into())), Data::Text(v) => Ok(Value::Table(v.into())),
_ => Err("Expected a CBOR text data type"), _ => Err("Expected a CBOR text data type"),
}, },
TAG_GEOMETRY_POINT => match v.deref() { TAG_GEOMETRY_POINT => match *v {
Data::Array(v) if v.len() == 2 => { Data::Array(mut v) if v.len() == 2 => {
let x = Value::try_from(Cbor(v.clone().remove(0)))?; let x = Value::try_from(Cbor(v.remove(0)))?;
let y = Value::try_from(Cbor(v.clone().remove(0)))?; let y = Value::try_from(Cbor(v.remove(0)))?;
match (x, y) { match (x, y) {
(Value::Number(x), Value::Number(y)) => { (Value::Number(x), Value::Number(y)) => Ok(Value::Geometry(
Ok(Value::Geometry(Geometry::Point((x.as_float(), y.as_float()).into()))) Geometry::Point((x.as_float(), y.as_float()).into()),
}, )),
_ => Err("Expected a CBOR array with 2 decimal values"), _ => Err("Expected a CBOR array with 2 decimal values"),
} }
}, }
_ => Err("Expected a CBOR array with 2 decimal values"), _ => Err("Expected a CBOR array with 2 decimal values"),
}, },
TAG_GEOMETRY_LINE => match v.deref() { TAG_GEOMETRY_LINE => match v.deref() {
@ -151,12 +145,12 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(Geometry::Point(v)) => Ok(v), Value::Geometry(Geometry::Point(v)) => Ok(v),
_ => Err("Expected a CBOR array with Geometry Point values") _ => Err("Expected a CBOR array with Geometry Point values"),
}) })
.collect::<Result<Vec<Point>, &str>>()?; .collect::<Result<Vec<Point>, &str>>()?;
Ok(Value::Geometry(Geometry::Line(LineString::from(points)))) Ok(Value::Geometry(Geometry::Line(LineString::from(points))))
}, }
_ => Err("Expected a CBOR array with Geometry Point values"), _ => Err("Expected a CBOR array with Geometry Point values"),
}, },
TAG_GEOMETRY_POLYGON => match v.deref() { TAG_GEOMETRY_POLYGON => match v.deref() {
@ -165,17 +159,22 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(Geometry::Line(v)) => Ok(v), Value::Geometry(Geometry::Line(v)) => Ok(v),
_ => Err("Expected a CBOR array with Geometry Line values") _ => Err("Expected a CBOR array with Geometry Line values"),
}) })
.collect::<Result<Vec<LineString>, &str>>()?; .collect::<Result<Vec<LineString>, &str>>()?;
let first = match lines.first() { let first = match lines.first() {
Some(v) => v, Some(v) => v,
_ => return Err("Expected a CBOR array with at least two Geometry Line values") _ => return Err(
"Expected a CBOR array with at least two Geometry Line values",
),
}; };
Ok(Value::Geometry(Geometry::Polygon(Polygon::new(first.clone(), Vec::from(&lines[1..]))))) Ok(Value::Geometry(Geometry::Polygon(Polygon::new(
}, first.clone(),
Vec::from(&lines[1..]),
))))
}
_ => Err("Expected a CBOR array with at least two Geometry Line values"), _ => Err("Expected a CBOR array with at least two Geometry Line values"),
}, },
TAG_GEOMETRY_MULTIPOINT => match v.deref() { TAG_GEOMETRY_MULTIPOINT => match v.deref() {
@ -184,12 +183,12 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(Geometry::Point(v)) => Ok(v), Value::Geometry(Geometry::Point(v)) => Ok(v),
_ => Err("Expected a CBOR array with Geometry Point values") _ => Err("Expected a CBOR array with Geometry Point values"),
}) })
.collect::<Result<Vec<Point>, &str>>()?; .collect::<Result<Vec<Point>, &str>>()?;
Ok(Value::Geometry(Geometry::MultiPoint(MultiPoint::from(points)))) Ok(Value::Geometry(Geometry::MultiPoint(MultiPoint::from(points))))
}, }
_ => Err("Expected a CBOR array with Geometry Point values"), _ => Err("Expected a CBOR array with Geometry Point values"),
}, },
TAG_GEOMETRY_MULTILINE => match v.deref() { TAG_GEOMETRY_MULTILINE => match v.deref() {
@ -198,12 +197,12 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(Geometry::Line(v)) => Ok(v), Value::Geometry(Geometry::Line(v)) => Ok(v),
_ => Err("Expected a CBOR array with Geometry Line values") _ => Err("Expected a CBOR array with Geometry Line values"),
}) })
.collect::<Result<Vec<LineString>, &str>>()?; .collect::<Result<Vec<LineString>, &str>>()?;
Ok(Value::Geometry(Geometry::MultiLine(MultiLineString::new(lines)))) Ok(Value::Geometry(Geometry::MultiLine(MultiLineString::new(lines))))
}, }
_ => Err("Expected a CBOR array with Geometry Point values"), _ => Err("Expected a CBOR array with Geometry Point values"),
}, },
TAG_GEOMETRY_MULTIPOLYGON => match v.deref() { TAG_GEOMETRY_MULTIPOLYGON => match v.deref() {
@ -212,12 +211,14 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(Geometry::Polygon(v)) => Ok(v), Value::Geometry(Geometry::Polygon(v)) => Ok(v),
_ => Err("Expected a CBOR array with Geometry Polygon values") _ => Err("Expected a CBOR array with Geometry Polygon values"),
}) })
.collect::<Result<Vec<Polygon>, &str>>()?; .collect::<Result<Vec<Polygon>, &str>>()?;
Ok(Value::Geometry(Geometry::MultiPolygon(MultiPolygon::from(polygons)))) Ok(Value::Geometry(Geometry::MultiPolygon(MultiPolygon::from(
}, polygons,
))))
}
_ => Err("Expected a CBOR array with Geometry Polygon values"), _ => Err("Expected a CBOR array with Geometry Polygon values"),
}, },
TAG_GEOMETRY_COLLECTION => match v.deref() { TAG_GEOMETRY_COLLECTION => match v.deref() {
@ -226,12 +227,12 @@ impl TryFrom<Cbor> for Value {
.iter() .iter()
.map(|v| match Value::try_from(Cbor(v.clone()))? { .map(|v| match Value::try_from(Cbor(v.clone()))? {
Value::Geometry(v) => Ok(v), Value::Geometry(v) => Ok(v),
_ => Err("Expected a CBOR array with Geometry values") _ => Err("Expected a CBOR array with Geometry values"),
}) })
.collect::<Result<Vec<Geometry>, &str>>()?; .collect::<Result<Vec<Geometry>, &str>>()?;
Ok(Value::Geometry(Geometry::Collection(geometries))) Ok(Value::Geometry(Geometry::Collection(geometries)))
}, }
_ => Err("Expected a CBOR array with Geometry values"), _ => Err("Expected a CBOR array with Geometry values"),
}, },
// An unknown tag // An unknown tag