/*
* 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 <https://www.gnu.org/licenses/>.
*/
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, Debug)]
pub enum Value {
U(usize),
B(bool),
M(BTreeMap<Value, Value>),
S(Cow<'static, str>),
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
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<str> for Value {
fn eq(&self, other: &str) -> bool {
matches!(self, Value::S(l) if l == other)
}
}
impl PartialEq<Value> for str {
fn eq(&self, other: &Value) -> bool {
matches!(other, Value::S(r) if self == r)
}
}
impl PartialEq<Dummy> for Value {
fn eq(&self, other: &Dummy) -> bool {
let _ = other;
unreachable!()
}
}
impl PartialEq<Value> for Dummy {
fn eq(&self, other: &Value) -> bool {
let _ = other;
unreachable!()
}
}
impl PartialEq<str> for Dummy {
fn eq(&self, other: &str) -> bool {
let _ = other;
unreachable!()
}
}
impl PartialEq<Dummy> for str {
fn eq(&self, other: &Dummy) -> bool {
let _ = other;
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<std::cmp::Ordering> {
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<dyn ValueHelper + 'a> 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<Box<dyn Iterator<Item=KVPair<'b, Self>> + '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<Option<KVPair<'b, Self>>> {
match item {
RefOwn::Ref(Value::M(map)) => {
Some(match key {
RefOwn::Ref(key) => map.get_key_value(key),
RefOwn::Own(_key) => unreachable!(),
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
}
fn as_str<'b>(
item: RefOwn<'b, Self, Dummy>
) -> Option<&'b str> {
match item {
RefOwn::Str(key) => Some(key),
RefOwn::Ref(Value::S(key)) => Some(key),
_ => None,
}
}
}