<commit_before>use quick_xml::se::{to_string, Serializer};
use quick_xml::writer::Writer;

use pretty_assertions::assert_eq;

use serde::{Serialize, Serializer as SerSerializer};

#[test]
fn serialize_bool() {
    let inputs = [(true, "true"), (false, "false")];

    for (src, should_be) in &inputs {
        let mut buffer = Vec::new();
        let mut ser = Serializer::new(&mut buffer);
        ser.serialize_bool(*src).unwrap();

        assert_eq!(String::from_utf8(buffer).unwrap(), *should_be);
    }
}

#[test]
fn serialize_struct() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    bob.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Person name=\"Bob\" age=\"42\"/>"
    );
}

#[test]
fn serialize_struct_value_number() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$value")]
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_struct_value_string() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$value")]
        age: String,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: "42".to_string(),
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_enum() {
    #[derive(Serialize)]
    #[allow(dead_code)]
    enum Node {
        Boolean(bool),
        Number(f64),
        String(String),
    }

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    let node = Node::Boolean(true);
    node.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Boolean>true</Boolean>"
    );
}

#[test]
#[ignore]
fn serialize_a_list() {
    let inputs = vec![1, 2, 3, 4];

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    inputs.serialize(&mut ser).unwrap();

    println!("{}", String::from_utf8(buffer).unwrap());
    panic!();
}

#[derive(Serialize)]
struct Unit;

#[derive(Serialize)]
struct Newtype(bool);

#[derive(Serialize)]
struct Tuple(f32, &'static str);

#[derive(Serialize)]
struct Struct {
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
struct NestedStruct {
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct FlattenStruct {
    #[serde(flatten)]
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct Nested {
    float: f64,
}

#[derive(Serialize)]
enum ExternallyTagged {
    Unit,
    #[serde(rename = "$primitive=PrimitiveUnit")]
    PrimitiveUnit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
    Unit,
    /// Primitives (such as `bool`) are not supported by the serde in the internally tagged mode
    Newtype(Nested),
    // Tuple(f64, &'static str),// Tuples are not supported in the internally tagged mode
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag", content = "content")]
enum AdjacentlyTagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(untagged)]
enum Untagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

mod with_root {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn unit() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let data = Unit;
        data.serialize(&mut ser).unwrap();
        assert_eq!(String::from_utf8(buffer).unwrap(), "<root/>");
    }

    #[test]
    fn newtype() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let data = Newtype(true);
        data.serialize(&mut ser).unwrap();
        assert_eq!(String::from_utf8(buffer).unwrap(), "<root>true</root>");
    }

    #[test]
    fn tuple() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let data = (42.0, "answer");
        data.serialize(&mut ser).unwrap();
        assert_eq!(
            String::from_utf8(buffer).unwrap(),
            "<root>42</root><root>answer</root>"
        );
    }

    #[test]
    fn tuple_struct() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let data = Tuple(42.0, "answer");
        data.serialize(&mut ser).unwrap();
        assert_eq!(
            String::from_utf8(buffer).unwrap(),
            "<root>42</root><root>answer</root>"
        );
    }

    #[test]
    fn struct_() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let node = Struct {
            float: 42.0,
            string: "answer",
        };
        node.serialize(&mut ser).unwrap();
        assert_eq!(
            String::from_utf8(buffer).unwrap(),
            r#"<root float="42" string="answer"/>"#
        );
    }

    #[test]
    fn nested_struct() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let node = NestedStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        };
        node.serialize(&mut ser).unwrap();
        assert_eq!(
            String::from_utf8(buffer).unwrap(),
            r#"<root string="answer"><nested float="42"/></root>"#
        );
    }

    #[test]
    fn flatten_struct() {
        let mut buffer = Vec::new();
        let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

        let node = FlattenStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        };
        node.serialize(&mut ser).unwrap();
        assert_eq!(
            String::from_utf8(buffer).unwrap(),
            r#"<root><float>42</float><string>answer</string></root>"#
        );
    }

    mod enum_ {
        use super::*;

        mod externally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            #[test]
            fn unit() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Unit;
                node.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), "<Unit/>");
            }

            #[test]
            fn primitive_unit() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::PrimitiveUnit;
                node.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), "PrimitiveUnit");
            }

            #[test]
            fn newtype() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Newtype(true);
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    "<Newtype>true</Newtype>"
                );
            }

            #[test]
            fn struct_() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<Struct float="42" string="answer"/>"#
                );
            }

            #[test]
            fn tuple_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Tuple(42.0, "answer");
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    "<Tuple>42</Tuple><Tuple>answer</Tuple>"
                );
            }

            #[test]
            fn nested_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<Holder string="answer"><nested float="42"/></Holder>"#
                );
            }

            #[test]
            fn flatten_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = ExternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<Flatten><float>42</float><string>answer</string></Flatten>"#
                );
            }
        }

        mod internally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            #[test]
            fn unit() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = InternallyTagged::Unit;
                node.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), r#"<root tag="Unit"/>"#);
            }

            #[test]
            fn newtype() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = InternallyTagged::Newtype(Nested { float: 4.2 });
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Newtype" float="4.2"/>"#
                );
            }

            #[test]
            fn struct_() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = InternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Struct" float="42" string="answer"/>"#
                );
            }

            #[test]
            fn nested_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = InternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Holder" string="answer"><nested float="42"/></root>"#
                );
            }

            #[test]
            fn flatten_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = InternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root><tag>Flatten</tag><float>42</float><string>answer</string></root>"#
                );
            }
        }

        mod adjacently_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            #[test]
            fn unit() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Unit;
                node.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), r#"<root tag="Unit"/>"#);
            }

            #[test]
            fn newtype() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Newtype(true);
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Newtype" content="true"/>"#
                );
            }

            #[test]
            fn tuple_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Tuple(42.0, "answer");
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Tuple"><content>42</content><content>answer</content></root>"#
                );
            }

            #[test]
            fn struct_() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Struct"><content float="42" string="answer"/></root>"#
                );
            }

            #[test]
            fn nested_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Holder"><content string="answer"><nested float="42"/></content></root>"#
                );
            }

            #[test]
            fn flatten_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = AdjacentlyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root tag="Flatten"><content><float>42</float><string>answer</string></content></root>"#
                );
            }
        }

        mod untagged {
            use super::*;
            use pretty_assertions::assert_eq;

            #[test]
            fn unit() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Unit;
                node.serialize(&mut ser).unwrap();
                // Unit variant consists just from the tag, and because tags
                // are not written in untagged mode, nothing is written
                assert_eq!(String::from_utf8(buffer).unwrap(), "");
            }

            #[test]
            fn newtype() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Newtype(true);
                node.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), "true");
            }

            #[test]
            fn tuple_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Tuple(42.0, "answer");
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    "<root>42</root><root>answer</root>"
                );
            }

            #[test]
            fn struct_() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Struct {
                    float: 42.0,
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root float="42" string="answer"/>"#
                );
            }

            #[test]
            fn nested_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root string="answer"><nested float="42"/></root>"#
                );
            }

            #[test]
            fn flatten_struct() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                let node = Untagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                };
                node.serialize(&mut ser).unwrap();
                assert_eq!(
                    String::from_utf8(buffer).unwrap(),
                    r#"<root><float>42</float><string>answer</string></root>"#
                );
            }
        }
    }
}
<commit_msg>Rewrite tests using macros<commit_after>use quick_xml::se::{to_string, Serializer};
use quick_xml::writer::Writer;

