use crate::rust::vec;
use crate::rust::vec::Vec;
use crate::value::Value;
use crate::CustomValueKind;
use crate::*;
#[derive(Eq, PartialEq, Clone)]
pub struct SborPathBuf(Vec<usize>);
impl SborPathBuf {
pub fn new() -> Self {
SborPathBuf(vec![])
}
pub fn push(&mut self, path: usize) {
self.0.push(path);
}
pub fn pop(&mut self) {
self.0.pop();
}
}
impl From<SborPath> for SborPathBuf {
fn from(path: SborPath) -> Self {
Self(path.0)
}
}
impl From<SborPathBuf> for SborPath {
fn from(mutable: SborPathBuf) -> Self {
SborPath::new(mutable.0)
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct SborPath(Vec<usize>);
impl SborPath {
pub fn new(path: Vec<usize>) -> Self {
SborPath(path)
}
pub fn get_from_value<'a, X: CustomValueKind, Y: CustomValue<X>>(
&'a self,
value: &'a Value<X, Y>,
) -> Option<&'a Value<X, Y>> {
let rel_path = ValueRetriever(&self.0);
rel_path.get_from(value)
}
pub fn get_from_value_mut<'a, X: CustomValueKind, Y: CustomValue<X>>(
&'a self,
value: &'a mut Value<X, Y>,
) -> Option<&'a mut Value<X, Y>> {
let rel_path = ValueRetriever(&self.0);
rel_path.get_from_mut(value)
}
}
struct ValueRetriever<'a>(&'a [usize]);
impl<'a> ValueRetriever<'a> {
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn advance(&self) -> Option<(usize, Self)> {
if self.is_empty() {
return None;
}
let (index_slice, extended_path) = self.0.split_at(1);
let index = index_slice[0];
Some((index, ValueRetriever(extended_path)))
}
fn get_from<X: CustomValueKind, Y: CustomValue<X>>(
self,
value: &'a Value<X, Y>,
) -> Option<&'a Value<X, Y>> {
if self.is_empty() {
return Option::Some(value);
}
match value {
Value::Tuple { fields: v, .. }
| Value::Enum { fields: v, .. }
| Value::Array { elements: v, .. } => {
let (index, next_path) = self.advance().expect("Should be available");
v.get(index).and_then(|value| next_path.get_from(value))
}
Value::Map { entries, .. } => {
let (index, next_path) = self.advance().expect("Should be available");
entries.get(index).and_then(|value| {
if let Some((index, next_path)) = next_path.advance() {
match index {
0 => next_path.get_from(&value.0),
1 => next_path.get_from(&value.1),
_ => None,
}
} else {
None
}
})
}
_ => Option::None,
}
}
fn get_from_mut<X: CustomValueKind, Y: CustomValue<X>>(
self,
value: &'a mut Value<X, Y>,
) -> Option<&'a mut Value<X, Y>> {
if self.is_empty() {
return Option::Some(value);
}
match value {
Value::Tuple { fields: v, .. }
| Value::Enum { fields: v, .. }
| Value::Array { elements: v, .. } => {
let (index, next_path) = self.advance().expect("Should be available");
v.get_mut(index)
.and_then(|value| next_path.get_from_mut(value))
}
Value::Map { entries, .. } => {
let (index, next_path) = self.advance().expect("Should be available");
entries.get_mut(index).and_then(|value| {
if let Some((index, next_path)) = next_path.advance() {
match index {
0 => next_path.get_from_mut(&mut value.0),
1 => next_path.get_from_mut(&mut value.1),
_ => None,
}
} else {
None
}
})
}
_ => Option::None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn query_array() {
let value = BasicValue::Array {
element_value_kind: BasicValueKind::Array,
elements: vec![BasicValue::Array {
element_value_kind: BasicValueKind::U8,
elements: vec![BasicValue::U8 { value: 5 }],
}],
};
assert_eq!(
SborPath(vec![0]).get_from_value(&value),
Some(&BasicValue::Array {
element_value_kind: BasicValueKind::U8,
elements: vec![BasicValue::U8 { value: 5 }],
})
);
assert_eq!(
SborPath(vec![0, 0]).get_from_value(&value),
Some(&BasicValue::U8 { value: 5 })
);
assert_eq!(SborPath(vec![0, 0, 0]).get_from_value(&value), None);
assert_eq!(SborPath(vec![1]).get_from_value(&value), None);
assert_eq!(SborPath(vec![0, 1]).get_from_value(&value), None);
assert_eq!(SborPath(vec![0, 0, 1]).get_from_value(&value), None);
}
#[test]
fn query_map() {
let value = BasicValue::Map {
key_value_kind: BasicValueKind::U8,
value_value_kind: BasicValueKind::Array,
entries: vec![(
BasicValue::U8 { value: 3 },
BasicValue::Array {
element_value_kind: BasicValueKind::U8,
elements: vec![BasicValue::U8 { value: 5 }],
},
)],
};
assert_eq!(
SborPath(vec![0, 0]).get_from_value(&value),
Some(&BasicValue::U8 { value: 3 })
);
assert_eq!(
SborPath(vec![0, 1]).get_from_value(&value),
Some(&BasicValue::Array {
element_value_kind: BasicValueKind::U8,
elements: vec![BasicValue::U8 { value: 5 }],
})
);
assert_eq!(
SborPath(vec![0, 1, 0]).get_from_value(&value),
Some(&BasicValue::U8 { value: 5 })
);
assert_eq!(SborPath(vec![0]).get_from_value(&value), None);
assert_eq!(SborPath(vec![0, 2]).get_from_value(&value), None);
assert_eq!(SborPath(vec![0, 0, 0]).get_from_value(&value), None);
}
}