use std::{cmp::Ordering, collections::BTreeMap, ops::{Add, Div, Mul, Neg, Rem, Sub}};
use jaq_all::jaq_core::{Error, ops};
use crate::{RpcValue, Value};
pub type ValR = jaq_all::jaq_core::ValR<RpcValue>;
pub type ValX = jaq_all::jaq_core::ValX<RpcValue>;
impl Neg for RpcValue {
type Output = ValR;
fn neg(self) -> Self::Output {
match &self.value {
Value::Int(num) => Ok((-num).into()),
_ => Err(jaq_all::jaq_core::Error::typ(self, "")),
}
}
}
impl Add for RpcValue {
type Output = ValR;
fn add(self, rhs: Self) -> Self::Output {
match (&self.value, &rhs.value) {
(Value::Int(x), Value::Int(y)) => Ok((x + y).into()),
(Value::UInt(x), Value::UInt(y)) => Ok((x + y).into()),
_=> Err(Error::math(self, ops::Math::Add, rhs))
}
}
}
impl Sub for RpcValue {
type Output = ValR;
fn sub(self, rhs: Self) -> Self::Output {
match (&self.value, &rhs.value) {
(Value::Int(x), Value::Int(y)) => Ok((x - y).into()),
(Value::UInt(x), Value::UInt(y)) => Ok((x - y).into()),
_=> Err(Error::math(self, ops::Math::Sub, rhs))
}
}
}
impl Mul for RpcValue {
type Output = ValR;
fn mul(self, rhs: Self) -> Self::Output {
match (&self.value, &rhs.value) {
(Value::Int(x), Value::Int(y)) => Ok((x * y).into()),
_=> Err(Error::math(self, ops::Math::Mul, rhs))
}
}
}
impl Div for RpcValue {
type Output = ValR;
fn div(self, rhs: Self) -> Self::Output {
match (&self.value, &rhs.value) {
(Value::Int(x), Value::Int(y)) => Ok((x / y).into()),
_=> Err(Error::math(self, ops::Math::Div, rhs))
}
}
}
impl Rem for RpcValue {
type Output = ValR;
fn rem(self, rhs: Self) -> Self::Output {
match (&self.value, &rhs.value) {
(Value::Int(x), Value::Int(y)) => Ok((x % y).into()),
_=> Err(Error::math(self, ops::Math::Rem, rhs))
}
}
}
impl PartialOrd for RpcValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for RpcValue {}
impl Ord for RpcValue {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
use Ordering::{Equal, Greater, Less};
match (&self.value, &other.value) {
(Value::Bool(x), Value::Bool(y)) => x.cmp(y),
(Value::Int(x), Value::Int(y)) => x.cmp(y),
(Value::UInt(x), Value::UInt(y)) => x.cmp(y),
(Value::DateTime(x), Value::DateTime(y)) => x.cmp(y),
(Value::Decimal(x), Value::Decimal(y)) => x.cmp(y),
(Value::String(x), Value::String(y)) => x.cmp(y),
(Value::Blob(x), Value::Blob(y)) => x.cmp(y),
(Value::List(x), Value::List(y)) => x.cmp(y),
(Value::Map(x), Value::Map(y)) => x.cmp(y),
(Value::IMap(x), Value::IMap(y)) => x.cmp(y),
(Value::Null, Value::Null) => Equal,
(Value::Null, _) => Less,
(_, Value::Null) => Greater,
(Value::Bool(_), _) => Less,
(_, Value::Bool(_)) => Greater,
(Value::Int(_), _) => Less,
(_, Value::Int(_)) => Greater,
(Value::UInt(_), _) => Less,
(_, Value::UInt(_)) => Greater,
(Value::Double(_), _) => Less,
(_, Value::Double(_)) => Greater,
(Value::Decimal(_), _) => Less,
(_, Value::Decimal(_)) => Greater,
(Value::DateTime(_), _) => Less,
(_, Value::DateTime(_)) => Greater,
(Value::String(_), _) => Less,
(_, Value::String(_)) => Greater,
(Value::Blob(_), _) => Less,
(_, Value::Blob(_)) => Greater,
(Value::List(_), _) => Less,
(_, Value::List(_)) => Greater,
(Value::IMap(_), _) => Less,
(_, Value::IMap(_)) => Greater,
}
}
}
impl FromIterator<RpcValue> for RpcValue {
fn from_iter<T: IntoIterator<Item = RpcValue>>(iter: T) -> Self {
iter.into_iter().collect::<Vec<_>>().into()
}
}
impl From<core::ops::Range<Option<RpcValue>>> for RpcValue {
fn from(value: core::ops::Range<Option<RpcValue>>) -> Self {
let kv = |(k, v): (&str, Option<_>)| v.map(|v| (k.to_owned(), v));
let kvs = [("start", value.start), ("end", value.end)];
kvs.into_iter().filter_map(kv).collect::<BTreeMap<String,_>>().into()
}
}
impl From<usize> for RpcValue {
fn from(value: usize) -> Self {
(value as u64).into()
}
}
impl jaq_all::jaq_std::ValT for RpcValue {
fn into_seq<S: FromIterator<Self>>(self) -> Result<S, Self> {
match self.value {
Value::List(list) => Ok(list.into_iter().collect()),
_ => Err(self)
}
}
fn is_int(&self) -> bool {
self.is_int()
}
fn as_isize(&self) -> Option<isize> {
match self.value {
#[expect(clippy::cast_possible_truncation, reason = "We assume pointer size is 64-bit")]
Value::Int(num) => Some(num as isize),
_ => None,
}
}
fn as_f64(&self) -> Option<f64> {
todo!("{}", fn_name::uninstantiated!());
}
fn is_utf8_str(&self) -> bool {
todo!("{}", fn_name::uninstantiated!());
}
fn as_bytes(&self) -> Option<&[u8]> {
todo!("{}", fn_name::uninstantiated!());
}
fn as_sub_str(&self, _sub: &[u8]) -> Self {
todo!("{}", fn_name::uninstantiated!());
}
fn from_utf8_bytes(_b: impl AsRef<[u8]> + Send + 'static) -> Self {
todo!("{}", fn_name::uninstantiated!());
}
}
impl jaq_all::jaq_core::ValT for RpcValue {
fn from_num(n: &str) -> ValR {
Ok(n.parse::<i64>().map_or_else(|_| 0_i64.into(), RpcValue::from))
}
fn from_map<I: IntoIterator<Item = (Self, Self)>>(iter: I) -> ValR {
Ok(iter.into_iter().map(|(k, v)| (k.as_str().to_owned(), v)).collect::<BTreeMap<String, _>>().into())
}
fn key_values(self) -> jaq_all::jaq_core::box_iter::BoxIter<'static, jaq_all::jaq_core::ValR<(Self, Self), Self>> {
match self.value {
Value::List(list) => {
Box::new(list
.into_iter()
.enumerate()
.map(|(idx, val)| Ok((RpcValue::from(idx.cast_signed()), val))))
}
Value::Map(map) => {
Box::new(map
.into_iter()
.map(|(key, val)| Ok((RpcValue::from(key), val))))
}
Value::IMap(map) => {
Box::new(map
.into_iter()
.map(|(key, val)| Ok((RpcValue::from(key), val))))
}
_ => Box::new(Err(Error::typ(self, "iterable (List or Map or IMap)")).into_iter())
}
}
fn values(self) -> Box<dyn Iterator<Item = ValR>> {
match self.value {
Value::List(list) => {
Box::new(list
.into_iter()
.map(Ok))
}
Value::Map(map) => {
Box::new(map
.into_values()
.map(Ok))
}
Value::IMap(map) => {
Box::new(map
.into_values()
.map(Ok))
}
_ => Box::new(Err(Error::typ(self, "iterable (List or Map or IMap)")).into_iter())
}
}
fn index(self, index: &Self) -> ValR {
match (&self.value, &index.value) {
(Value::Null, _) => Ok(RpcValue::null()),
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss, reason = "We assume pointer size is 64-bit")]
(Value::String(rv), Value::Int(i)) => Ok(rv.chars().nth(*i as usize).map(|cha| cha.to_string()).into()),
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss, reason = "We assume pointer size is 64-bit")]
(Value::List(list), Value::Int(i)) => Ok((*list).get(*i as usize).cloned().unwrap_or_else(RpcValue::null)),
(Value::Map(o), Value::String(key)) => Ok(o.get(key.as_str()).cloned().unwrap_or_else(RpcValue::null)),
(_s, _) => Err(Error::typ(self, "")),
}
}
fn range(self, _range: jaq_all::jaq_core::val::Range<&Self>) -> ValR {
todo!("{}", fn_name::uninstantiated!());
}
fn map_values<I: Iterator<Item = ValX>>(
self,
_opt: jaq_all::jaq_core::path::Opt,
_f: impl Fn(Self) -> I,
) -> ValX {
todo!("{}", fn_name::uninstantiated!());
}
fn map_index<I: Iterator<Item = ValX>>(
self,
_index: &Self,
_opt: jaq_all::jaq_core::path::Opt,
_f: impl Fn(Self) -> I,
) -> ValX {
todo!("{}", fn_name::uninstantiated!());
}
fn map_range<I: Iterator<Item = ValX>>(
self,
_range: jaq_all::jaq_core::val::Range<&Self>,
_opt: jaq_all::jaq_core::path::Opt,
_f: impl Fn(Self) -> I,
) -> ValX {
todo!("{}", fn_name::uninstantiated!());
}
fn as_bool(&self) -> bool {
self.as_bool()
}
fn into_string(self) -> Self {
self.to_cpon().into()
}
}