use pretty_assertions::assert_eq;

use serde::{Serialize, Serializer as SerSerializer};

#[test]
fn serialize_bool() {
    let inputs = [(true, "true"), (false, "false")];

    for (src, should_be) in &inputs {
        let mut buffer = Vec::new();
        let mut ser = Serializer::new(&mut buffer);
        ser.serialize_bool(*src).unwrap();

        assert_eq!(String::from_utf8(buffer).unwrap(), *should_be);
    }
}

#[test]
fn serialize_struct() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    bob.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Person name=\"Bob\" age=\"42\"/>"
    );
}

#[test]
fn serialize_struct_value_number() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$value")]
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_struct_value_string() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$value")]
        age: String,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: "42".to_string(),
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_enum() {
    #[derive(Serialize)]
    #[allow(dead_code)]
    enum Node {
        Boolean(bool),
        Number(f64),
        String(String),
    }

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    let node = Node::Boolean(true);
    node.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Boolean>true</Boolean>"
    );
}

#[test]
#[ignore]
fn serialize_a_list() {
    let inputs = vec![1, 2, 3, 4];

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    inputs.serialize(&mut ser).unwrap();

    println!("{}", String::from_utf8(buffer).unwrap());
    panic!();
}

#[derive(Serialize)]
struct Unit;

#[derive(Serialize)]
struct Newtype(bool);

