nson 0.12.1

NSON is a lightweight data-interchange format like JSON or BSON
Documentation
use serde_json::{self, json, Map};
use base64;

use crate::{Value, Message, Array, MessageId};

impl From<Value> for serde_json::Value {
    fn from(value: Value) -> Self {
        match value {
            Value::F32(v) => json!(v),
            Value::F64(v) => json!({"$f64": v}),
            Value::I32(v) => json!(v),
            Value::I64(v) => json!({"$i64": v}),
            Value::U32(v) => json!({"$u32": v}),
            Value::U64(v) => json!({"$u64": v}),
            Value::String(v) => json!(v),
            Value::Array(v) => {
                let array: Vec<serde_json::Value> = v.into_iter().map(|v| v.into()).collect();
                json!(array)
            }
            Value::Message(v) => {
                let map: Map<String, serde_json::Value> = v.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
                json!(map)
            }
            Value::Bool(v) => json!(v),
            Value::Null => json!(null),
            Value::Binary(v) => json!({"$bin": base64::encode(v.0)}),
            Value::TimeStamp(v) => json!({"$tim": v.0}),
            Value::MessageId(v) => json!({"$mid": v.to_hex()})
        }
    }
}

impl From<serde_json::Value> for Value {
    fn from(value: serde_json::Value) -> Self {
        match value {
            serde_json::Value::Number(v) => {
                if let Some(i) = v.as_i64() {
                    Value::I32(i as i32)
                } else if let Some(u) = v.as_u64() {
                    Value::I32(u as i32)
                } else if let Some(f) = v.as_f64() {
                    Value::F32(f as f32)
                } else {
                   unreachable!()
                }
            }
            serde_json::Value::String(v) => v.into(),
            serde_json::Value::Bool(v) => v.into(),
            serde_json::Value::Array(v) => {
                let array: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
                Value::Array(Array::from_vec(array))
            }
            serde_json::Value::Object(map) => {
                if map.len() == 1 {
                    let keys: Vec<_> = map.keys().map(|s| s.as_str()).collect();

                    match keys.as_slice() {
                        ["$tim"] => {
                            if let Some(v) = map.get("$tim") {
                                if let Some(u) = v.as_u64() {
                                    return Value::TimeStamp(u.into())
                                }
                            }
                        }
                        ["$bin"] => {
                            if let Some(v) = map.get("$bin") {
                                if let Some(hex) = v.as_str() {
                                    if let Ok(bin) = base64::decode(hex) {
                                        return bin.into()
                                    }
                                }
                            }
                        }
                        ["$mid"] => {
                            if let Some(v) = map.get("$mid") {
                                if let Some(hex) = v.as_str() {
                                    if let Ok(message_id) = MessageId::with_string(hex) {
                                        return message_id.into()
                                    }
                                }
                            }
                        }
                        ["$f64"] => {
                            if let Some(v) = map.get("$f64") {
                                if let Some(f) = v.as_f64() {
                                    return Value::F64(f)
                                }
                            }
                        }
                        ["$i64"] => {
                            if let Some(v) = map.get("$i64") {
                                if let Some(i) = v.as_i64() {
                                    return Value::I64(i)
                                }
                            }
                        }
                        ["$u32"] => {
                            if let Some(v) = map.get("$u32") {
                                if let Some(u) = v.as_u64() {
                                    return Value::U32(u as u32)
                                }
                            }
                        }
                        ["$u64"] => {
                            if let Some(v) = map.get("$u64") {
                                if let Some(u) = v.as_u64() {
                                    return Value::U64(u)
                                }
                            }
                        }
                        _ => ()
                    }
                }

                let message: Message = map.into_iter().map(|(k, v)| (k, v.into())).collect();

                Value::Message(message)
            }
            serde_json::Value::Null => Value::Null
        }
    }
}

impl From<Message> for serde_json::Value {
    fn from(message: Message) -> Self {
        Value::Message(message).into()
    }
}

impl From<serde_json::Value> for Message {
    fn from(json: serde_json::Value) -> Self {
        let value: Value = json.into();

        match value {
            Value::Message(message) => message,
            _ => Message::new()
        }
    }
}

#[cfg(test)]
mod test {
    use crate::{msg, Value, MessageId};
    use crate::value::TimeStamp;
    use serde_json::{self, json};

    #[test]
    fn convert_json() {
        let json = json!({
            "a": 1i32,
            "b": {"$i64": 2i64},
            "c": {"$u32": 3u32},
            "d": {"$u64": 4u64},
            "e": 5.6f32,
            "f": {"$f64": 7.8f64},
            "g": {
                "$tim": 456
            },
            "h": {
                "$mid": "0171253e54db9aef760d5fbd"
            },
            "i": {
                "$bin": "AQIDBAUG"
            }
        });

        let message = msg!{
            "a": 1i32,
            "b": 2i64,
            "c": 3u32,
            "d": 4u64,
            "e": 5.6f32,
            "f": 7.8f64,
            "g": TimeStamp(456),
            "h": MessageId::with_string("0171253e54db9aef760d5fbd").unwrap(),
            "i": vec![1u8, 2, 3, 4, 5, 6]
        };

        let nson_value: Value = message.clone().into();

        let value: serde_json::Value = message.into();

        assert!(json == value);

        let value2: Value = json.into();

        assert!(nson_value == value2);
    }
}