From 338a76b324c7fbf2999e8d8f3a3c5d6ed66ee5df Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 9 Feb 2024 02:55:44 -0500 Subject: [PATCH] wip --- lib/oxigraph/src/sparql/eval.rs | 8 +++++ lib/oxigraph/src/storage/binary_encoder.rs | 11 +++++++ lib/oxigraph/src/storage/error.rs | 9 ++++++ lib/oxigraph/src/storage/numeric_encoder.rs | 33 ++++++--------------- lib/oxsdatatypes/src/geopoint.rs | 29 ++++++++++++++---- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/lib/oxigraph/src/sparql/eval.rs b/lib/oxigraph/src/sparql/eval.rs index 174f41fa..71df01e3 100644 --- a/lib/oxigraph/src/sparql/eval.rs +++ b/lib/oxigraph/src/sparql/eval.rs @@ -13,6 +13,7 @@ use json_event_parser::{JsonEvent, ToWriteJsonWriter}; use md5::Md5; use oxilangtag::LanguageTag; use oxiri::Iri; +use oxrdf::vocab::geosparql; use oxrdf::{TermRef, Variable}; use oxsdatatypes::*; use rand::random; @@ -2930,6 +2931,7 @@ fn to_string_id(dataset: &DatasetView, term: &EncodedTerm) -> Option { Some(build_string_id(dataset, &value.to_string())) } + EncodedTerm::GeoPoint(value) => Some(build_string_id(dataset, &value.to_string())), } } @@ -3318,6 +3320,11 @@ fn equals(a: &EncodedTerm, b: &EncodedTerm) -> Option { _ if b.is_unknown_typed_literal() => None, _ => Some(false), }, + EncodedTerm::GeoPoint(a) => match b { + EncodedTerm::GeoPoint(b) => Some(a == b), + _ if b.is_unknown_typed_literal() => None, + _ => Some(false), + }, EncodedTerm::Triple(a) => { if let EncodedTerm::Triple(b) = b { Some( @@ -3672,6 +3679,7 @@ fn datatype(dataset: &DatasetView, value: &EncodedTerm) -> Option { EncodedTerm::DayTimeDurationLiteral(..) => { Some(encode_named_node(dataset, xsd::DAY_TIME_DURATION)) } + EncodedTerm::GeoPoint(..) => Some(encode_named_node(dataset, geosparql::WKT_LITERAL)), } } diff --git a/lib/oxigraph/src/storage/binary_encoder.rs b/lib/oxigraph/src/storage/binary_encoder.rs index 25626571..3f37f5c0 100644 --- a/lib/oxigraph/src/storage/binary_encoder.rs +++ b/lib/oxigraph/src/storage/binary_encoder.rs @@ -46,6 +46,7 @@ const TYPE_G_MONTH_LITERAL: u8 = 41; const TYPE_DURATION_LITERAL: u8 = 42; const TYPE_YEAR_MONTH_DURATION_LITERAL: u8 = 43; const TYPE_DAY_TIME_DURATION_LITERAL: u8 = 44; +const TYPE_GEO_POINT_LITERAL: u8 = 45; const TYPE_TRIPLE: u8 = 48; #[derive(Clone, Copy)] @@ -388,6 +389,11 @@ impl TermReader for R { self.read_exact(&mut buffer)?; Ok(DayTimeDuration::from_be_bytes(buffer).into()) } + TYPE_GEO_POINT_LITERAL => { + let mut buffer = [0; 16]; + self.read_exact(&mut buffer)?; + Ok(DayTimeDuration::from_be_bytes(buffer).into()) + } TYPE_TRIPLE => Ok(EncodedTriple { subject: self.read_term()?, predicate: self.read_term()?, @@ -622,6 +628,11 @@ pub fn write_term(sink: &mut Vec, term: &EncodedTerm) { sink.push(TYPE_DAY_TIME_DURATION_LITERAL); sink.extend_from_slice(&value.to_be_bytes()) } + EncodedTerm::GeoPoint(value) => { + sink.push(TYPE_GEO_POINT_LITERAL); + sink.extend_from_slice(&value.x.to_be_bytes()); + sink.extend_from_slice(&value.y.to_be_bytes()); + } EncodedTerm::Triple(value) => { sink.push(TYPE_TRIPLE); write_term(sink, &value.subject); diff --git a/lib/oxigraph/src/storage/error.rs b/lib/oxigraph/src/storage/error.rs index 7a119637..681478bf 100644 --- a/lib/oxigraph/src/storage/error.rs +++ b/lib/oxigraph/src/storage/error.rs @@ -1,5 +1,7 @@ use crate::io::{ParseError, RdfFormat}; +use crate::storage::numeric_encoder::EncodedTerm; use oxiri::IriParseError; +use oxrdf::TermRef; use std::error::Error; use std::io; @@ -45,6 +47,13 @@ impl CorruptionError { Self::Other(error.into()) } + /// Builds an error from encoding and the term. + #[inline] + pub(crate) fn from_encoded_term(encoded: &EncodedTerm, term: &TermRef<'_>) -> Self { + // TODO: eventually use a dedicated error enum value + Self::new(format!("Invalid term encoding {encoded:?} for {term}")) + } + /// Builds an error from a printable error message. #[inline] pub(crate) fn msg(msg: impl Into) -> Self { diff --git a/lib/oxigraph/src/storage/numeric_encoder.rs b/lib/oxigraph/src/storage/numeric_encoder.rs index e730a163..8bf3f89c 100644 --- a/lib/oxigraph/src/storage/numeric_encoder.rs +++ b/lib/oxigraph/src/storage/numeric_encoder.rs @@ -95,6 +95,7 @@ pub enum EncodedTerm { DurationLiteral(Duration), YearMonthDurationLiteral(YearMonthDuration), DayTimeDurationLiteral(DayTimeDuration), + GeoPoint(GeoPoint), Triple(Arc), } @@ -266,6 +267,7 @@ impl Hash for EncodedTerm { Self::YearMonthDurationLiteral(value) => value.hash(state), Self::DayTimeDurationLiteral(value) => value.hash(state), Self::Triple(value) => value.hash(state), + EncodedTerm::GeoPoint(_) => {} } } } @@ -713,19 +715,13 @@ pub fn insert_term Result<(), StorageError>>( if let EncodedTerm::NamedNode { iri_id } = encoded { insert_str(iri_id, node.as_str()) } else { - Err( - CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}")) - .into(), - ) + Err(CorruptionError::from_encoded_term(encoded, &term).into()) } } TermRef::BlankNode(node) => match encoded { EncodedTerm::BigBlankNode { id_id } => insert_str(id_id, node.as_str()), EncodedTerm::SmallBlankNode(..) | EncodedTerm::NumericalBlankNode { .. } => Ok(()), - _ => Err( - CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}")) - .into(), - ), + _ => Err(CorruptionError::from_encoded_term(encoded, &term).into()), }, TermRef::Literal(literal) => match encoded { EncodedTerm::BigStringLiteral { value_id } @@ -736,10 +732,7 @@ pub fn insert_term Result<(), StorageError>>( if let Some(language) = literal.language() { insert_str(language_id, language) } else { - Err(CorruptionError::new(format!( - "Invalid term encoding {encoded:?} for {term}" - )) - .into()) + Err(CorruptionError::from_encoded_term(encoded, &term).into()) } } EncodedTerm::BigBigLangStringLiteral { @@ -750,10 +743,7 @@ pub fn insert_term Result<(), StorageError>>( if let Some(language) = literal.language() { insert_str(language_id, language) } else { - Err(CorruptionError::new(format!( - "Invalid term encoding {encoded:?} for {term}" - )) - .into()) + Err(CorruptionError::from_encoded_term(encoded, &term).into()) } } EncodedTerm::SmallTypedLiteral { datatype_id, .. } => { @@ -784,10 +774,7 @@ pub fn insert_term Result<(), StorageError>>( | EncodedTerm::DurationLiteral(..) | EncodedTerm::YearMonthDurationLiteral(..) | EncodedTerm::DayTimeDurationLiteral(..) => Ok(()), - _ => Err( - CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}")) - .into(), - ), + _ => Err(CorruptionError::from_encoded_term(encoded, &term).into()), }, TermRef::Triple(triple) => { if let EncodedTerm::Triple(encoded) = encoded { @@ -799,10 +786,7 @@ pub fn insert_term Result<(), StorageError>>( )?; insert_term(triple.object.as_ref(), &encoded.object, insert_str) } else { - Err( - CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}")) - .into(), - ) + Err(CorruptionError::from_encoded_term(encoded, &term).into()) } } } @@ -1035,6 +1019,7 @@ impl Decoder for S { EncodedTerm::DurationLiteral(value) => Ok(Literal::from(*value).into()), EncodedTerm::YearMonthDurationLiteral(value) => Ok(Literal::from(*value).into()), EncodedTerm::DayTimeDurationLiteral(value) => Ok(Literal::from(*value).into()), + EncodedTerm::GeoPoint(value) => Ok(Literal::from(*value).into()), EncodedTerm::Triple(triple) => Ok(self.decode_triple(triple)?.into()), } } diff --git a/lib/oxsdatatypes/src/geopoint.rs b/lib/oxsdatatypes/src/geopoint.rs index 83d05ed1..16a5b51c 100644 --- a/lib/oxsdatatypes/src/geopoint.rs +++ b/lib/oxsdatatypes/src/geopoint.rs @@ -2,7 +2,7 @@ use std::fmt; use std::fmt::Formatter; use std::str::FromStr; use thiserror::Error; -use wkt::types::Point; +use wkt::types::{Coord, Point}; use wkt::{Geometry, Wkt}; // use std::time::Geo as StdDuration; @@ -10,8 +10,11 @@ use wkt::{Geometry, Wkt}; /// [XML Schema `duration` datatype](https://www.w3.org/TR/xmlschema11-2/#duration) /// /// It stores the duration using a pair of a [`YearMonthDuration`] and a [`DayTimeDuration`]. -#[derive(Debug, Clone)] -pub struct GeoPoint(Point); +#[derive(Debug, Clone, Copy, Default, PartialEq)] +pub struct GeoPoint { + pub x: f32, + pub y: f32, +} #[derive(Error, Debug)] pub enum GeoPointError { @@ -26,6 +29,14 @@ impl GeoPoint { pub fn new() -> Result { Self::from_str("POINT(0 0)") } + + #[inline] + pub fn from_be_bytes(bytes: [u8; 8]) -> Self { + Self { + x: f32::from_be_bytes(bytes[0..4].try_into().unwrap()), + y: f32::from_be_bytes(bytes[4..8].try_into().unwrap()), + } + } } impl FromStr for GeoPoint { @@ -33,16 +44,22 @@ impl FromStr for GeoPoint { fn from_str(input: &str) -> Result { let geo = Wkt::from_str(input).map_err(GeoPointError::WktParsingError)?; - let Geometry::Point(point) = geo.item else { + let Geometry::Point(Point(Some(Coord { + x, + y, + z: None, + m: None, + }))) = geo.item + else { return Err(GeoPointError::UnsupportedWktType(geo.item.to_string())); }; - Ok(Self(point)) + Ok(Self { x, y }) } } impl fmt::Display for GeoPoint { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + write!(f, "POINT({} {})", self.x, self.y) } } #[cfg(test)]