#[derive(Serialize)]
struct Tuple(f32, &'static str);

#[derive(Serialize)]
struct Struct {
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
struct NestedStruct {
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct FlattenStruct {
    #[serde(flatten)]
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct Nested {
    float: f64,
}

#[derive(Serialize)]
enum ExternallyTagged {
    Unit,
    #[serde(rename = "$primitive=PrimitiveUnit")]
    PrimitiveUnit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
    Unit,
    /// Primitives (such as `bool`) are not supported by the serde in the internally tagged mode
    Newtype(Nested),
    // Tuple(f64, &'static str),// Tuples are not supported in the internally tagged mode
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag", content = "content")]
enum AdjacentlyTagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(untagged)]
enum Untagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
}

mod with_root {
    use super::*;
    use pretty_assertions::assert_eq;

    macro_rules! serialize_as {
        ($name:ident: $data:expr => $expected:literal) => {
            #[test]
            fn $name() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                $data.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), $expected);
            }
        };
    }

    serialize_as!(unit:
        Unit
        => "<root/>");
    serialize_as!(newtype:
        Newtype(true)
        => "<root>true</root>");
    serialize_as!(tuple:
        (42.0, "answer")
        => "<root>42</root><root>answer</root>");
    serialize_as!(tuple_struct:
        Tuple(42.0, "answer")
        => "<root>42</root><root>answer</root>");
    serialize_as!(struct_:
        Struct {
            float: 42.0,
            string: "answer"
        }
        => r#"<root float="42" string="answer"/>"#);
    serialize_as!(nested_struct:
        NestedStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => r#"<root string="answer"><nested float="42"/></root>"#);
    serialize_as!(flatten_struct:
        FlattenStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => r#"<root><float>42</float><string>answer</string></root>"#);

    mod enum_ {
        use super::*;

        mod externally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                ExternallyTagged::Unit
                => "<Unit/>");
            serialize_as!(primitive_unit:
                ExternallyTagged::PrimitiveUnit
                => "PrimitiveUnit");
            serialize_as!(newtype:
                ExternallyTagged::Newtype(true)
                => "<Newtype>true</Newtype>");
            serialize_as!(tuple_struct:
                ExternallyTagged::Tuple(42.0, "answer")
                => "<Tuple>42</Tuple><Tuple>answer</Tuple>");
            serialize_as!(struct_:
                ExternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<Struct float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                ExternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<Holder string="answer"><nested float="42"/></Holder>"#);
            serialize_as!(flatten_struct:
                ExternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<Flatten><float>42</float><string>answer</string></Flatten>"#);
        }

        mod internally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                InternallyTagged::Unit
                => r#"<root tag="Unit"/>"#);
            serialize_as!(newtype:
                InternallyTagged::Newtype(Nested { float: 4.2 })
                => r#"<root tag="Newtype" float="4.2"/>"#);
            serialize_as!(struct_:
                InternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root tag="Struct" float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                InternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Holder" string="answer"><nested float="42"/></root>"#);
            serialize_as!(flatten_struct:
                InternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root><tag>Flatten</tag><float>42</float><string>answer</string></root>"#);
        }

        mod adjacently_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                AdjacentlyTagged::Unit
                => r#"<root tag="Unit"/>"#);
            serialize_as!(newtype:
                AdjacentlyTagged::Newtype(true)
                => r#"<root tag="Newtype" content="true"/>"#);
            serialize_as!(tuple_struct:
                AdjacentlyTagged::Tuple(42.0, "answer")
                => r#"<root tag="Tuple"><content>42</content><content>answer</content></root>"#);
            serialize_as!(struct_:
                AdjacentlyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root tag="Struct"><content float="42" string="answer"/></root>"#);
            serialize_as!(nested_struct:
                AdjacentlyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Holder"><content string="answer"><nested float="42"/></content></root>"#);
            serialize_as!(flatten_struct:
                AdjacentlyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Flatten"><content><float>42</float><string>answer</string></content></root>"#);
        }

        mod untagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                Untagged::Unit
                // Unit variant consists just from the tag, and because tags
                // are not written in untagged mode, nothing is written
                => "");
            serialize_as!(newtype:
                Untagged::Newtype(true)
                => "true");
            serialize_as!(tuple_struct:
                Untagged::Tuple(42.0, "answer")
                => "<root>42</root><root>answer</root>");
            serialize_as!(struct_:
                Untagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                Untagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root string="answer"><nested float="42"/></root>"#);
            serialize_as!(flatten_struct:
                Untagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root><float>42</float><string>answer</string></root>"#);
        }
    }
}
<|endoftext|>


<commit_before>use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use geometry::CGPoint;
use event_source::{CGEventSource,CGEventSourceRef};

use libc;
use std::mem;
use std::ptr;

pub type CGKeyCode = libc::uint16_t;

/// Flags for events
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventFlags {
  // Device-independent modifier key bits.
  AlphaShift = 0x00010000,
  Shift = 0x00020000,
  Control = 0x00040000,
  Alternate = 0x00080000,
  Command = 0x00100000,

  // Special key identifiers.
  Help = 0x00400000,
  SecondaryFn = 0x00800000,

  // Identifies key events from numeric keypad area on extended keyboards.
  NumericPad = 0x00200000,

  // Indicates if mouse/pen movement events are not being coalesced
  NonCoalesced = 0x00000100,
}

/// Constants that specify the different types of input events.
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventType {
    Null = 1 << 0,

    // Mouse events.
    LeftMouseDown = 1 << 1,
    LeftMouseUp = 1 << 2,
    RightMouseDown = 1 << 3,
    RightMouseUp = 1 << 4,
    MouseMoved = 1 << 5,
    LeftMouseDragged = 1 << 6,
    RightMouseDragged = 1 << 7,

    // Keyboard events.
    KeyDown = 1 << 10,
    KeyUp = 1 << 11,
    FlagsChanged = 1 << 12,

    // Specialized control devices.
    ScrollWheel = 1 << 22,
    TabletPointer = 1 << 23,
    TabletProximity = 1 << 24,
    OtherMouseDown = 1 << 25,
    OtherMouseUp = 1 << 26,
    OtherMouseDragged = 1 << 27,

    // Out of band event types. These are delivered to the event tap callback
    // to notify it of unusual conditions that disable the event tap.
    TapDisabledByTimeout = 0xFFFFFFFE,
    TapDisabledByUserInput = 0xFFFFFFFF,
}

// Constants that specify buttons on a one, two, or three-button mouse.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGMouseButton {
    Left,
    Right,
    Center,
}

/// Possible tapping points for events.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapLocation {
    HID,
    Session,
    AnnotatedSession,
}

#[repr(C)]
pub struct __CGEvent;

pub type CGEventRef = *const __CGEvent;

pub struct CGEvent {
    obj: CGEventRef,
}

impl Clone for CGEvent {
    #[inline]
    fn clone(&self) -> CGEvent {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGEvent {
    fn drop(&mut self) {
        unsafe {
            let ptr = self.as_CFTypeRef();
            assert!(ptr != ptr::null());
            CFRelease(ptr);
        }
    }
}

impl TCFType<CGEventRef> for CGEvent {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGEventRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
        let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
        CGEvent {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGEventGetTypeID()
        }
    }
}

impl CGEvent {
    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreate(source.as_concrete_TypeRef());
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_keyboard_event(
        source: CGEventSource,
        keycode: CGKeyCode,
        keydown: bool
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_mouse_event(
        source: CGEventSource,
        mouse_type: CGEventType,
        mouse_cursor_position: CGPoint,
        mouse_button: CGMouseButton
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
                mouse_cursor_position, mouse_button);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn post(&self, tap_location: CGEventTapLocation) {
        unsafe {
            CGEventPost(tap_location, self.as_concrete_TypeRef());
        }
    }

    pub fn location(&self) -> CGPoint {
        unsafe {
            CGEventGetLocation(self.as_concrete_TypeRef())
        }
    }

    #[cfg(feature = "elcapitan")]
    pub fn post_to_pid(&self, pid: libc::pid_t) {
        unsafe {
            CGEventPostToPid(pid, self.as_concrete_TypeRef());
        }
    }

    pub fn set_flags(&self, flags: CGEventFlags) {
        unsafe {
            CGEventSetFlags(self.as_concrete_TypeRef(), flags);
        }
    }

    pub fn get_flags(&self) -> CGEventFlags {
        unsafe {
            CGEventGetFlags(self.as_concrete_TypeRef())
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    /// Return the type identifier for the opaque type `CGEventRef'.
    fn CGEventGetTypeID() -> CFTypeID;

    /// Return a new event using the event source `source'. If `source' is NULL,
    /// the default source is used.
    fn CGEventCreate(source: CGEventSourceRef) -> CGEventRef;

    /// Return a new keyboard event.
    ///
    /// The event source may be taken from another event, or may be NULL. Based
    /// on the virtual key code values entered, the appropriate key down, key up,
    /// or flags changed events are generated.
    ///
    /// All keystrokes needed to generate a character must be entered, including
    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
    /// and 'z' key must be released:
    fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
        keydown: bool) -> CGEventRef;

    /// Return a new mouse event.
    ///
    /// The event source may be taken from another event, or may be NULL.
    /// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
    /// should be the position of the mouse cursor in global coordinates.
    /// `mouseButton' should be the button that's changing state; `mouseButton'
    /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
    /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
    ///
    /// The current implemementation of the event system supports a maximum of
    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
    /// the center button, and the remaining buttons are in USB device order.
    fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
        mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;

    /// Post an event into the event stream at a specified location.
    ///
    /// This function posts the specified event immediately before any event taps
    /// instantiated for that location, and the event passes through any such
    /// taps.
    fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);

    #[cfg(feature = "elcapitan")]
    /// Post an event to a specified process ID
    fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);

    /// Set the event flags of an event.
    fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);

    /// Return the event flags of an event.
    fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;

    /// Return the location of an event in global display coordinates.
    /// CGPointZero is returned if event is not a valid CGEventRef.
    fn CGEventGetLocation(event: CGEventRef) -> CGPoint;
}
<commit_msg>Fixed CGEventType in event.rs<commit_after>use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use geometry::CGPoint;
use event_source::{CGEventSource,CGEventSourceRef};

use libc;
use std::mem;
use std::ptr;

pub type CGKeyCode = libc::uint16_t;

/// Flags for events
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventFlags {
  // Device-independent modifier key bits.
  AlphaShift = 0x00010000,
  Shift = 0x00020000,
  Control = 0x00040000,
  Alternate = 0x00080000,
  Command = 0x00100000,

  // Special key identifiers.
  Help = 0x00400000,
  SecondaryFn = 0x00800000,

  // Identifies key events from numeric keypad area on extended keyboards.
  NumericPad = 0x00200000,

  // Indicates if mouse/pen movement events are not being coalesced
  NonCoalesced = 0x00000100,
}

/// Constants that specify the different types of input events.
///
/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h)
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventType {
    Null = 0,

    // Mouse events.
    LeftMouseDown = 1,
    LeftMouseUp = 2,
    RightMouseDown = 3,
    RightMouseUp = 4,
    MouseMoved = 5,
    LeftMouseDragged = 6,
    RightMouseDragged = 7,

    // Keyboard events.
    KeyDown = 10,
    KeyUp = 11,
    FlagsChanged = 12,

    // Specialized control devices.
    ScrollWheel = 22,
    TabletPointer = 23,
    TabletProximity = 24,
    OtherMouseDown = 25,
    OtherMouseUp = 26,
    OtherMouseDragged = 27,

    // Out of band event types. These are delivered to the event tap callback
    // to notify it of unusual conditions that disable the event tap.
    TapDisabledByTimeout = 0xFFFFFFFE,
    TapDisabledByUserInput = 0xFFFFFFFF,
}

// Constants that specify buttons on a one, two, or three-button mouse.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGMouseButton {
    Left,
    Right,
    Center,
}

/// Possible tapping points for events.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapLocation {
    HID,
    Session,
    AnnotatedSession,
}

#[repr(C)]
pub struct __CGEvent;

pub type CGEventRef = *const __CGEvent;

pub struct CGEvent {
    obj: CGEventRef,
}

impl Clone for CGEvent {
    #[inline]
    fn clone(&self) -> CGEvent {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGEvent {
    fn drop(&mut self) {
        unsafe {
            let ptr = self.as_CFTypeRef();
            assert!(ptr != ptr::null());
            CFRelease(ptr);
        }
    }
}

impl TCFType<CGEventRef> for CGEvent {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGEventRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGEventRef) -> CGEvent {
        let reference: CGEventRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGEventRef) -> CGEvent {
        CGEvent {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGEventGetTypeID()
        }
    }
}

impl CGEvent {
    pub fn new(source: CGEventSource) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreate(source.as_concrete_TypeRef());
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_keyboard_event(
        source: CGEventSource,
        keycode: CGKeyCode,
        keydown: bool
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateKeyboardEvent(source.as_concrete_TypeRef(), keycode, keydown);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn new_mouse_event(
        source: CGEventSource,
        mouse_type: CGEventType,
        mouse_cursor_position: CGPoint,
        mouse_button: CGMouseButton
    ) -> Result<CGEvent, ()> {
        unsafe {
            let event_ref = CGEventCreateMouseEvent(source.as_concrete_TypeRef(), mouse_type,
                mouse_cursor_position, mouse_button);
            if event_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(event_ref))
            } else {
                Err(())
            }
        }
    }

    pub fn post(&self, tap_location: CGEventTapLocation) {
        unsafe {
            CGEventPost(tap_location, self.as_concrete_TypeRef());
        }
    }

    pub fn location(&self) -> CGPoint {
        unsafe {
            CGEventGetLocation(self.as_concrete_TypeRef())
        }
    }

    #[cfg(feature = "elcapitan")]
    pub fn post_to_pid(&self, pid: libc::pid_t) {
        unsafe {
            CGEventPostToPid(pid, self.as_concrete_TypeRef());
        }
    }

    pub fn set_flags(&self, flags: CGEventFlags) {
        unsafe {
            CGEventSetFlags(self.as_concrete_TypeRef(), flags);
        }
    }

    pub fn get_flags(&self) -> CGEventFlags {
        unsafe {
            CGEventGetFlags(self.as_concrete_TypeRef())
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    /// Return the type identifier for the opaque type `CGEventRef'.
    fn CGEventGetTypeID() -> CFTypeID;

    /// Return a new event using the event source `source'. If `source' is NULL,
    /// the default source is used.
    fn CGEventCreate(source: CGEventSourceRef) -> CGEventRef;

    /// Return a new keyboard event.
    ///
    /// The event source may be taken from another event, or may be NULL. Based
    /// on the virtual key code values entered, the appropriate key down, key up,
    /// or flags changed events are generated.
    ///
    /// All keystrokes needed to generate a character must be entered, including
    /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z',
    /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT
    /// and 'z' key must be released:
    fn CGEventCreateKeyboardEvent(source: CGEventSourceRef, keycode: CGKeyCode,
        keydown: bool) -> CGEventRef;

    /// Return a new mouse event.
    ///
    /// The event source may be taken from another event, or may be NULL.
    /// `mouseType' should be one of the mouse event types. `mouseCursorPosition'
    /// should be the position of the mouse cursor in global coordinates.
    /// `mouseButton' should be the button that's changing state; `mouseButton'
    /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown',
    /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'.
    ///
    /// The current implemementation of the event system supports a maximum of
    /// thirty-two buttons. Mouse button 0 is the primary button on the mouse.
    /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is
    /// the center button, and the remaining buttons are in USB device order.
    fn CGEventCreateMouseEvent(source: CGEventSourceRef, mouseType: CGEventType,
        mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> CGEventRef;

    /// Post an event into the event stream at a specified location.
    ///
    /// This function posts the specified event immediately before any event taps
    /// instantiated for that location, and the event passes through any such
    /// taps.
    fn CGEventPost(tapLocation: CGEventTapLocation, event: CGEventRef);

    #[cfg(feature = "elcapitan")]
    /// Post an event to a specified process ID
    fn CGEventPostToPid(pid: libc::pid_t, event: CGEventRef);

    /// Set the event flags of an event.
    fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);

    /// Return the event flags of an event.
    fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;

    /// Return the location of an event in global display coordinates.
    /// CGPointZero is returned if event is not a valid CGEventRef.
    fn CGEventGetLocation(event: CGEventRef) -> CGPoint;
}
<|endoftext|>


<commit_before>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported(Vec<u8>),
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[doc(hidden)]
    __IsNotComplete,
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
    where I: Iterator<Item = Result<u8, Error>>
{
    let error = Error::new(ErrorKind::Other, "Could not parse an event");
    match item {
        b'\x1B' => {
            // This is an escape character, leading a control sequence.
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        // F1-F4
                        Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return Err(error),
                    }
                }
                Some(Ok(b'[')) => {
                    // This is a CSI sequence.
                    parse_csi(iter).ok_or(error)?
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return Err(error),
            })
        }
        b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
        b'\t' => Ok(Event::Key(Key::Char('\t'))),
        b'\x7F' => Ok(Event::Key(Key::Backspace)),
        c @ b'\x01'...b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        c @ b'\x1C'...b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
        b'\0' => Ok(Event::Key(Key::Null)),
        c => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
    }
}

/// Parses a CSI sequence, just after reading ^[
///
/// Returns None if an unrecognized sequence is found.
fn parse_csi<I>(iter: &mut I) -> Option<Event>
    where I: Iterator<Item = Result<u8, Error>>
{
    Some(match iter.next() {
        Some(Ok(b'D')) => Event::Key(Key::Left),
        Some(Ok(b'C')) => Event::Key(Key::Right),
        Some(Ok(b'A')) => Event::Key(Key::Up),
        Some(Ok(b'B')) => Event::Key(Key::Down),
        Some(Ok(b'H')) => Event::Key(Key::Home),
        Some(Ok(b'F')) => Event::Key(Key::End),
        Some(Ok(b'M')) => {
            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
            let mut next = || iter.next().unwrap().unwrap();

            let cb = next() as i8 - 32;
            // (1, 1) are the coords for upper left.
            let cx = next().saturating_sub(32) as u16;
            let cy = next().saturating_sub(32) as u16;
            Event::Mouse(match cb & 0b11 {
                0 => {
                    if cb & 0x40 != 0 {
                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                    } else {
                        MouseEvent::Press(MouseButton::Left, cx, cy)
                    }
                }
                1 => {
                    if cb & 0x40 != 0 {
                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                    } else {
                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                    }
                }
                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                3 => MouseEvent::Release(cx, cy),
                _ => return None,
            })
        }
        Some(Ok(b'<')) => {
            // xterm mouse encoding:
            // ESC [ < Cb ; Cx ; Cy (;) (M or m)
            let mut buf = Vec::new();
            let mut c = iter.next().unwrap().unwrap();
            while match c {
                b'm' | b'M' => false,
                _ => true,
            } {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }
            let str_buf = String::from_utf8(buf).unwrap();
            let nums = &mut str_buf.split(';');

            let cb = nums.next().unwrap().parse::<u16>().unwrap();
            let cx = nums.next().unwrap().parse::<u16>().unwrap();
            let cy = nums.next().unwrap().parse::<u16>().unwrap();

            let event = match cb {
                0...2 | 64...65 => {
                    let button = match cb {
                        0 => MouseButton::Left,
                        1 => MouseButton::Middle,
                        2 => MouseButton::Right,
                        64 => MouseButton::WheelUp,
                        65 => MouseButton::WheelDown,
                        _ => unreachable!(),
                    };
                    match c {
                        b'M' => MouseEvent::Press(button, cx, cy),
                        b'm' => MouseEvent::Release(cx, cy),
                        _ => return None,
                    }
                }
                32 => MouseEvent::Hold(cx, cy),
                3 => MouseEvent::Release(cx, cy),
                _ => return None,
            };

            Event::Mouse(event)
        }
        Some(Ok(c @ b'0'...b'9')) => {
            // Numbered escape code.
            let mut buf = Vec::new();
            buf.push(c);
            let mut c = iter.next().unwrap().unwrap();
            // The final byte of a CSI sequence can be in the range 64-126, so
            // let's keep reading anything else.
            while c < 64 || c > 126 {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }

            match c {
                // rxvt mouse encoding:
                // ESC [ Cb ; Cx ; Cy ; M
                b'M' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    let nums: Vec<u16> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    let cb = nums[0];
                    let cx = nums[1];
                    let cy = nums[2];

                    let event = match cb {
                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                        35 => MouseEvent::Release(cx, cy),
                        64 => MouseEvent::Hold(cx, cy),
                        96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                        _ => return None,
                    };

                    Event::Mouse(event)
                }
                // Special key code.
                b'~' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    // This CSI sequence can be a list of semicolon-separated
                    // numbers.
                    let nums: Vec<u8> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    if nums.is_empty() {
                        return None;
                    }

                    // TODO: handle multiple values for key modififiers (ex: values
                    // [3, 2] means Shift+Delete)
                    if nums.len() > 1 {
                        return None;
                    }

                    match nums[0] {
                        1 | 7 => Event::Key(Key::Home),
                        2 => Event::Key(Key::Insert),
                        3 => Event::Key(Key::Delete),
                        4 | 8 => Event::Key(Key::End),
                        5 => Event::Key(Key::PageUp),
                        6 => Event::Key(Key::PageDown),
                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                        _ => return None,
                    }
                }
                _ => return None,
            }
        }
        _ => return None,
    })

}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap());
            }
            if bytes.len() >= 4 {
                return error;
            }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<commit_msg>fix for #94 (#95)<commit_after>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported(Vec<u8>),
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[doc(hidden)]
    __IsNotComplete,
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
    where I: Iterator<Item = Result<u8, Error>>
{
    let error = Error::new(ErrorKind::Other, "Could not parse an event");
    match item {
        b'\x1B' => {
            // This is an escape character, leading a control sequence.
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        // F1-F4
                        Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return Err(error),
                    }
                }
                Some(Ok(b'[')) => {
                    // This is a CSI sequence.
                    parse_csi(iter).ok_or(error)?
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return Err(error),
            })
        }
        b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
        b'\t' => Ok(Event::Key(Key::Char('\t'))),
        b'\x7F' => Ok(Event::Key(Key::Backspace)),
        c @ b'\x01'...b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        c @ b'\x1C'...b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
        b'\0' => Ok(Event::Key(Key::Null)),
        c => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
    }
}

