use serde_json::Map;
use serde_json::Number;
use serde_json::Value as JsonValue;
use crate::ValueRef;
pub(super) enum PreparedScalar<'a> {
Borrowed(ValueRef<'a>),
Formatted(String),
Number(Number),
}
macro_rules! borrowed_payload {
(String, $class:ident, $value:expr) => {
JsonValue::String($value.to_owned())
};
($variant:ident, json_bool, $value:expr) => {
JsonValue::Bool($value)
};
($variant:ident, json_number, $value:expr) => {
JsonValue::from($value)
};
($variant:ident, json_identity, $value:expr) => {
crate::wire::json::canonicalize_json_value($value)
};
($variant:ident, json_object, $value:expr) => {{
let mut entries: Vec<_> = $value.iter().collect();
entries.sort_unstable_by(|(left, _), (right, _)| left.cmp(right));
let mut object = Map::with_capacity(entries.len());
for (key, value) in entries {
object.insert(key.clone(), JsonValue::String(value.clone()));
}
JsonValue::Object(object)
}};
($variant:ident, $class:ident, $value:expr) => {{
let _ = $value;
unreachable!("formatted payloads must use their prepared rendering")
}};
}
macro_rules! borrowed_match {
($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
match $value {
ValueRef::Unset(_) => JsonValue::Null,
$($(#[$cfg])* ValueRef::$variant(value) => borrowed_payload!($variant, $json_class, value),)+
}
};
}
impl PreparedScalar<'_> {
pub(super) fn materialize(self) -> JsonValue {
match self {
Self::Borrowed(value) => for_each_value_type!(borrowed_match, value),
Self::Formatted(text) => JsonValue::String(text),
Self::Number(number) => JsonValue::Number(number),
}
}
}