xrl 0.0.9

Xi Rpc Lib - Tokio based implementation of the RPC used in the Xi editor
Documentation
use serde_json as json;

use super::line::Line;

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub enum OperationType {
    Copy,
    Skip,
    Invalidate,
    Update,
    Insert,
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Operation {
    #[serde(rename = "op")]
    #[serde(deserialize_with = "deserialize_operation_type")]
    pub operation_type: OperationType,
    #[serde(rename = "n")]
    pub nb_lines: u64,
    #[serde(rename = "ln")]
    pub line_num: Option<u64>,
    #[serde(default)]
    pub lines: Vec<Line>,
}

fn deserialize_operation_type<'de, D>(de: D) -> ::std::result::Result<OperationType, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let value: json::Value = serde::Deserialize::deserialize(de)?;
    match value {
        json::Value::String(ref s) if &*s == "copy" => Ok(OperationType::Copy),
        json::Value::String(ref s) if &*s == "skip" => Ok(OperationType::Skip),
        json::Value::String(ref s) if &*s == "invalidate" => Ok(OperationType::Invalidate),
        json::Value::String(ref s) if &*s == "update" => Ok(OperationType::Update),
        json::Value::String(ref s) if &*s == "ins" => Ok(OperationType::Insert),
        _ => Err(serde::de::Error::custom(
            "Unexpected value for operation type",
        )),
    }
}

#[test]
fn deserialize_operation_from_value() {
    use serde_json;

    let value = json!({"n": 12, "op": "ins"});
    let operation = Operation {
        operation_type: OperationType::Insert,
        nb_lines: 12,
        line_num: None,
        lines: vec![],
    };
    let deserialized: Result<Operation, _> = serde_json::from_value(value);
    assert_eq!(deserialized.unwrap(), operation);

    let value = json!({"lines":[{"cursor":[0],"styles":[],"text":"foo"},{"styles":[],"text":""}],"n":60,"op":"invalidate"});
    let operation = Operation {
        operation_type: OperationType::Invalidate,
        nb_lines: 60,
        line_num: None,
        lines: vec![
            Line {
                cursor: vec![0],
                styles: vec![],
                text: "foo".to_owned(),
                line_num: None,
            },
            Line {
                cursor: vec![],
                styles: vec![],
                text: "".to_owned(),
                line_num: None,
            },
        ],
    };
    let deserialized: Result<Operation, _> = serde_json::from_value(value);
    assert_eq!(deserialized.unwrap(), operation);
}

#[test]
fn deserialize_operation() {
    use serde_json;

    let s = r#"{"n": 12, "op": "ins"}"#;
    let operation = Operation {
        operation_type: OperationType::Insert,
        nb_lines: 12,
        line_num: None,
        lines: vec![],
    };
    let deserialized: Result<Operation, _> = serde_json::from_str(s);
    assert_eq!(deserialized.unwrap(), operation);

    let s = r#"{"lines":[{"cursor":[0],"styles":[],"text":"foo"},{"styles":[],"text":""}],"n":60,"op":"invalidate"}"#;
    let operation = Operation {
        operation_type: OperationType::Invalidate,
        nb_lines: 60,
        line_num: None,
        lines: vec![
            Line {
                cursor: vec![0],
                styles: vec![],
                text: "foo".to_owned(),
                line_num: None,
            },
            Line {
                cursor: vec![],
                styles: vec![],
                text: "".to_owned(),
                line_num: None,
            },
        ],
    };
    let deserialized: Result<Operation, _> = serde_json::from_str(s);
    assert_eq!(deserialized.unwrap(), operation);
}

#[test]
fn deserialize_copy() {
    use serde_json;
    let s = r#"{"ln":3,"n":1,"op":"copy"}"#;
    let operation = Operation {
        operation_type: OperationType::Copy,
        line_num: Some(3),
        nb_lines: 1,
        lines: Vec::new(),
    };

    let deserialized: Result<Operation, _> = serde_json::from_str(s);
    assert_eq!(deserialized.unwrap(), operation);
}