/// Parses a CSI sequence, just after reading ^[
///
/// Returns None if an unrecognized sequence is found.
fn parse_csi<I>(iter: &mut I) -> Option<Event>
    where I: Iterator<Item = Result<u8, Error>>
{
    Some(match iter.next() {
        Some(Ok(b'D')) => Event::Key(Key::Left),
        Some(Ok(b'C')) => Event::Key(Key::Right),
        Some(Ok(b'A')) => Event::Key(Key::Up),
        Some(Ok(b'B')) => Event::Key(Key::Down),
        Some(Ok(b'H')) => Event::Key(Key::Home),
        Some(Ok(b'F')) => Event::Key(Key::End),
        Some(Ok(b'M')) => {
            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
            let mut next = || iter.next().unwrap().unwrap();

            let cb = next() as i8 - 32;
            // (1, 1) are the coords for upper left.
            let cx = next().saturating_sub(32) as u16;
            let cy = next().saturating_sub(32) as u16;
            Event::Mouse(match cb & 0b11 {
                0 => {
                    if cb & 0x40 != 0 {
                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                    } else {
                        MouseEvent::Press(MouseButton::Left, cx, cy)
                    }
                }
                1 => {
                    if cb & 0x40 != 0 {
                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                    } else {
                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                    }
                }
                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                3 => MouseEvent::Release(cx, cy),
                _ => return None,
            })
        }
        Some(Ok(b'<')) => {
            // xterm mouse encoding:
            // ESC [ < Cb ; Cx ; Cy (;) (M or m)
            let mut buf = Vec::new();
            let mut c = iter.next().unwrap().unwrap();
            while match c {
                b'm' | b'M' => false,
                _ => true,
            } {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }
            let str_buf = String::from_utf8(buf).unwrap();
            let nums = &mut str_buf.split(';');

            let cb = nums.next().unwrap().parse::<u16>().unwrap();
            let cx = nums.next().unwrap().parse::<u16>().unwrap();
            let cy = nums.next().unwrap().parse::<u16>().unwrap();

            let event = match cb {
                0...2 | 64...65 => {
                    let button = match cb {
                        0 => MouseButton::Left,
                        1 => MouseButton::Middle,
                        2 => MouseButton::Right,
                        64 => MouseButton::WheelUp,
                        65 => MouseButton::WheelDown,
                        _ => unreachable!(),
                    };
                    match c {
                        b'M' => MouseEvent::Press(button, cx, cy),
                        b'm' => MouseEvent::Release(cx, cy),
                        _ => return None,
                    }
                }
                32 => MouseEvent::Hold(cx, cy),
                3 => MouseEvent::Release(cx, cy),
                _ => return None,
            };

            Event::Mouse(event)
        }
        Some(Ok(c @ b'0'...b'9')) => {
            // Numbered escape code.
            let mut buf = Vec::new();
            buf.push(c);
            let mut c = iter.next().unwrap().unwrap();
            // The final byte of a CSI sequence can be in the range 64-126, so
            // let's keep reading anything else.
            while c < 64 || c > 126 {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }

            match c {
                // rxvt mouse encoding:
                // ESC [ Cb ; Cx ; Cy ; M
                b'M' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    let nums: Vec<u16> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    let cb = nums[0];
                    let cx = nums[1];
                    let cy = nums[2];

                    let event = match cb {
                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                        35 => MouseEvent::Release(cx, cy),
                        64 => MouseEvent::Hold(cx, cy),
                        96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                        _ => return None,
                    };

                    Event::Mouse(event)
                }
                // Special key code.
                b'~' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    // This CSI sequence can be a list of semicolon-separated
                    // numbers.
                    let nums: Vec<u8> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    if nums.is_empty() {
                        return None;
                    }

                    // TODO: handle multiple values for key modififiers (ex: values
                    // [3, 2] means Shift+Delete)
                    if nums.len() > 1 {
                        return None;
                    }

                    match nums[0] {
                        1 | 7 => Event::Key(Key::Home),
                        2 => Event::Key(Key::Insert),
                        3 => Event::Key(Key::Delete),
                        4 | 8 => Event::Key(Key::End),
                        5 => Event::Key(Key::PageUp),
                        6 => Event::Key(Key::PageDown),
                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                        _ => return None,
                    }
                }
                _ => return None,
            }
        }
        _ => return None,
    })

}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            match iter.next() {
                Some(Ok(next)) => {
                    bytes.push(next);
                    if let Ok(st) = str::from_utf8(bytes) {
                        return Ok(st.chars().next().unwrap());
                    }
                    if bytes.len() >= 4 {
                        return error;
                    }
                }
                _ => return error,
            }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<|endoftext|>


