/* * This file is part of Datafu * Copyright (C) 2021 Soni L. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use std::borrow::Borrow; use std::borrow::Cow; use std::collections::BTreeMap; use datafu::RefOwn; use datafu::PatternTypes; use datafu::KVPair; #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Value { U(usize), B(bool), M(BTreeMap), S(Cow<'static, str>), } #[derive(Copy, Clone, Eq, PartialEq)] pub enum Dummy { } trait ValueHelper { fn as_value(&self) -> Result<&Value, &str>; } impl ValueHelper for Value { fn as_value(&self) -> Result<&Value, &str> { Ok(self) } } impl ValueHelper for &str { fn as_value(&self) -> Result<&Value, &str> { Err(self) } } impl PartialEq for Value { fn eq(&self, other: &str) -> bool { matches!(self, Value::S(l) if l == other) } } impl PartialEq for str { fn eq(&self, other: &Value) -> bool { matches!(other, Value::S(r) if self == r) } } impl PartialEq for Value { fn eq(&self, other: &Dummy) -> bool { unreachable!() } } impl PartialEq for Dummy { fn eq(&self, other: &Value) -> bool { unreachable!() } } impl PartialEq for Dummy { fn eq(&self, other: &str) -> bool { unreachable!() } } impl PartialEq for str { fn eq(&self, other: &Dummy) -> bool { unreachable!() } } impl<'a> PartialEq for dyn ValueHelper + 'a { fn eq(&self, other: &(dyn ValueHelper + 'a)) -> bool { match (self.as_value(), other.as_value()) { (a, b) if a == b => true, (Ok(Value::S(a)), Err(b)) | (Err(b), Ok(Value::S(a))) => { a.eq(b) }, _ => false, } } } impl<'a> PartialOrd for dyn ValueHelper + 'a { fn partial_cmp(&self, other: &(dyn ValueHelper + 'a)) -> Option { Some(self.cmp(other)) } } impl<'a> Eq for dyn ValueHelper + 'a { } impl<'a> Ord for dyn ValueHelper + 'a { fn cmp(&self, other: &(dyn ValueHelper + 'a)) -> std::cmp::Ordering { match (self.as_value(), other.as_value()) { (Ok(a), Ok(b)) => a.cmp(b), (Err(a), Err(b)) => a.cmp(b), (Ok(Value::S(a)), Err(b)) => (**a).cmp(b), (Err(a), Ok(Value::S(b))) => a.cmp(b.borrow()), (Ok(_), Err(_)) => std::cmp::Ordering::Less, (Err(_), Ok(_)) => std::cmp::Ordering::Greater, } } } impl From<&'static str> for Value { fn from(x: &'static str) -> Value { Value::S(x.into()) } } impl<'a> Borrow for Value { fn borrow(&self) -> &(dyn ValueHelper + 'a) { self } } impl PatternTypes for Value { type Ref = Self; type Own = Dummy; fn pairs<'b>( item: RefOwn<'b, Self, Dummy> ) -> Option> + 'b>> { match item { RefOwn::Ref(Value::M(map)) => { Some(Box::new(map.iter().map(|(a, b)| (a.into(), b.into())))) }, _ => None } } fn get<'a, 'b>( item: RefOwn<'b, Self, Dummy>, key: RefOwn<'a, Self, Dummy> ) -> Option>> { match item { RefOwn::Ref(Value::M(map)) => { Some(match key { RefOwn::Ref(key) => map.get_key_value(key), RefOwn::Own(key) => unreachable!(),//map.get_key_value(&Value::U(key)), RefOwn::Str(key) => map.get_key_value(&key as &dyn ValueHelper), }.map(|(k,v)| (k.into(), v.into()))) }, _ => None } } fn matches( left: RefOwn<'_, Self, Dummy>, right: RefOwn<'_, Self, Dummy> ) -> bool { left == right } }