use crate::value::Value;
use crate::value::error::Error;
use crate::value::key::Key;
use crate::value::keys::Keys;
use crate::value::map::Map;
use crate::value::parse;
use crate::value::span::Span;
use crate::value::tracer::Tracer;
use core::cmp::Ordering;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
Get(Get),
Set(Set),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Get {
value: Value,
source: String,
span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Set {
value: Value,
}
impl Ord for Operation {
fn cmp(&self, other: &Self) -> Ordering {
let a = self.as_ref();
let b = other.as_ref();
let a_order = operation_meta_order(self);
let b_order = operation_meta_order(other);
let a_label = operation_meta_label(self);
let b_label = operation_meta_label(other);
let cmp_source = || match a.tracer().source.cmp(&b.tracer().source) {
Ordering::Equal => self.tracer().span.cmp(&b.tracer().span),
o => o,
};
let cmp_keys = || match a.tracer().keys.cmp(&b.tracer().keys) {
Ordering::Equal => cmp_source(),
o => o,
};
let cmp_label = || match a_label.cmp(&b_label) {
Ordering::Equal => cmp_keys(),
o => o,
};
let cmp_order = |a: isize, b: isize| match a.cmp(&b) {
Ordering::Equal => cmp_label(),
o => o,
};
match (a_order, b_order) {
(a, 0) if a > 0 => Ordering::Less,
(a, 0) if a < 0 => Ordering::Greater,
(0, b) if b > 0 => Ordering::Greater,
(0, b) if b < 0 => Ordering::Less,
(a, b) if a > 0 && b < 0 => Ordering::Less,
(a, b) if a < 0 && b > 0 => Ordering::Greater,
(a, b) => cmp_order(a, b),
}
}
}
impl PartialOrd for Operation {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
fn operation_meta_label(op: &Operation) -> Option<&[u8]> {
op.as_ref()
.meta()
.get(b"internal-label")
.filter(|s| !s.is_empty())
}
fn operation_meta_order(op: &Operation) -> isize {
op.as_ref()
.meta()
.get(b"internal-order")
.filter(|s| !s.is_empty())
.and_then(|s| str::from_utf8(s).ok())
.and_then(|s| s.parse::<isize>().ok())
.unwrap_or(0)
}
impl From<Operation> for Value {
fn from(op: Operation) -> Self {
match op {
Operation::Get(v) => v.value,
Operation::Set(v) => v.value,
}
}
}
impl AsRef<Value> for Operation {
fn as_ref(&self) -> &Value {
match self {
Operation::Get(v) => &v.value,
Operation::Set(v) => &v.value,
}
}
}
impl AsMut<Value> for Operation {
fn as_mut(&mut self) -> &mut Value {
match self {
Operation::Get(v) => &mut v.value,
Operation::Set(v) => &mut v.value,
}
}
}
impl FromIterator<Operation> for Vec<Value> {
fn from_iter<T: IntoIterator<Item = Operation>>(iter: T) -> Self {
iter.into_iter().map(Value::from).collect()
}
}
impl Operation {
pub fn with_value(mut self, value: Value) -> Self {
match &mut self {
Operation::Get(o) => o.value = value,
Operation::Set(o) => o.value = value,
}
self
}
pub fn tracer(&self) -> &Tracer {
self.as_ref().tracer()
}
pub fn map(self) -> Map {
let value = Value::from(self);
let tracer = value.tracer().clone();
Map::default()
.with("value", value)
.with("operation", tracer)
}
pub fn compare(&self, value: &Value, source: Option<&str>, span: Option<Span>) -> bool {
match self {
Operation::Set(o) => o.value.tracer() == value.tracer(),
Operation::Get(o) => {
o.value.tracer() == value.tracer()
&& source.is_none_or(|s| s == o.source)
&& span.is_none_or(|s| s == o.span)
}
}
}
pub fn get(value: Value, source: String, span: Span) -> Result<Self, Error> {
if value.tracer().source.is_none() {
return Err(Error::Operation(format!("no getter source: {value:?}")));
}
if value.tracer().keys.is_none() {
return Err(Error::Operation(format!("no getter keys: {value:?}")));
}
Ok(Operation::Get(Get {
value,
source,
span,
}))
}
pub fn set(value: Value) -> Result<Self, Error> {
if value.tracer().source.is_none() {
return Err(Error::Operation(format!("no setter source: {value:?}")));
}
if value.tracer().span.is_none() {
return Err(Error::Operation(format!("no setter span: {value:?}")));
}
if value.tracer().keys.is_none() {
return Err(Error::Operation(format!("no setter keys: {value:?}")));
}
Ok(Operation::Set(Set { value }))
}
}
pub fn iter_getters(ops: &[Operation]) -> impl Iterator<Item = &Value> {
ops.iter()
.filter(|o| matches!(o, Operation::Get(_)))
.map(AsRef::as_ref)
}
pub fn iter_setters(ops: &[Operation]) -> impl Iterator<Item = &Value> {
ops.iter()
.filter(|o| matches!(o, Operation::Set(_)))
.map(AsRef::as_ref)
}
pub fn get_value<'a>(mut value: &'a Value, mut keys: &[Key]) -> Option<&'a Value> {
loop {
if keys.is_empty() {
return Some(value);
}
let Some(([head], tail)) = keys.split_at_checked(1) else {
return None;
};
value = match value {
Value::Bytes(_) => None,
Value::Map(v) => v.get(head),
Value::List(v) => v.get(parse::usize(head.as_ref()).ok()?),
}?;
if tail.is_empty() {
return Some(value);
}
keys = tail;
}
}
pub fn get_map_value<T: AsRef<[Key]>>(map: &Map, keys: T) -> Option<Value> {
let keys = keys.as_ref();
let Some(([head], tail)) = keys.split_at_checked(1) else {
return map.get(Key::default()).cloned();
};
if tail.is_empty() {
return match head.as_ref() {
b"..." => Some(map.clone().into()),
b"." => map.get([]).cloned(),
_ => map.get(head).cloned(),
};
}
get_value(map.get(head)?, tail).cloned()
}
pub fn insert_map_value(map: &mut Map, keys: &Keys, mut value: Value) {
let mut keys = keys.as_slice();
loop {
let Some((last, rest)) = keys.split_last() else {
map.insert(Key::default(), value);
return;
};
let last = last.as_ref();
if last.starts_with(b".") {
return;
}
if rest.is_empty() {
map.insert(last.to_vec(), value);
return;
}
if let Ok(index) = parse::usize(last) {
if let Some(Value::List(mut list)) = get_map_value(map, rest) {
if list.get(index).is_some() {
list.set(index, value);
value = list.into();
keys = rest;
continue;
}
}
}
value = Value::Map(Map::from((last.to_vec(), value)));
keys = rest;
}
}
pub fn fold_map_value(map: &mut Map, keys: &Keys, mut value: Value) {
let mut keys = keys.as_slice();
loop {
let Some((last, rest)) = keys.split_last() else {
return map.fold_key(Key::default(), value);
};
let last = last.as_ref();
if last.starts_with(b".") {
return;
}
if rest.is_empty() {
return map.fold_key(last.to_vec(), value);
}
if let Ok(index) = parse::usize(last) {
if let Some(Value::List(mut list)) = get_map_value(map, rest) {
if list.get(index).is_some() {
list.set(index, value);
value = list.into();
keys = rest;
continue;
}
}
}
value = Value::Map(Map::from((last.to_vec(), value)));
keys = rest;
}
}
#[cfg(test)]
mod test {
use crate::value::Value;
use crate::value::equivalent::Equivalent;
use crate::value::keys::Keys;
use crate::value::list::List;
use crate::value::map::Map;
use crate::value::operation::fold_map_value;
use crate::value::operation::get_map_value;
use crate::value::operation::insert_map_value;
#[test]
fn test_get_empty_key() {
let map = Map::default().with("", "a");
let keys = Keys::from(String::from(""));
let res = get_map_value(&map, &keys);
assert!(res.unwrap().equivalent(&"a".into()));
}
#[test]
fn test_get_default_key() {
let map = Map::default().with("", "a");
let keys = Keys::default();
let res = get_map_value(&map, &keys);
assert!(res.unwrap().equivalent(&"a".into()));
}
#[test]
fn test_insert_empty_key() {
let mut map = Map::default();
let keys = Keys::from(String::from(""));
insert_map_value(&mut map, &keys, Value::from("x"));
assert_eq!(map.get(b""), Some(&"x".into()));
}
#[test]
fn test_insert_default_key() {
let mut map = Map::default();
let keys = Keys::default();
insert_map_value(&mut map, &keys, Value::from("x"));
assert_eq!(map.get(b""), Some(&"x".into()));
}
#[test]
fn test_insert_bad_key() {
let mut map = Map::default();
insert_map_value(&mut map, &Keys::from("."), Value::from("x"));
insert_map_value(&mut map, &Keys::from(".."), Value::from("x"));
insert_map_value(&mut map, &Keys::from("..."), Value::from("x"));
insert_map_value(&mut map, &Keys::from("...."), Value::from("x"));
insert_map_value(&mut map, &Keys::from(".a"), Value::from("x"));
assert!(map.is_empty(), "{map:?}");
}
#[test]
fn test_insert_list_key() {
let mut map = Map::default().with("x", List::default().with("a"));
let kx = Keys::parse(b"x");
let kx0 = Keys::parse(b"x.0");
let la = Value::from(List::default().with("a"));
let lb = Value::from(List::default().with("b"));
assert_eq!(get_map_value(&map, &kx).unwrap(), la);
insert_map_value(&mut map, &kx0, "b".into());
assert_eq!(get_map_value(&map, &kx).unwrap(), lb);
}
#[test]
fn test_fold_empty_key() {
let mut map = Map::default();
let keys = Keys::from(String::from(""));
fold_map_value(&mut map, &keys, Value::from("x"));
assert_eq!(map.get(b""), Some(&"x".into()));
}
#[test]
fn test_fold_default_key() {
let mut map = Map::default();
let keys = Keys::default();
fold_map_value(&mut map, &keys, Value::from("x"));
assert_eq!(map.get(b""), Some(&"x".into()));
}
#[test]
fn test_fold_bad_key() {
let mut map = Map::default();
fold_map_value(&mut map, &Keys::from("."), Value::from("x"));
fold_map_value(&mut map, &Keys::from(".."), Value::from("x"));
fold_map_value(&mut map, &Keys::from("..."), Value::from("x"));
fold_map_value(&mut map, &Keys::from("...."), Value::from("x"));
fold_map_value(&mut map, &Keys::from(".a"), Value::from("x"));
assert!(map.is_empty(), "{map:?}");
}
#[test]
fn test_fold_list_key() {
let mut map = Map::default().with("x", List::default().with("a"));
let kx = Keys::parse(b"x");
let kx0 = Keys::parse(b"x.0");
let la = Value::from(List::default().with("a"));
let lb = Value::from(List::default().with("b"));
assert_eq!(get_map_value(&map, &kx).unwrap(), la);
fold_map_value(&mut map, &kx0, "b".into());
assert_eq!(get_map_value(&map, &kx).unwrap(), lb);
}
}