<commit_before>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported,
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: Result<u8, Error>, iter: &mut I) -> Result<Event, Error>
where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Could not parse an event"));
    match item {
        Ok(b'\x1B') => {
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return error,
                    }
                }
                Some(Ok(b'[')) => {
                    match iter.next() {
                        Some(Ok(b'D')) => Event::Key(Key::Left),
                        Some(Ok(b'C')) => Event::Key(Key::Right),
                        Some(Ok(b'A')) => Event::Key(Key::Up),
                        Some(Ok(b'B')) => Event::Key(Key::Down),
                        Some(Ok(b'H')) => Event::Key(Key::Home),
                        Some(Ok(b'F')) => Event::Key(Key::End),
                        Some(Ok(b'M')) => {
                            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
                            let cb = iter.next().unwrap().unwrap() as i8 - 32;
                            // (1, 1) are the coords for upper left.
                            let cx = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            let cy = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            Event::Mouse(match cb & 0b11 {
                                0 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Left, cx, cy)
                                    }
                                }
                                1 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                                    }
                                }
                                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                3 => MouseEvent::Release(cx, cy),
                                _ => return error,
                            })
                        },
                        Some(Ok(b'<')) => {
                            // xterm mouse encoding:
                            // ESC [ < Cb ; Cx ; Cy ; (M or m)
                            let mut buf = Vec::new();
                            let mut c = iter.next().unwrap().unwrap();
                                while match c {
                                    b'm' | b'M' => false,
                                    _ => true,
                                } {
                                    buf.push(c);
                                    c = iter.next().unwrap().unwrap();
                                }
                            let str_buf = String::from_utf8(buf).unwrap();
                            let nums = &mut str_buf.split(';');

                            let cb = nums.next().unwrap().parse::<u16>().unwrap();
                            let cx = nums.next().unwrap().parse::<u16>().unwrap();
                            let cy = nums.next().unwrap().parse::<u16>().unwrap();

                            let event = match cb {
                                0...2 | 64...65 => {
                                    let button = match cb {
                                        0 => MouseButton::Left,
                                        1 => MouseButton::Middle,
                                        2 => MouseButton::Right,
                                        64 => MouseButton::WheelUp,
                                        65 => MouseButton::WheelDown,
                                        _ => return error,
                                    };
                                    match c {
                                        b'M' => MouseEvent::Press(button, cx, cy),
                                        b'm' => MouseEvent::Release(cx, cy),
                                        _ => return error,
                                    }
                                }
                                32 => MouseEvent::Hold(cx, cy),
                                _ => return error,
                            };

                            Event::Mouse(event)
                        },
                        Some(Ok(c @ b'0'...b'9')) => {
                            // Numbered escape code.
                            let mut buf = Vec::new();
                            buf.push(c);
                            let mut c = iter.next().unwrap().unwrap();
                            // The final byte of a CSI sequence can be in the range 64-126
                            // So let's keep reading anything else.
                            while c < 64 || c > 126 {
                                buf.push(c);
                                c = iter.next().unwrap().unwrap();
                            }

                            match c {
                                // rxvt mouse encoding:
                                // ESC [ Cb ; Cx ; Cy ; M
                                b'M' => {
                                    let str_buf = String::from_utf8(buf).unwrap();
                                    let nums = &mut str_buf.split(';');

                                    let cb = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cx = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cy = nums.next().unwrap().parse::<u16>().unwrap();

                                    let event = match cb {
                                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                        35 => MouseEvent::Release(cx, cy),
                                        64 => MouseEvent::Hold(cx, cy),
                                        96 |
                                        97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                                        _ => return error,
                                    };

                                    Event::Mouse(event)
                                },
                                // Special key code.
                                b'~' => {
                                    let num: u8 = String::from_utf8(buf).unwrap().parse().unwrap();
                                    match num {
                                        1 | 7 => Event::Key(Key::Home),
                                        2 => Event::Key(Key::Insert),
                                        3 => Event::Key(Key::Delete),
                                        4 | 8 => Event::Key(Key::End),
                                        5 => Event::Key(Key::PageUp),
                                        6 => Event::Key(Key::PageDown),
                                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                                        _ => return error,
                                    }
                                },
                                _ => return error,
                            }
                        },
                        _ => return error,
                    }
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return error,
            })
        }
        Ok(b'\n') | Ok(b'\r') => Ok(Event::Key(Key::Char('\n'))),
        Ok(b'\t') => Ok(Event::Key(Key::Char('\t'))),
        Ok(b'\x7F') => Ok(Event::Key(Key::Backspace)),
        Ok(c @ b'\x01'...b'\x1A') => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        Ok(c @ b'\x1C'...b'\x1F') => {
            Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char)))
        }
        Ok(b'\0') => Ok(Event::Key(Key::Null)),
        Ok(c) => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
        Err(e) => Err(e),
    }
}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>> {
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap())
            }
            if bytes.len() >= 4 { return error; }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<commit_msg>Handles CSI `~` sequences with multiple values (#70)<commit_after>//! Mouse and key events.

use std::io::{Error, ErrorKind};
use std::ascii::AsciiExt;
use std::str;

/// An event reported by the terminal.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Event {
    /// A key press.
    Key(Key),
    /// A mouse button press, release or wheel use at specific coordinates.
    Mouse(MouseEvent),
    /// An event that cannot currently be evaluated.
    Unsupported,
}

