//! `JsonNumber` — elicitation-enabled wrapper around `serde_json::Number`.

use elicitation::{elicit_newtype, elicit_newtype_traits};
use elicitation_derive::reflect_methods;

elicit_newtype!(serde_json::Number, as JsonNumber, serde);
elicit_newtype_traits!(JsonNumber, serde_json::Number, [eq, display]);

#[reflect_methods]
impl JsonNumber {
    /// Returns true if this number is representable as an `i64`.
    pub fn is_i64(&self) -> bool {
        self.0.is_i64()
    }

    /// Returns true if this number is representable as a `u64`.
    pub fn is_u64(&self) -> bool {
        self.0.is_u64()
    }

    /// Returns true if this number is a float (`f64`).
    pub fn is_f64(&self) -> bool {
        self.0.is_f64()
    }

    /// Returns the value as `i64` if representable, or `None`.
    pub fn as_i64(&self) -> Option<i64> {
        self.0.as_i64()
    }

    /// Returns the value as `u64` if representable, or `None`.
    pub fn as_u64(&self) -> Option<u64> {
        self.0.as_u64()
    }

    /// Returns the value as `f64`, or `None` if it cannot be represented.
    pub fn as_f64(&self) -> Option<f64> {
        self.0.as_f64()
    }

    /// Serialize this number to its JSON string representation.
    pub fn to_json_string(&self) -> String {
        self.0.to_string()
    }
}

mod emit_impls {
    use super::JsonNumber;
    use elicitation::emit_code::ToCodeLiteral;
    use proc_macro2::TokenStream;

    impl ToCodeLiteral for JsonNumber {
        fn to_code_literal(&self) -> TokenStream {
            let s = self.0.to_string();
            quote::quote! {
                ::elicit_serde_json::JsonNumber::from(
                    ::serde_json::from_str::<::serde_json::Number>(#s).expect("valid JSON number")
                )
            }
        }
    }
}

impl elicitation::ElicitComplete for JsonNumber {}
