use std::collections::BTreeMap;
use std::fmt;
use serde::de::{DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
#[derive(Debug, Clone, PartialEq, Default)]
pub enum WhiskerValue {
#[default]
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Bytes(Vec<u8>),
Array(Vec<WhiskerValue>),
Map(BTreeMap<String, WhiskerValue>),
Error(String),
}
impl WhiskerValue {
pub fn map<I, K>(entries: I) -> Self
where
I: IntoIterator<Item = (K, WhiskerValue)>,
K: Into<String>,
{
let mut m = BTreeMap::new();
for (k, v) in entries {
m.insert(k.into(), v);
}
WhiskerValue::Map(m)
}
pub fn args<I>(items: I) -> Self
where
I: IntoIterator<Item = WhiskerValue>,
{
WhiskerValue::map([("args", WhiskerValue::Array(items.into_iter().collect()))])
}
pub fn as_error(&self) -> Option<&str> {
if let WhiskerValue::Error(msg) = self {
Some(msg.as_str())
} else {
None
}
}
pub fn deserialize_into<T: DeserializeOwned>(&self) -> Result<T, String> {
serde_json::from_value(self.to_json()).map_err(|e| e.to_string())
}
pub fn to_json(&self) -> serde_json::Value {
use serde_json::Value as J;
match self {
WhiskerValue::Null => J::Null,
WhiskerValue::Bool(b) => J::Bool(*b),
WhiskerValue::Int(i) => J::Number((*i).into()),
WhiskerValue::Float(f) => serde_json::Number::from_f64(*f)
.map(J::Number)
.unwrap_or(J::Null),
WhiskerValue::String(s) => J::String(s.clone()),
WhiskerValue::Bytes(b) => {
J::Array(b.iter().map(|x| J::Number((*x as u64).into())).collect())
}
WhiskerValue::Array(a) => J::Array(a.iter().map(WhiskerValue::to_json).collect()),
WhiskerValue::Map(m) => {
J::Object(m.iter().map(|(k, v)| (k.clone(), v.to_json())).collect())
}
WhiskerValue::Error(e) => J::String(e.clone()),
}
}
pub fn from_json(v: serde_json::Value) -> WhiskerValue {
use serde_json::Value as J;
match v {
J::Null => WhiskerValue::Null,
J::Bool(b) => WhiskerValue::Bool(b),
J::Number(n) => {
if let Some(i) = n.as_i64() {
WhiskerValue::Int(i)
} else if let Some(f) = n.as_f64() {
WhiskerValue::Float(f)
} else {
WhiskerValue::Null
}
}
J::String(s) => WhiskerValue::String(s),
J::Array(a) => {
WhiskerValue::Array(a.into_iter().map(WhiskerValue::from_json).collect())
}
J::Object(o) => WhiskerValue::Map(
o.into_iter()
.map(|(k, v)| (k, WhiskerValue::from_json(v)))
.collect(),
),
}
}
}
impl<'de> Deserialize<'de> for WhiskerValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct WhiskerValueVisitor;
impl<'de> Visitor<'de> for WhiskerValueVisitor {
type Value = WhiskerValue;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("any JSON-compatible value")
}
fn visit_unit<E>(self) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Null)
}
fn visit_none<E>(self) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Null)
}
fn visit_some<D>(self, d: D) -> Result<WhiskerValue, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(d)
}
fn visit_bool<E>(self, v: bool) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Bool(v))
}
fn visit_i64<E>(self, v: i64) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Int(v))
}
fn visit_u64<E>(self, v: u64) -> Result<WhiskerValue, E> {
Ok(i64::try_from(v).map_or(WhiskerValue::Float(v as f64), WhiskerValue::Int))
}
fn visit_f64<E>(self, v: f64) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Float(v))
}
fn visit_str<E>(self, v: &str) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::String(v.to_owned()))
}
fn visit_string<E>(self, v: String) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::String(v))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<WhiskerValue, E> {
Ok(WhiskerValue::Bytes(v.to_owned()))
}
fn visit_seq<A>(self, mut seq: A) -> Result<WhiskerValue, A::Error>
where
A: SeqAccess<'de>,
{
let mut out = Vec::new();
while let Some(item) = seq.next_element()? {
out.push(item);
}
Ok(WhiskerValue::Array(out))
}
fn visit_map<A>(self, mut map: A) -> Result<WhiskerValue, A::Error>
where
A: MapAccess<'de>,
{
let mut out = BTreeMap::new();
while let Some((k, v)) = map.next_entry::<String, WhiskerValue>()? {
out.insert(k, v);
}
Ok(WhiskerValue::Map(out))
}
}
deserializer.deserialize_any(WhiskerValueVisitor)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WhiskerModuleError(pub String);
impl std::fmt::Display for WhiskerModuleError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for WhiskerModuleError {}
impl From<()> for WhiskerValue {
fn from(_: ()) -> Self {
WhiskerValue::Null
}
}
impl From<bool> for WhiskerValue {
fn from(v: bool) -> Self {
WhiskerValue::Bool(v)
}
}
impl From<i32> for WhiskerValue {
fn from(v: i32) -> Self {
WhiskerValue::Int(v as i64)
}
}
impl From<i64> for WhiskerValue {
fn from(v: i64) -> Self {
WhiskerValue::Int(v)
}
}
impl From<u32> for WhiskerValue {
fn from(v: u32) -> Self {
WhiskerValue::Int(v as i64)
}
}
impl From<f32> for WhiskerValue {
fn from(v: f32) -> Self {
WhiskerValue::Float(v as f64)
}
}
impl From<f64> for WhiskerValue {
fn from(v: f64) -> Self {
WhiskerValue::Float(v)
}
}
impl From<String> for WhiskerValue {
fn from(v: String) -> Self {
WhiskerValue::String(v)
}
}
impl From<&str> for WhiskerValue {
fn from(v: &str) -> Self {
WhiskerValue::String(v.to_string())
}
}
impl From<Vec<u8>> for WhiskerValue {
fn from(v: Vec<u8>) -> Self {
WhiskerValue::Bytes(v)
}
}
impl<T> From<Vec<T>> for WhiskerValue
where
T: Into<WhiskerValue>,
{
fn from(v: Vec<T>) -> Self {
WhiskerValue::Array(v.into_iter().map(Into::into).collect())
}
}
impl TryFrom<WhiskerValue> for () {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Null => Ok(()),
other => Err(format!("expected Null, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for bool {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Bool(b) => Ok(b),
other => Err(format!("expected Bool, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for i64 {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Int(i) => Ok(i),
other => Err(format!("expected Int, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for i32 {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Int(i) => {
i32::try_from(i).map_err(|_| format!("Int {i} out of range for i32"))
}
other => Err(format!("expected Int, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for f64 {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Float(f) => Ok(f),
WhiskerValue::Int(i) => Ok(i as f64),
other => Err(format!("expected Float, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for f32 {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
f64::try_from(v).map(|f| f as f32)
}
}
impl TryFrom<WhiskerValue> for String {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::String(s) => Ok(s),
other => Err(format!("expected String, got {other:?}")),
}
}
}
impl TryFrom<WhiskerValue> for Vec<u8> {
type Error = String;
fn try_from(v: WhiskerValue) -> Result<Self, Self::Error> {
match v {
WhiskerValue::Bytes(b) => Ok(b),
other => Err(format!("expected Bytes, got {other:?}")),
}
}
}