/// A mouse related event.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseEvent {
    /// A mouse button was pressed.
    ///
    /// The coordinates are one-based.
    Press(MouseButton, u16, u16),
    /// A mouse button was released.
    ///
    /// The coordinates are one-based.
    Release(u16, u16),
    /// A mouse button is held over the given coordinates.
    ///
    /// The coordinates are one-based.
    Hold(u16, u16),
}

/// A mouse button.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MouseButton {
    /// The left mouse button.
    Left,
    /// The right mouse button.
    Right,
    /// The middle mouse button.
    Middle,
    /// Mouse wheel is going up.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelUp,
    /// Mouse wheel is going down.
    ///
    /// This event is typically only used with Mouse::Press.
    WheelDown,
}

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Null byte.
    Null,
    /// Esc key.
    Esc,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: Result<u8, Error>, iter: &mut I) -> Result<Event, Error>
where I: Iterator<Item = Result<u8, Error>>
{
    let error = Err(Error::new(ErrorKind::Other, "Could not parse an event"));
    match item {
        Ok(b'\x1B') => {
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return error,
                    }
                }
                Some(Ok(b'[')) => {
                    match iter.next() {
                        Some(Ok(b'D')) => Event::Key(Key::Left),
                        Some(Ok(b'C')) => Event::Key(Key::Right),
                        Some(Ok(b'A')) => Event::Key(Key::Up),
                        Some(Ok(b'B')) => Event::Key(Key::Down),
                        Some(Ok(b'H')) => Event::Key(Key::Home),
                        Some(Ok(b'F')) => Event::Key(Key::End),
                        Some(Ok(b'M')) => {
                            // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
                            let cb = iter.next().unwrap().unwrap() as i8 - 32;
                            // (1, 1) are the coords for upper left.
                            let cx = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            let cy = (iter.next().unwrap().unwrap() as u8).saturating_sub(32) as u16;
                            Event::Mouse(match cb & 0b11 {
                                0 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelUp, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Left, cx, cy)
                                    }
                                }
                                1 => {
                                    if cb & 0x40 != 0 {
                                        MouseEvent::Press(MouseButton::WheelDown, cx, cy)
                                    } else {
                                        MouseEvent::Press(MouseButton::Middle, cx, cy)
                                    }
                                }
                                2 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                3 => MouseEvent::Release(cx, cy),
                                _ => return error,
                            })
                        },
                        Some(Ok(b'<')) => {
                            // xterm mouse encoding:
                            // ESC [ < Cb ; Cx ; Cy ; (M or m)
                            let mut buf = Vec::new();
                            let mut c = iter.next().unwrap().unwrap();
                                while match c {
                                    b'm' | b'M' => false,
                                    _ => true,
                                } {
                                    buf.push(c);
                                    c = iter.next().unwrap().unwrap();
                                }
                            let str_buf = String::from_utf8(buf).unwrap();
                            let nums = &mut str_buf.split(';');

                            let cb = nums.next().unwrap().parse::<u16>().unwrap();
                            let cx = nums.next().unwrap().parse::<u16>().unwrap();
                            let cy = nums.next().unwrap().parse::<u16>().unwrap();

                            let event = match cb {
                                0...2 | 64...65 => {
                                    let button = match cb {
                                        0 => MouseButton::Left,
                                        1 => MouseButton::Middle,
                                        2 => MouseButton::Right,
                                        64 => MouseButton::WheelUp,
                                        65 => MouseButton::WheelDown,
                                        _ => return error,
                                    };
                                    match c {
                                        b'M' => MouseEvent::Press(button, cx, cy),
                                        b'm' => MouseEvent::Release(cx, cy),
                                        _ => return error,
                                    }
                                }
                                32 => MouseEvent::Hold(cx, cy),
                                _ => return error,
                            };

                            Event::Mouse(event)
                        },
                        Some(Ok(c @ b'0'...b'9')) => {
                            // Numbered escape code.
                            let mut buf = Vec::new();
                            buf.push(c);
                            let mut c = iter.next().unwrap().unwrap();
                            // The final byte of a CSI sequence can be in the range 64-126
                            // So let's keep reading anything else.
                            while c < 64 || c > 126 {
                                buf.push(c);
                                c = iter.next().unwrap().unwrap();
                            }

                            match c {
                                // rxvt mouse encoding:
                                // ESC [ Cb ; Cx ; Cy ; M
                                b'M' => {
                                    let str_buf = String::from_utf8(buf).unwrap();
                                    let nums = &mut str_buf.split(';');

                                    let cb = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cx = nums.next().unwrap().parse::<u16>().unwrap();
                                    let cy = nums.next().unwrap().parse::<u16>().unwrap();

                                    let event = match cb {
                                        32 => MouseEvent::Press(MouseButton::Left, cx, cy),
                                        33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
                                        34 => MouseEvent::Press(MouseButton::Right, cx, cy),
                                        35 => MouseEvent::Release(cx, cy),
                                        64 => MouseEvent::Hold(cx, cy),
                                        96 |
                                        97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
                                        _ => return error,
                                    };

                                    Event::Mouse(event)
                                },
                                // Special key code.
                                b'~' => {
                                    let str_buf = String::from_utf8(buf).unwrap();

                                    // This CSI sequence can be a list of
                                    // semicolon-separated numbers.
                                    let nums: Vec<u8> = str_buf.split(';')
                                        .map(|n| n.parse().unwrap())
                                        .collect();

                                    if nums.is_empty() {
                                        return error;
                                    }

                                    // TODO: handle multiple values for key modififiers
                                    // (ex: values [3, 2] means Shift+Delete)
                                    match nums[0] {
                                        1 | 7 => Event::Key(Key::Home),
                                        2 => Event::Key(Key::Insert),
                                        3 => Event::Key(Key::Delete),
                                        4 | 8 => Event::Key(Key::End),
                                        5 => Event::Key(Key::PageUp),
                                        6 => Event::Key(Key::PageDown),
                                        v @ 11...15 => Event::Key(Key::F(v - 10)),
                                        v @ 17...21 => Event::Key(Key::F(v - 11)),
                                        v @ 23...24 => Event::Key(Key::F(v - 12)),
                                        _ => return error,
                                    }
                                },
                                _ => return error,
                            }
                        },
                        _ => return error,
                    }
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter);
                    Event::Key(Key::Alt(try!(ch)))
                }
                Some(Err(_)) | None => return error,
            })
        }
        Ok(b'\n') | Ok(b'\r') => Ok(Event::Key(Key::Char('\n'))),
        Ok(b'\t') => Ok(Event::Key(Key::Char('\t'))),
        Ok(b'\x7F') => Ok(Event::Key(Key::Backspace)),
        Ok(c @ b'\x01'...b'\x1A') => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        Ok(c @ b'\x1C'...b'\x1F') => {
            Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char)))
        }
        Ok(b'\0') => Ok(Event::Key(Key::Null)),
        Ok(c) => {
            Ok({
                let ch = parse_utf8_char(c, iter);
                Event::Key(Key::Char(try!(ch)))
            })
        }
        Err(e) => Err(e),
    }
}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error>
    where I: Iterator<Item = Result<u8, Error>> {
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap())
            }
            if bytes.len() >= 4 { return error; }
        }
    }
}

