diff --git a/contracts/okp4-cognitarium/src/state/de.rs b/contracts/okp4-cognitarium/src/state/de.rs new file mode 100644 index 00000000..e6e5ae32 --- /dev/null +++ b/contracts/okp4-cognitarium/src/state/de.rs @@ -0,0 +1,182 @@ +use crate::state::triples::{Literal, Node, Object, Subject}; +use cosmwasm_std::{StdError, StdResult}; +use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey}; + +fn parse_length(value: &[u8]) -> StdResult { + Ok(u16::from_be_bytes( + value + .try_into() + .map_err(|_| StdError::generic_err("Could not read 2 byte length"))?, + ) + .into()) +} + +impl<'a> PrimaryKey<'a> for Subject { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + match self { + Subject::Named(node) => node.key(), + Subject::Blank(node) => vec![Key::Ref(&[]), Key::Ref(node.as_bytes())], + } + } +} + +impl<'a> Prefixer<'a> for Subject { + fn prefix(&self) -> Vec { + self.key() + } +} + +impl KeyDeserialize for Subject { + type Output = Subject; + + fn from_vec(value: Vec) -> StdResult { + let named = Node::from_vec(value)?; + if named.namespace.is_empty() { + return Ok(Subject::Blank(named.value)); + } + Ok(Subject::Named(named)) + } +} + +impl<'a> PrimaryKey<'a> for Object { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + match self { + Object::Named(node) => { + let mut key: Vec = Vec::with_capacity(3); + key.push(Key::Val8([b'n'])); + for k in node.key() { + key.push(k); + } + key + } + Object::Blank(node) => { + let mut key: Vec = Vec::with_capacity(2); + key.push(Key::Val8([b'b'])); + key.push(Key::Ref(node.as_bytes())); + key + } + Object::Literal(literal) => { + let encoded = literal.key(); + let mut key: Vec = Vec::with_capacity(encoded.len() + 1); + key.push(Key::Val8([b'l'])); + for k in encoded { + key.push(k); + } + key + } + } + } +} + +impl KeyDeserialize for Object { + type Output = Object; + + fn from_vec(mut value: Vec) -> StdResult { + let bytes = value.split_off(3); + match bytes[2] { + b'n' => Node::from_vec(value).map(|n| Object::Named(n)), + b'b' => Ok(Object::Blank(String::from_vec(value)?)), + b'l' => Literal::from_vec(value).map(|l| Object::Literal(l)), + _ => Err(StdError::generic_err("Could not deserialize Object")), + } + } +} + +impl<'a> PrimaryKey<'a> for Node { + type Prefix = (); + type SubPrefix = (); + type Suffix = Self; + type SuperSuffix = Self; + + fn key(&self) -> Vec { + vec![ + Key::Ref(self.namespace.as_bytes()), + Key::Ref(self.value.as_bytes()), + ] + } +} + +impl<'a> Prefixer<'a> for Node { + fn prefix(&self) -> Vec { + self.key() + } +} + +impl KeyDeserialize for Node { + type Output = Node; + + fn from_vec(mut value: Vec) -> StdResult { + let mut val = value.split_off(2); + let n_len = parse_length(&value)?; + let ns = val.split_off(n_len); + + Ok(Node { + namespace: String::from_vec(ns)?, + value: String::from_vec(val)?, + }) + } +} + +impl Literal { + fn key(&self) -> Vec { + match self { + Literal::Simple { value } => { + vec![Key::Ref(value.as_bytes()), Key::Ref(&[]), Key::Ref(&[])] + } + Literal::I18NString { value, language } => { + vec![ + Key::Ref(value.as_bytes()), + Key::Ref(language.as_bytes()), + Key::Ref(&[]), + ] + } + Literal::Typed { value, datatype } => { + let mut key: Vec = Vec::with_capacity(3); + key.push(Key::Ref(value.as_bytes())); + for k in datatype.key() { + key.push(k); + } + key + } + } + } + + fn from_vec(mut value: Vec) -> StdResult { + let mut part1 = value.split_off(2); + let p1_len = parse_length(&value)?; + let mut part2_len = part1.split_off(p1_len); + + let mut part2 = part2_len.split_off(2); + let p2_len = parse_length(&part2_len)?; + let part3 = part2.split_off(p2_len); + + if part3.is_empty() { + if part2.is_empty() { + return Ok(Literal::Simple { + value: String::from_vec(part1)?, + }); + } + return Ok(Literal::I18NString { + value: String::from_vec(part1)?, + language: String::from_vec(part2)?, + }); + } + Ok(Literal::Typed { + value: String::from_vec(part1)?, + datatype: Node { + value: String::from_vec(part2)?, + namespace: String::from_vec(part3)?, + }, + }) + } +} diff --git a/contracts/okp4-cognitarium/src/state/mod.rs b/contracts/okp4-cognitarium/src/state/mod.rs index 779733ec..89fdb3c4 100644 --- a/contracts/okp4-cognitarium/src/state/mod.rs +++ b/contracts/okp4-cognitarium/src/state/mod.rs @@ -1,3 +1,4 @@ +mod de; mod store; mod triples;