#[cfg(test)]
#[test]
fn test_parse_utf8() {
    let st = "abcéŷ¤£€ù%323";
    let ref mut bytes = st.bytes().map(|x| Ok(x));
    let chars = st.chars();
    for c in chars {
        let b = bytes.next().unwrap().unwrap();
        assert!(c == parse_utf8_char(b, bytes).unwrap());
    }
}
<|endoftext|>


<commit_before>//! Field utils

use std::marker::PhantomData;

/// Represents the field of a struct
///
/// Created with the `field!` macro.
pub struct Field<T> {
    offs: usize,
    size: usize,
    phantom: PhantomData<T>,
}

impl<T> Field<T> {
    /// Gets the offset of the field
    pub const fn offs(&self) -> usize {
        self.offs
    }
    /// Gets the size of the field
    pub const fn size(&self) -> usize {
        self.size
    }
}

#[doc(hidden)]
pub fn _hidden_field<T>(offs: usize, _: usize, _: Option<&T>) -> Field<T> {
    Field {
        offs,
        size: std::mem::size_of::<T>(),
        phantom: PhantomData,
    }
}

/// A macro to create a `Field`.
#[macro_export]
macro_rules! field {
    ($struct_name:ident, $field_name:ident) => {{
        let opt = None::<&$struct_name>.map(|v| &v.$field_name);
        let offs = $crate::__glium_offset_of!($struct_name, $field_name);
        $crate::field::_hidden_field(offs, 0, opt)
    }};
}
<commit_msg>Remove size parameter.<commit_after>//! Field utils

use std::marker::PhantomData;

/// Represents the field of a struct
///
/// Created with the `field!` macro.
pub struct Field<T> {
    offs: usize,
    size: usize,
    phantom: PhantomData<T>,
}

impl<T> Field<T> {
    /// Gets the offset of the field
    pub const fn offs(&self) -> usize {
        self.offs
    }
    /// Gets the size of the field
    pub const fn size(&self) -> usize {
        self.size
    }
}

#[doc(hidden)]
pub fn _hidden_field<T>(offs: usize, _: Option<&T>) -> Field<T> {
    Field {
        offs,
        size: std::mem::size_of::<T>(),
        phantom: PhantomData,
    }
}

/// A macro to create a `Field`.
#[macro_export]
macro_rules! field {
    ($struct_name:ident, $field_name:ident) => {{
        let opt = None::<&$struct_name>.map(|v| &v.$field_name);
        let offs = $crate::__glium_offset_of!($struct_name, $field_name);
        $crate::field::_hidden_field(offs, opt)
    }};
}
<|endoftext|>