<commit_before>/// Internal metric representation
///
use std::fmt;
use std::str::FromStr;

/// Enum of metric types
pub enum MetricKind {
    Counter(f64), // sample rate
    Gauge,
    Timer,
}

impl fmt::Debug for MetricKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MetricKind::Gauge      => write!(f, "Gauge"),
            MetricKind::Timer      => write!(f, "Timer"),
            MetricKind::Counter(s) => write!(f, "Counter(s={})", s)
        }
    }
}

/// Error types for parsing Metrics from strings.
///
pub enum ParseError {
    // Error message, column
    SyntaxError(&'static str, usize)
}

/// Metric value objects.
///
#[derive(Debug)]
pub struct Metric {
    kind: MetricKind,
    name: String,
    value: f64
}

impl Metric {
    fn new(name: &str, value: f64, kind: MetricKind) -> Metric {
        Metric{name: name.to_string(), value: value, kind: kind}
    }
}

impl FromStr for Metric {
    type Err = ParseError;

    /// Valid message formats are:
    ///
    /// - `<str:metric_name>:<f64:value>|<str:type>`
    /// - `<str:metric_name>:<f64:value>|c|@<f64:sample_rate>`
    fn from_str(line: &str) -> Result<Metric, ParseError> {
        // Get the metric name
        let name_parts: Vec<&str> = line.split(':').collect();
        if name_parts.len() < 2 || name_parts[0].is_empty() {
            return Err(ParseError::SyntaxError(
                    "Metrics require a name.",
                    0))
        }
        let name = name_parts[0].to_string();

        // Get the float val
        let val_parts: Vec<&str> = name_parts[1].split('|').collect();
        if val_parts.len() < 2 || val_parts[0].is_empty() {
            return Err(ParseError::SyntaxError(
                    "Metrics require a value.",
                    name.len()))
        }
        let value = val_parts[0].parse::<f64>().ok().unwrap();

        // Get kind parts
        let kind = match val_parts[1] {
            "ms" => MetricKind::Timer,
            "g" => MetricKind::Gauge,
            "c" => {
                let mut rate:f64 = 1.0;
                if val_parts.len() == 3 {
                    rate = val_parts[2].trim_left_matches('@')
                        .parse::<f64>().ok().unwrap();
                }
                MetricKind::Counter(rate)
            }
            _ => return Err(ParseError::SyntaxError(
                    "Unknown metric type.",
                    2))
        };

        Ok(Metric{name: name, value: value, kind: kind})
    }
}

//
// Tests
//
#[cfg(test)]
mod test {
    use metric::{Metric,MetricKind};
    use std::str::FromStr;
    use std::collections::HashMap;

    #[test]
    fn test_metric_kind_debug_fmt() {
        assert_eq!(
            "Gauge",
            format!("{:?}", MetricKind::Gauge)
        );
        assert_eq!(
            "Timer",
            format!("{:?}", MetricKind::Timer)
        );
        assert_eq!(
            "Counter(s=6)",
            format!("{:?}", MetricKind::Counter(6.0))
        );
    }

    #[test]
    fn test_metric_from_str_invalid_no_name() {
        let res = Metric::from_str("");
        assert!(res.is_err(), "Should have an error");
        assert!(!res.is_ok(), "Should have an error");
    }

    #[test]
    fn test_metric_from_str_invalid_no_value() {
        let res = Metric::from_str("foo:");
        assert!(res.is_err(), "Should have an error");
        assert!(!res.is_ok(), "Should have an error");
    }

    #[test]
    fn test_metric_valid() {
        let mut valid = HashMap::new();
        valid.insert(
            "foo.test:12.3|ms",
            Metric::new("foo.test", 12.3, MetricKind::Timer)
        );
        valid.insert(
            "test:18.123|g",
            Metric::new("test", 18.123, MetricKind::Gauge)
        );
        valid.insert(
            "test:18.123|g",
            Metric::new("test", 18.123, MetricKind::Gauge)
        );
        valid.insert(
            "thing.total:12|c",
            Metric::new("thing.total", 12.0, MetricKind::Counter(1.0))
        );
        valid.insert(
            "thing.total:5.6|c|@123",
            Metric::new("thing.total", 5.6, MetricKind::Counter(123.0))
        );

        for (input, expected) in valid.iter() {
            let result = Metric::from_str(*input);
            assert!(result.is_ok());

            let actual = result.ok().unwrap();
            assert_eq!(expected.name, actual.name);
            assert_eq!(expected.value, actual.value);

            // TODO this is stupid, there must be a better way.
            assert_eq!(
                format!("{:?}", expected.kind),
                format!("{:?}", actual.kind)
            );
        }
    }

    #[test]
    fn test_metric_invalid() {
        let invalid = vec![
            "",
            "metric",
            "metric|12",
            "metric:13|",
            "metric:14|c@1",
            ":|@",
            ":1.0|c"
        ];
        for input in invalid.iter() {
            let result = Metric::from_str(*input);
            assert!(result.is_err());
        }
    }
}
<commit_msg>Allow newlines in metric names.<commit_after>/// Internal metric representation
///
use std::fmt;
use std::str::FromStr;

/// Enum of metric types
pub enum MetricKind {
    Counter(f64), // sample rate
    Gauge,
    Timer,
}

impl fmt::Debug for MetricKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MetricKind::Gauge      => write!(f, "Gauge"),
            MetricKind::Timer      => write!(f, "Timer"),
            MetricKind::Counter(s) => write!(f, "Counter(s={})", s)
        }
    }
}

/// Error types for parsing Metrics from strings.
///
#[derive(Debug)]
pub enum ParseError {
    // Error message, column
    SyntaxError(&'static str, usize)
}

/// Metric value objects.
///
#[derive(Debug)]
pub struct Metric {
    kind: MetricKind,
    name: String,
    value: f64
}

impl Metric {
    fn new(name: &str, value: f64, kind: MetricKind) -> Metric {
        Metric{name: name.to_string(), value: value, kind: kind}
    }
}

impl FromStr for Metric {
    type Err = ParseError;

    /// Valid message formats are:
    ///
    /// - `<str:metric_name>:<f64:value>|<str:type>`
    /// - `<str:metric_name>:<f64:value>|c|@<f64:sample_rate>`
    fn from_str(line: &str) -> Result<Metric, ParseError> {
        // Get the metric name
        let name_parts: Vec<&str> = line.trim_right_matches('\n')
            .split(':')
            .collect();
        if name_parts.len() < 2 || name_parts[0].is_empty() {
            return Err(ParseError::SyntaxError(
                    "Metrics require a name.",
                    0))
        }
        let name = name_parts[0].to_string();

        // Get the float val
        let val_parts: Vec<&str> = name_parts[1].split('|').collect();
        if val_parts.len() < 2 || val_parts[0].is_empty() {
            return Err(ParseError::SyntaxError(
                    "Metrics require a value.",
                    name.len()))
        }
        let value = val_parts[0].parse::<f64>().ok().unwrap();

        // Get kind parts
        let kind = match val_parts[1] {
            "ms" => MetricKind::Timer,
            "g" => MetricKind::Gauge,
            "c" => {
                let mut rate:f64 = 1.0;
                if val_parts.len() == 3 {
                    rate = val_parts[2].trim_left_matches('@')
                        .parse::<f64>().ok().unwrap();
                }
                MetricKind::Counter(rate)
            }
            _ => return Err(ParseError::SyntaxError(
                    "Unknown metric type.",
                    2))
        };

        Ok(Metric{name: name, value: value, kind: kind})
    }
}

//
// Tests
//
#[cfg(test)]
mod test {
    use metric::{Metric,MetricKind};
    use std::str::FromStr;
    use std::collections::HashMap;

    #[test]
    fn test_metric_kind_debug_fmt() {
        assert_eq!(
            "Gauge",
            format!("{:?}", MetricKind::Gauge)
        );
        assert_eq!(
            "Timer",
            format!("{:?}", MetricKind::Timer)
        );
        assert_eq!(
            "Counter(s=6)",
            format!("{:?}", MetricKind::Counter(6.0))
        );
    }

    #[test]
    fn test_metric_from_str_invalid_no_name() {
        let res = Metric::from_str("");
        assert!(res.is_err(), "Should have an error");
        assert!(!res.is_ok(), "Should have an error");
    }

    #[test]
    fn test_metric_from_str_invalid_no_value() {
        let res = Metric::from_str("foo:");
        assert!(res.is_err(), "Should have an error");
        assert!(!res.is_ok(), "Should have an error");
    }

    #[test]
    fn test_metric_valid() {
        let mut valid = HashMap::new();
        valid.insert(
            "foo.test:12.3|ms\n",
            Metric::new("foo.test", 12.3, MetricKind::Timer)
        );
        valid.insert(
            "foo.test:12.3|ms",
            Metric::new("foo.test", 12.3, MetricKind::Timer)
        );
        valid.insert(
            "test:18.123|g",
            Metric::new("test", 18.123, MetricKind::Gauge)
        );
        valid.insert(
            "test:18.123|g",
            Metric::new("test", 18.123, MetricKind::Gauge)
        );
        valid.insert(
            "thing.total:12|c",
            Metric::new("thing.total", 12.0, MetricKind::Counter(1.0))
        );
        valid.insert(
            "thing.total:5.6|c|@123",
            Metric::new("thing.total", 5.6, MetricKind::Counter(123.0))
        );

        for (input, expected) in valid.iter() {
            let result = Metric::from_str(*input);
            assert!(result.is_ok());

            let actual = result.ok().unwrap();
            assert_eq!(expected.name, actual.name);
            assert_eq!(expected.value, actual.value);

            // TODO this is stupid, there must be a better way.
            assert_eq!(
                format!("{:?}", expected.kind),
                format!("{:?}", actual.kind)
            );
        }
    }

    #[test]
    fn test_metric_invalid() {
        let invalid = vec![
            "",
            "metric",
            "metric|12",
            "metric:13|",
            "metric:14|c@1",
            ":|@",
            ":1.0|c"
        ];
        for input in invalid.iter() {
            let result = Metric::from_str(*input);
            assert!(result.is_err());
        }
    }
}
<|endoftext|>


<commit_before>pub mod responses {

    use std::fmt;

    use serde;
    use serde_json as json;

    #[derive(Deserialize, Debug)]
    pub struct AuthResponse {
        pub session: SessionResponse,
    }

    #[derive(Deserialize, Debug, Clone)]
    pub struct SessionResponse {
        pub key: String,
        pub subscriber: i64,
        pub name: String,
    }

    #[derive(Deserialize)]
    pub struct NowPlayingResponseWrapper {
        pub nowplaying: NowPlayingResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct NowPlayingResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename="albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
    }

    #[derive(Deserialize)]
    pub struct ScrobbleResponseWrapper {
        pub scrobbles: Scrobbles,
    }

    #[derive(Deserialize)]
    pub struct Scrobbles {
        pub scrobble: ScrobbleResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct ScrobbleResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename="albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
        pub timestamp: String,
    }

    #[derive(Deserialize, Debug)]
    pub struct CorrectableString {
        #[serde(deserialize_with="CorrectableString::deserialize_corrected_field")]
        pub corrected: bool,
        #[serde(rename="#text", default)]
        pub text: String,
    }

    impl CorrectableString {
        fn deserialize_corrected_field<'de, D>(de: D) -> Result<bool, D::Error>
            where D: serde::Deserializer<'de>
        {
            let deser_result: json::Value = try!(serde::Deserialize::deserialize(de));
            match deser_result {
                json::Value::String(ref s) if &*s == "1" => Ok(true),
                json::Value::String(ref s) if &*s == "0" => Ok(false),
                _ => Err(serde::de::Error::custom("Unexpected value")),
            }
        }
    }

    impl fmt::Display for CorrectableString {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.text)
        }
    }

}

pub mod metadata {

    use std::collections::HashMap;

    pub struct Scrobble {
        artist: String,
        track: String,
        album: Option<String>,
    }

    impl Scrobble {

        pub fn new(artist: String, track: String, album: Option<String>) -> Scrobble {
            Scrobble{ artist: artist, track: track, album: album }
        }

        pub fn as_map(&self) -> HashMap<&str, String> {
            let mut params = HashMap::new();
            params.insert("track", self.track.clone());
            params.insert("artist", self.artist.clone());
            params.insert("album", self.album.clone());

            params
        }

    }

}<commit_msg>Make album field mandatory in Scrobble<commit_after>pub mod responses {

    use std::fmt;

    use serde;
    use serde_json as json;

    #[derive(Deserialize, Debug)]
    pub struct AuthResponse {
        pub session: SessionResponse,
    }

    #[derive(Deserialize, Debug, Clone)]
    pub struct SessionResponse {
        pub key: String,
        pub subscriber: i64,
        pub name: String,
    }

    #[derive(Deserialize)]
    pub struct NowPlayingResponseWrapper {
        pub nowplaying: NowPlayingResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct NowPlayingResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename="albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
    }

    #[derive(Deserialize)]
    pub struct ScrobbleResponseWrapper {
        pub scrobbles: Scrobbles,
    }

    #[derive(Deserialize)]
    pub struct Scrobbles {
        pub scrobble: ScrobbleResponse,
    }

    #[derive(Deserialize, Debug)]
    pub struct ScrobbleResponse {
        pub artist: CorrectableString,
        pub album: CorrectableString,
        #[serde(rename="albumArtist")]
        pub album_artist: CorrectableString,
        pub track: CorrectableString,
        pub timestamp: String,
    }

    #[derive(Deserialize, Debug)]
    pub struct CorrectableString {
        #[serde(deserialize_with="CorrectableString::deserialize_corrected_field")]
        pub corrected: bool,
        #[serde(rename="#text", default)]
        pub text: String,
    }

    impl CorrectableString {
        fn deserialize_corrected_field<'de, D>(de: D) -> Result<bool, D::Error>
            where D: serde::Deserializer<'de>
        {
            let deser_result: json::Value = try!(serde::Deserialize::deserialize(de));
            match deser_result {
                json::Value::String(ref s) if &*s == "1" => Ok(true),
                json::Value::String(ref s) if &*s == "0" => Ok(false),
                _ => Err(serde::de::Error::custom("Unexpected value")),
            }
        }
    }

    impl fmt::Display for CorrectableString {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.text)
        }
    }

}

pub mod metadata {

    use std::collections::HashMap;

    pub struct Scrobble {
        artist: String,
        track: String,
        album: String
    }

    impl Scrobble {

        pub fn new(artist: String, track: String, album: String) -> Scrobble {
            Scrobble{ artist: artist, track: track, album: album }
        }

        pub fn as_map(&self) -> HashMap<&str, String> {
            let mut params = HashMap::new();
            params.insert("track", self.track.clone());
            params.insert("artist", self.artist.clone());
            params.insert("album", self.album.clone());

            params
        }

    }

}<|endoftext|>


<commit_before>use serde_json;
use std::collections::BTreeMap;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::BufReader;
use std::path::Path;

use search::SearchIndex;

#[derive(Deserialize, Debug)]
pub struct User {
    // NOTE: when changing these fields, be sure to update
    // `.remove_empty_strings()` and `.with_str_fields()` below
    pub name: Option<String>,
    pub irc: Option<String>,
    #[serde(default)]
    pub irc_channels: Vec<String>,
    #[serde(default)]
    pub show_avatar: bool,
    pub email: Option<String>,
    pub discourse: Option<String>,
    pub reddit: Option<String>,
    pub twitter: Option<String>,
    pub blog: Option<String>,
    pub website: Option<String>,
    pub notes: Option<String>,
}

impl User {
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<User, serde_json::Error> {
        let reader = BufReader::new(File::open(path)?);
        let mut user: User = serde_json::from_reader(reader)?;
        user.remove_empty_strings();
        Ok(user)
    }

    /// Some users use empty strings to mean "not applicable", instead of using
    /// `null` or omitting the field as they should be doing. We fix up their
    /// carelessness here.
    fn remove_empty_strings(&mut self) {
        macro_rules! fixup {
            ($($field:ident)*) => {
                $(
                    // If the field is just whitespace, replace it with `None`
                    // This boolean dance is needed to satisfy borrowck
                    let should_replace = match self.$field {
                        Some(ref s) if is_whitespace(s) => true,
                        _ => false,
                    };
                    if should_replace {
                        self.$field = None;
                    }
                )*
            }
        }
        fixup!(name irc email discourse reddit twitter blog website notes);
    }

    /// Applies the given callback to every searchable field in this entry.
    ///
    /// Used by the full-text search machinery.
    fn with_str_fields<F>(&self, mut callback: F) where F: FnMut(&str, u64) {
        macro_rules! callme {
            ($callback:ident, $($field:ident ($weight:expr))*) => {
                $(
                    if let Some(ref s) = self.$field {
                        $callback(s, $weight);
                    }
                )*
            }
        }
        callme!(
            callback,
            // Give names more weight than URLs and notes
            name(20) irc(10) email(1) discourse(10) reddit(10)
            twitter(10) blog(1) website(1) notes(1)
            );
        for channel in &self.irc_channels {
            callback(channel, 1);
        }
    }
}

fn is_whitespace(s: &str) -> bool {
    s.chars().all(char::is_whitespace)
}

#[derive(Debug)]
pub struct Users {
    data: BTreeMap<String, Result<User, String>>,
    index: SearchIndex<String>,
}

impl Users {
    pub fn load<P: AsRef<Path>>(base: P) -> Result<Users, serde_json::Error> {
        let mut data = BTreeMap::new();
        for entry in fs::read_dir(base)? {
            let path = entry?.path();
            if path.extension() == Some(OsStr::new("json")) {
                let id = path.file_stem().unwrap().to_string_lossy().into_owned();
                // Some users' entries actually fail to parse!
                // Instead of bailing on these, just record the error and move on.
                let user = User::from_path(&path).map_err(|e| {
                    warn!("could not parse entry for {}: {}", id, e);
                    e.to_string()
                });
                data.insert(id, user);
            }
        }
        let mut index = SearchIndex::new();
        for (id, user) in &data {
            index.add(id.clone(), id, 10);
            if let Ok(ref user) = *user {
                user.with_str_fields(|s, w| index.add(id.clone(), s, w));
            }
        }
        info!("loaded {} rustaceans", data.len());
        Ok(Users { data: data, index: index })
    }

    pub fn get(&self, id: &str) -> Option<Result<&User, &str>> {
        self.data.get(id).map(|r| r.as_ref().map_err(|e| &e[..]))
    }

    pub fn search(&self, query: &str) -> (Vec<(String, u64)>, Option<String>) {
        self.index.query(query)
    }
}

#[test]
fn smoke() {
    const DATA: &'static str = r#"
        {
            "name": "Bors",
            "show_avatar": true,
            "irc": "bors",
            "irc_channels": ["rust", "rust-bots"],
            "website": "http://rust-lang.org/"
        }
    "#;
    let _: User = serde_json::from_str(DATA).unwrap();
}
<commit_msg>Remove extraneous '#' chars from IRC channel field<commit_after>use serde_json;
use std::collections::BTreeMap;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::BufReader;
use std::path::Path;

use search::SearchIndex;

#[derive(Deserialize, Debug)]
pub struct User {
    // NOTE: when changing these fields, be sure to update
    // `.remove_empty_strings()` and `.with_str_fields()` below
    pub name: Option<String>,
    pub irc: Option<String>,
    #[serde(default)]
    pub irc_channels: Vec<String>,
    #[serde(default)]
    pub show_avatar: bool,
    pub email: Option<String>,
    pub discourse: Option<String>,
    pub reddit: Option<String>,
    pub twitter: Option<String>,
    pub blog: Option<String>,
    pub website: Option<String>,
    pub notes: Option<String>,
}

impl User {
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<User, serde_json::Error> {
        let reader = BufReader::new(File::open(path)?);
        let mut user: User = serde_json::from_reader(reader)?;
        user.remove_empty_strings();
        for channel in &mut user.irc_channels {
            if channel.starts_with("#") {
                *channel = channel.trim_left_matches('#').to_string();
            }
        }
        Ok(user)
    }

    /// Some users use empty strings to mean "not applicable", instead of using
    /// `null` or omitting the field as they should be doing. We fix up their
    /// carelessness here.
    fn remove_empty_strings(&mut self) {
        macro_rules! fixup {
            ($($field:ident)*) => {
                $(
                    // If the field is just whitespace, replace it with `None`
                    // This boolean dance is needed to satisfy borrowck
                    let should_replace = match self.$field {
                        Some(ref s) if is_whitespace(s) => true,
                        _ => false,
                    };
                    if should_replace {
                        self.$field = None;
                    }
                )*
            }
        }
        fixup!(name irc email discourse reddit twitter blog website notes);
    }

    /// Applies the given callback to every searchable field in this entry.
    ///
    /// Used by the full-text search machinery.
    fn with_str_fields<F>(&self, mut callback: F) where F: FnMut(&str, u64) {
        macro_rules! callme {
            ($callback:ident, $($field:ident ($weight:expr))*) => {
                $(
                    if let Some(ref s) = self.$field {
                        $callback(s, $weight);
                    }
                )*
            }
        }
        callme!(
            callback,
            // Give names more weight than URLs and notes
            name(20) irc(10) email(1) discourse(10) reddit(10)
            twitter(10) blog(1) website(1) notes(1)
            );
        for channel in &self.irc_channels {
            callback(channel, 1);
        }
    }
}

fn is_whitespace(s: &str) -> bool {
    s.chars().all(char::is_whitespace)
}

#[derive(Debug)]
pub struct Users {
    data: BTreeMap<String, Result<User, String>>,
    index: SearchIndex<String>,
}

impl Users {
    pub fn load<P: AsRef<Path>>(base: P) -> Result<Users, serde_json::Error> {
        let mut data = BTreeMap::new();
        for entry in fs::read_dir(base)? {
            let path = entry?.path();
            if path.extension() == Some(OsStr::new("json")) {
                let id = path.file_stem().unwrap().to_string_lossy().into_owned();
                // Some users' entries actually fail to parse!
                // Instead of bailing on these, just record the error and move on.
                let user = User::from_path(&path).map_err(|e| {
                    warn!("could not parse entry for {}: {}", id, e);
                    e.to_string()
                });
                data.insert(id, user);
            }
        }
        let mut index = SearchIndex::new();
        for (id, user) in &data {
            index.add(id.clone(), id, 10);
            if let Ok(ref user) = *user {
                user.with_str_fields(|s, w| index.add(id.clone(), s, w));
            }
        }
        info!("loaded {} rustaceans", data.len());
        Ok(Users { data: data, index: index })
    }

    pub fn get(&self, id: &str) -> Option<Result<&User, &str>> {
        self.data.get(id).map(|r| r.as_ref().map_err(|e| &e[..]))
    }

    pub fn search(&self, query: &str) -> (Vec<(String, u64)>, Option<String>) {
        self.index.query(query)
    }
}

#[test]
fn smoke() {
    const DATA: &'static str = r#"
        {
            "name": "Bors",
            "show_avatar": true,
            "irc": "bors",
            "irc_channels": ["rust", "rust-bots"],
            "website": "http://rust-lang.org/"
        }
    "#;
    let _: User = serde_json::from_str(DATA).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Object wrapper implementation and `Object` binding.

use translate::*;
use types::{self, StaticType};
use wrapper::{UnsafeFrom, Wrapper};
use gobject_ffi;

/// Upcasting and downcasting support.
///
/// Provides conversions up and down the class hierarchy tree.
pub trait Cast: IsA<Object> {
    /// Upcasts an object to a superclass or interface `T`.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let button = gtk::Button::new();
    /// let widget = button.upcast::<gtk::Widget>();
    /// ```
    #[inline]
    fn upcast<T>(self) -> T
    where T: StaticType + UnsafeFrom<ObjectRef> + Wrapper,
          Self: IsA<T> {
        unsafe { T::from(self.into()) }
    }

    /// Tries to downcast to a subclass or interface implementor `T`.
    ///
    /// Returns `Ok(T)` if the object is an instance of `T` and `Err(self)`
    /// otherwise.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let button = gtk::Button::new();
    /// let widget = button.upcast::<gtk::Widget>();
    /// assert!(widget.downcast::<gtk::Button>().is_ok());
    /// ```
    #[inline]
    fn downcast<T>(self) -> Result<T, Self>
    where Self: Sized + Downcast<T> {
        Downcast::downcast(self)
    }

    /// Returns `true` if the object is an instance of (can be downcast to) `T`.
    fn is<T>(&self) -> bool where Self: Downcast<T> {
        Downcast::can_downcast(self)
    }
}

impl<T: IsA<Object>> Cast for T { }

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T`.
///
/// For instance, since originally `GtkWidget` is a subclass of `GObject` and
/// implements the `GtkBuildable` interface, `gtk::Widget` implements
/// `IsA<glib::Object>` and `IsA<gtk::Buildable>`.
///
///
/// The trait can only be implemented if the appropriate `ToGlibPtr`
/// implementations exist.
///
/// `T` always implements `IsA<T>`.
pub trait IsA<T: StaticType + UnsafeFrom<ObjectRef> + Wrapper>: StaticType + Wrapper +
    Into<ObjectRef> + UnsafeFrom<ObjectRef> +
    for<'a> ToGlibPtr<'a, *mut <T as Wrapper>::GlibType> { }

impl<T> IsA<T> for T
where T: StaticType + Wrapper + Into<ObjectRef> + UnsafeFrom<ObjectRef> +
    for<'a> ToGlibPtr<'a, *mut <T as Wrapper>::GlibType> { }

/// Downcasts support.
pub trait Downcast<T> {
    /// Checks if it's possible to downcast to `T`.
    ///
    /// Returns `true` if the instance implements `T` and `false` otherwise.
    fn can_downcast(&self) -> bool;
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self> where Self: Sized;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`.
    unsafe fn downcast_unchecked(self) -> T;
}

impl<Super: IsA<Super>, Sub: IsA<Super>> Downcast<Sub> for Super {
    #[inline]
    fn can_downcast(&self) -> bool {
        types::instance_of::<Sub>(self.to_glib_none().0 as *const _)
    }

    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        unsafe {
            if !types::instance_of::<Sub>(self.to_glib_none().0 as *const _) {
                return Err(self);
            }
            Ok(Sub::from(self.into()))
        }
    }

    #[inline]
    unsafe fn downcast_unchecked(self) -> Sub {
        debug_assert!(types::instance_of::<Sub>(self.to_glib_none().0 as *const _));
        Sub::from(self.into())
    }
}

#[doc(hidden)]
pub use gobject_ffi::GObject;

glib_wrapper! {
    #[doc(hidden)]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct ObjectRef(Shared<GObject>);

    match fn {
        ref => |ptr| gobject_ffi::g_object_ref(ptr),
        unref => |ptr| gobject_ffi::g_object_unref(ptr),
    }
}

/// Wrapper implementations for Object types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_object_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug, Hash)]
        pub struct $name($crate::object::ObjectRef, ::std::marker::PhantomData<$ffi_name>);

        #[doc(hidden)]
        impl Into<$crate::object::ObjectRef> for $name {
            fn into(self) -> $crate::object::ObjectRef {
                self.0
            }
        }

        #[doc(hidden)]
        impl $crate::wrapper::UnsafeFrom<$crate::object::ObjectRef> for $name {
            unsafe fn from(t: $crate::object::ObjectRef) -> Self {
                $name(t, ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        #[doc(hidden)]
        impl $crate::wrapper::Wrapper for $name {
            type GlibType = $ffi_name;
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *const _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *const $ffi_name {
                self.0.to_glib_full() as *const _
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $ffi_name {
                self.0.to_glib_full() as *mut _
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_none(ptr as *mut _), ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_full(ptr as *mut _), ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_borrow(ptr as *mut _),
                      ::std::marker::PhantomData)
            }
        }

        impl $crate::types::StaticType for $name {
            fn static_type() -> $crate::types::Type {
                unsafe { $crate::translate::from_glib($get_type_expr) }
            }
        }

        impl<T: $crate::object::IsA<$crate::object::Object>> ::std::cmp::PartialEq<T> for $name {
            #[inline]
            fn eq(&self, other: &T) -> bool {
                use $crate::translate::ToGlibPtr;
                self.0.to_glib_none().0 == other.to_glib_none().0
            }
        }

        impl ::std::cmp::Eq for $name { }
    };

    (@munch_impls $name:ident, ) => { };

    (@munch_impls $name:ident, $super_name:path) => {
        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a,
                *mut <$super_name as $crate::wrapper::Wrapper>::GlibType> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a,
                    *mut <$super_name as $crate::wrapper::Wrapper>::GlibType, Self> {
                let stash = self.0.to_glib_none();
                debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self)
                    -> *mut <$super_name as $crate::wrapper::Wrapper>::GlibType {
                let ptr = self.0.to_glib_full();
                debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
                ptr as *mut _
            }
        }

        impl $crate::object::IsA<$super_name> for $name { }
    };

    (@munch_impls $name:ident, $super_name:path => $super_ffi:path) => {
        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $super_ffi> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $super_ffi, Self> {
                let stash = self.0.to_glib_none();
                debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $super_ffi {
                let ptr = self.0.to_glib_full();
                debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
                ptr as *mut _
            }
        }

        impl $crate::object::IsA<$super_name> for $name { }
    };

    (@munch_impls $name:ident, $super_name:path, $($implements:tt)*) => {
        glib_object_wrapper!(@munch_impls $name, $super_name);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);
    };

    (@munch_impls $name:ident, $super_name:path => $super_ffi:path, $($implements:tt)*) => {
        glib_object_wrapper!(@munch_impls $name, $super_name => $super_ffi);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);
    };

    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr,
     @implements $($implements:tt)*) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self)
                    -> $crate::translate::Stash<'a, *mut $crate::object::GObject, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $crate::object::GObject {
                (&self.0).to_glib_full() as *mut _
            }
        }

        impl $crate::object::IsA<$crate::object::Object> for $name { }
    };

    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr,
     [$($implements:path),*]) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr,
            @implements $($implements),*);
    }
}

glib_object_wrapper! {
    [doc = "The base class in the object hierarchy."]
    Object, GObject, @get_type gobject_ffi::g_object_get_type()
}

pub trait ObjectExt {
}

impl<T: IsA<Object>> ObjectExt for T {
}
<commit_msg>Use g_object_ref_sink() instead of g_object_ref() everywhere<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Object wrapper implementation and `Object` binding.

use translate::*;
use types::{self, StaticType};
use wrapper::{UnsafeFrom, Wrapper};
use gobject_ffi;

/// Upcasting and downcasting support.
///
/// Provides conversions up and down the class hierarchy tree.
pub trait Cast: IsA<Object> {
    /// Upcasts an object to a superclass or interface `T`.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let button = gtk::Button::new();
    /// let widget = button.upcast::<gtk::Widget>();
    /// ```
    #[inline]
    fn upcast<T>(self) -> T
    where T: StaticType + UnsafeFrom<ObjectRef> + Wrapper,
          Self: IsA<T> {
        unsafe { T::from(self.into()) }
    }

    /// Tries to downcast to a subclass or interface implementor `T`.
    ///
    /// Returns `Ok(T)` if the object is an instance of `T` and `Err(self)`
    /// otherwise.
    ///
    /// # Example
    ///
    /// ```ignore
    /// let button = gtk::Button::new();
    /// let widget = button.upcast::<gtk::Widget>();
    /// assert!(widget.downcast::<gtk::Button>().is_ok());
    /// ```
    #[inline]
    fn downcast<T>(self) -> Result<T, Self>
    where Self: Sized + Downcast<T> {
        Downcast::downcast(self)
    }

    /// Returns `true` if the object is an instance of (can be downcast to) `T`.
    fn is<T>(&self) -> bool where Self: Downcast<T> {
        Downcast::can_downcast(self)
    }
}

impl<T: IsA<Object>> Cast for T { }

/// Declares the "is a" relationship.
///
/// `Self` is said to implement `T`.
///
/// For instance, since originally `GtkWidget` is a subclass of `GObject` and
/// implements the `GtkBuildable` interface, `gtk::Widget` implements
/// `IsA<glib::Object>` and `IsA<gtk::Buildable>`.
///
///
/// The trait can only be implemented if the appropriate `ToGlibPtr`
/// implementations exist.
///
/// `T` always implements `IsA<T>`.
pub trait IsA<T: StaticType + UnsafeFrom<ObjectRef> + Wrapper>: StaticType + Wrapper +
    Into<ObjectRef> + UnsafeFrom<ObjectRef> +
    for<'a> ToGlibPtr<'a, *mut <T as Wrapper>::GlibType> { }

impl<T> IsA<T> for T
where T: StaticType + Wrapper + Into<ObjectRef> + UnsafeFrom<ObjectRef> +
    for<'a> ToGlibPtr<'a, *mut <T as Wrapper>::GlibType> { }

/// Downcasts support.
pub trait Downcast<T> {
    /// Checks if it's possible to downcast to `T`.
    ///
    /// Returns `true` if the instance implements `T` and `false` otherwise.
    fn can_downcast(&self) -> bool;
    /// Tries to downcast to `T`.
    ///
    /// Returns `Ok(T)` if the instance implements `T` and `Err(Self)` otherwise.
    fn downcast(self) -> Result<T, Self> where Self: Sized;
    /// Downcasts to `T` unconditionally.
    ///
    /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`.
    unsafe fn downcast_unchecked(self) -> T;
}

impl<Super: IsA<Super>, Sub: IsA<Super>> Downcast<Sub> for Super {
    #[inline]
    fn can_downcast(&self) -> bool {
        types::instance_of::<Sub>(self.to_glib_none().0 as *const _)
    }

    #[inline]
    fn downcast(self) -> Result<Sub, Super> {
        unsafe {
            if !types::instance_of::<Sub>(self.to_glib_none().0 as *const _) {
                return Err(self);
            }
            Ok(Sub::from(self.into()))
        }
    }

    #[inline]
    unsafe fn downcast_unchecked(self) -> Sub {
        debug_assert!(types::instance_of::<Sub>(self.to_glib_none().0 as *const _));
        Sub::from(self.into())
    }
}

#[doc(hidden)]
pub use gobject_ffi::GObject;

glib_wrapper! {
    #[doc(hidden)]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct ObjectRef(Shared<GObject>);

    match fn {
        ref => |ptr| gobject_ffi::g_object_ref_sink(ptr),
        unref => |ptr| gobject_ffi::g_object_unref(ptr),
    }
}

/// Wrapper implementations for Object types. See `glib_wrapper!`.
#[macro_export]
macro_rules! glib_object_wrapper {
    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr) => {
        $(#[$attr])*
        #[derive(Clone, Debug, Hash)]
        pub struct $name($crate::object::ObjectRef, ::std::marker::PhantomData<$ffi_name>);

        #[doc(hidden)]
        impl Into<$crate::object::ObjectRef> for $name {
            fn into(self) -> $crate::object::ObjectRef {
                self.0
            }
        }

        #[doc(hidden)]
        impl $crate::wrapper::UnsafeFrom<$crate::object::ObjectRef> for $name {
            unsafe fn from(t: $crate::object::ObjectRef) -> Self {
                $name(t, ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::GlibPtrDefault for $name {
            type GlibType = *mut $ffi_name;
        }

        #[doc(hidden)]
        impl $crate::wrapper::Wrapper for $name {
            type GlibType = $ffi_name;
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *const _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *const $ffi_name {
                self.0.to_glib_full() as *const _
            }
        }

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $ffi_name {
                self.0.to_glib_full() as *mut _
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_none(ptr as *mut _), ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_full(ptr as *mut _), ::std::marker::PhantomData)
            }
        }

        #[doc(hidden)]
        impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name {
            #[inline]
            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
                debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
                $name($crate::translate::from_glib_borrow(ptr as *mut _),
                      ::std::marker::PhantomData)
            }
        }

        impl $crate::types::StaticType for $name {
            fn static_type() -> $crate::types::Type {
                unsafe { $crate::translate::from_glib($get_type_expr) }
            }
        }

        impl<T: $crate::object::IsA<$crate::object::Object>> ::std::cmp::PartialEq<T> for $name {
            #[inline]
            fn eq(&self, other: &T) -> bool {
                use $crate::translate::ToGlibPtr;
                self.0.to_glib_none().0 == other.to_glib_none().0
            }
        }

        impl ::std::cmp::Eq for $name { }
    };

    (@munch_impls $name:ident, ) => { };

    (@munch_impls $name:ident, $super_name:path) => {
        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a,
                *mut <$super_name as $crate::wrapper::Wrapper>::GlibType> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a,
                    *mut <$super_name as $crate::wrapper::Wrapper>::GlibType, Self> {
                let stash = self.0.to_glib_none();
                debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self)
                    -> *mut <$super_name as $crate::wrapper::Wrapper>::GlibType {
                let ptr = self.0.to_glib_full();
                debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
                ptr as *mut _
            }
        }

        impl $crate::object::IsA<$super_name> for $name { }
    };

    (@munch_impls $name:ident, $super_name:path => $super_ffi:path) => {
        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $super_ffi> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $super_ffi, Self> {
                let stash = self.0.to_glib_none();
                debug_assert!($crate::types::instance_of::<$super_name>(stash.0 as *const _));
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $super_ffi {
                let ptr = self.0.to_glib_full();
                debug_assert!($crate::types::instance_of::<$super_name>(ptr as *const _));
                ptr as *mut _
            }
        }

        impl $crate::object::IsA<$super_name> for $name { }
    };

    (@munch_impls $name:ident, $super_name:path, $($implements:tt)*) => {
        glib_object_wrapper!(@munch_impls $name, $super_name);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);
    };

    (@munch_impls $name:ident, $super_name:path => $super_ffi:path, $($implements:tt)*) => {
        glib_object_wrapper!(@munch_impls $name, $super_name => $super_ffi);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);
    };

    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr,
     @implements $($implements:tt)*) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr);
        glib_object_wrapper!(@munch_impls $name, $($implements)*);

        #[doc(hidden)]
        impl<'a> $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject> for $name {
            type Storage = <$crate::object::ObjectRef as
                $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage;

            #[inline]
            fn to_glib_none(&'a self)
                    -> $crate::translate::Stash<'a, *mut $crate::object::GObject, Self> {
                let stash = self.0.to_glib_none();
                $crate::translate::Stash(stash.0 as *mut _, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut $crate::object::GObject {
                (&self.0).to_glib_full() as *mut _
            }
        }

        impl $crate::object::IsA<$crate::object::Object> for $name { }
    };

    ([$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr,
     [$($implements:path),*]) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr,
            @implements $($implements),*);
    }
}

glib_object_wrapper! {
    [doc = "The base class in the object hierarchy."]
    Object, GObject, @get_type gobject_ffi::g_object_get_type()
}

pub trait ObjectExt {
}

impl<T: IsA<Object>> ObjectExt for T {
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::option;

use ::Result;
use ::Error;

use octets;
use crypto;
use rand;

const FORM_BIT: u8 = 0x80;
const KEY_PHASE_BIT: u8 = 0x40;
const DEMUX_BIT: u8 = 0x08;

const TYPE_MASK: u8 = 0x7f;

const MAX_CID_LEN: u8 = 18;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Type {
    Initial,
    Retry,
    Handshake,
    ZeroRTT,
    VersionNegotiation,
    Application,
}

pub fn has_long_header(b: u8) -> bool {
    b & FORM_BIT != 0
}

pub fn parse_long_header(buf: &mut [u8]) -> Result<Header> {
    let mut b = octets::Bytes::new(buf);
    Header::long_from_bytes(&mut b)
}

#[derive(Clone, Debug)]
pub struct Header {
    pub ty: Type,
    pub version: u32,
    pub flags: u8,
    pub dcid: Vec<u8>,
    pub scid: Vec<u8>,
    pub token: option::Option<Vec<u8>>,
}

impl Header {
    pub fn long_from_bytes(b: &mut octets::Bytes) -> Result<Header> {
        let first = b.get_u8()?;

        if !has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let version = b.get_u32()?;

        let ty = if version == 0 {
            Type::VersionNegotiation
        } else {
            match first & TYPE_MASK {
                0x7f => Type::Initial,
                0x7e => Type::Retry,
                0x7d => Type::Handshake,
                0x7c => Type::ZeroRTT,
                _    => return Err(Error::UnknownPacket),
            }
        };

        let (dcil, scil) = match b.get_u8() {
            Ok(v) => {
                let mut dcil = v >> 4;
                let mut scil = v & 0xf;

                if dcil > MAX_CID_LEN || scil > MAX_CID_LEN {
                    return Err(Error::InvalidPacket);
                }

                if dcil > 0 {
                    dcil += 3;
                }

                if scil > 0 {
                    scil += 3;
                }

                (dcil, scil)
            },

            Err(_) => return Err(Error::BufferTooShort),
        };

        let dcid = b.get_bytes(dcil as usize)?.to_vec();
        let scid = b.get_bytes(scil as usize)?.to_vec();

        // End of invariants.

        let mut token: option::Option<Vec<u8>> = None;

        match ty {
            Type::Initial => {
                token = Some(b.get_bytes_with_varint_length()?.to_vec());
            },

            Type::Retry => {
                panic!("Retry not supported");
            },

            Type::VersionNegotiation => {
                panic!("Retry not supported");
            },

            _ => (),
        };

        Ok(Header {
            ty,
            flags: first & FORM_BIT,
            version,
            dcid,
            scid,
            token,
        })
    }

    pub fn long_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let ty: u8 = match hdr.ty {
                Type::Initial   => 0x7f,
                Type::Retry     => 0x7e,
                Type::Handshake => 0x7d,
                Type::ZeroRTT   => 0x7c,
                // TODO: unify handling of version negotiation
                _               => return Err(Error::UnknownPacket),
        };

        let first = FORM_BIT | ty;

        out.put_u8(first)?;

        out.put_u32(hdr.version)?;

        let mut cil: u8 = 0;

        if hdr.dcid.len() > 0 {
            cil |= ((hdr.dcid.len() - 3) as u8) << 4;
        }

        if hdr.scid.len() > 0 {
            cil |= ((hdr.scid.len() - 3) as u8) & 0xf;
        }

        out.put_u8(cil)?;

        out.put_bytes(&hdr.dcid)?;
        out.put_bytes(&hdr.scid)?;

        // Only Initial packet have a token.
        if hdr.ty == Type::Initial {
            match hdr.token {
                Some(ref v) => {
                    out.put_bytes(v)?;
                },

                None => {
                    // No token, so lemgth = 0.
                    out.put_varint(0)?;
                }
            }
        }

        Ok(())
    }

    pub fn short_from_bytes(b: &mut octets::Bytes, dcil: usize) -> Result<Header> {
        let first = b.get_u8()?;

        if has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let dcid = b.get_bytes(dcil)?;

        Ok(Header {
            ty: Type::Application,
            flags: first & FORM_BIT,
            version: 0,
            dcid: dcid.to_vec(),
            scid: Vec::new(),
            token: None,
        })
    }

    pub fn short_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let mut first = rand::rand_u8();

        // Unset form bit for short header.
        first &= !FORM_BIT;

        // TODO: support key update
        first &= !KEY_PHASE_BIT;

        // "The third bit (0x20) of octet 0 is set to 1."
        first |= 0x20;

        // "The fourth bit (0x10) of octet 0 is set to 1."
        first |= 0x10;

        // Clear Google QUIC demultiplexing bit
        first &= !DEMUX_BIT;

        out.put_u8(first)?;
        out.put_bytes(&hdr.dcid)?;

        Ok(())
    }
}

pub fn pkt_num_len(pn: u64) -> Result<usize> {
    let len = if pn < 128 {
        1
    } else if pn < 16384 {
        2
    } else if pn < 1_073_741_824 {
        4
    } else {
        return Err(Error::InvalidPacket);
    };

    Ok(len)
}

pub fn decrypt_pkt_num(b: &mut octets::Bytes, aead: &crypto::Open)
                                                    -> Result<(u64,usize)> {
    let mut pn_and_sample = b.peek_bytes(20)?;

    let (mut ciphertext, sample) = pn_and_sample.split_at(4).unwrap();

    let ciphertext = ciphertext.as_mut();

    // Decrypt first byte of pkt num into separate buffer to get length.
    let mut pn_len_ciphertext: [u8; 1] = [0; 1];
    pn_len_ciphertext.copy_from_slice(&ciphertext[..1]);

    aead.xor_keystream(sample.as_ref(), &mut pn_len_ciphertext)?;

    let first = pn_len_ciphertext[0];

    let len = if first >> 7 == 0 {
        1
    } else {
        // Map most significant 2 bits to actual pkt num length.
        match first >> 6 {
            2 => 2,
            3 => 4,
            _ => return Err(Error::InvalidPacket),
        }
    };

    // Decrypt full pkt num in-place.
    aead.xor_keystream(sample.as_ref(), &mut ciphertext[..len])?;

    let mut plaintext: [u8; 4] = [0; 4];
    plaintext.copy_from_slice(&ciphertext[..4]);

    // Mask the 2 most significant bits to remove the encoded length.
    if len > 1 {
        plaintext[0] &= 0x3f;
    }

    let mut b = octets::Bytes::new(&mut plaintext);

    // Extract packet number corresponding to the decoded length.
    let out = match len {
        1 => u64::from(b.get_u8()?),
        2 => u64::from(b.get_u16()?),
        4 => u64::from(b.get_u32()?),
        _ => return Err(Error::InvalidPacket),
    };

    // TODO: implement packet number truncation
    Ok((out as u64, len))
}

pub fn encode_pkt_num(pn: u64, b: &mut octets::Bytes) -> Result<()> {
    let len = pkt_num_len(pn)?;

    match len {
        1 => {
            let mut buf = b.put_u8(pn as u8)?;
            buf[0] &= !0x80;
        },

        2 => {
            let mut buf = b.put_u16(pn as u16)?;
            buf[0] &= !0xc0;
            buf[0] |= 0x80;
        },

        4 => {
            let mut buf = b.put_u32(pn as u32)?;
            buf[0] |= 0xc0;
        },

        _ => return Err(Error::InvalidPacket),
    };

    Ok(())
}

pub fn decrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Open)
                                                            -> Result<usize> {
    aead.open_with_u64_counter(pn, ad, payload)
}

pub fn encrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Seal)
                                                            -> Result<usize> {
    aead.seal_with_u64_counter(pn, ad, payload)
}

pub fn negotiate_version(hdr: &Header, out: &mut [u8]) -> Result<usize> {
    let mut b = octets::Bytes::new(out);

    let first = rand::rand_u8() | FORM_BIT;

    b.put_u8(first)?;
    b.put_u32(0)?;

    // Invert client's scid and dcid.
    let mut cil: u8 = 0;
    if hdr.scid.len() > 0 {
        cil |= ((hdr.scid.len() - 3) as u8) << 4;
    }

    if hdr.dcid.len() > 0 {
        cil |= ((hdr.dcid.len() - 3) as u8) & 0xf;
    }

    b.put_u8(cil)?;
    b.put_bytes(&hdr.scid)?;
    b.put_bytes(&hdr.dcid)?;
    b.put_u32(::VERSION_DRAFT14)?;

    Ok(b.off())
}

pub struct PktNumSpace {
    pub pkt_type: Type,

    pub expected_pkt_num: u64,

    pub last_pkt_num: u64,

    pub need_ack: Vec<u64>,

    pub crypto_level: crypto::Level,

    pub crypto_open: option::Option<crypto::Open>,
    pub crypto_seal: option::Option<crypto::Seal>,

    pub crypto_offset: usize,
    pub crypto_buf: Vec<u8>,
}

impl PktNumSpace {
    pub fn new(ty: Type, crypto_level: crypto::Level) -> PktNumSpace {
        PktNumSpace {
            pkt_type: ty,

            expected_pkt_num: 0,

            last_pkt_num: 0,

            need_ack: Vec::new(),

            crypto_level,

            crypto_open: None,
            crypto_seal: None,

            crypto_offset: 0,
            crypto_buf: Vec::new(),
        }
    }

    pub fn pending(&self) -> usize {
        self.crypto_buf[self.crypto_offset..].len()
    }

    pub fn overhead(&self) -> usize {
        self.crypto_seal.as_ref().unwrap().tag_len()
    }

    pub fn get_buf(&self, len: usize) -> &[u8] {
        &self.crypto_buf[self.crypto_offset..len]
    }

    pub fn advance(&mut self, len: usize) -> Result<()> {
        self.crypto_offset += len;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn decrypt_initial() {
        decrypt_initial_helper("test_data/initial_ngtcp2.txt");
        decrypt_initial_helper("test_data/initial_quicly.txt");
    }

    fn decrypt_initial_helper(file_name: &'static str) {
        let mut file = File::open(file_name).unwrap();

        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap();

        let mut b = octets::Bytes::new(&mut buf);

        let hdr = Header::long_from_bytes(&mut b).unwrap();

        let payload_len = b.get_varint().unwrap() as usize;

        let (aead_open, _) =
            crypto::derive_initial_key_material(&hdr.dcid, true).unwrap();

        let (pn, pn_len) = decrypt_pkt_num(&mut b, &aead_open).unwrap();
        b.skip(pn_len).unwrap();

        let payload_offset = b.off();

        let (header, mut payload) = b.split_at(payload_offset).unwrap();

        decrypt_pkt(payload.slice(payload_len - pn_len).unwrap(),
                    pn, header.as_ref(), &aead_open).unwrap();
    }
}
<commit_msg>packet: use slice::from_mut<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::option;
use std::slice;

use ::Result;
use ::Error;

use octets;
use crypto;
use rand;

const FORM_BIT: u8 = 0x80;
const KEY_PHASE_BIT: u8 = 0x40;
const DEMUX_BIT: u8 = 0x08;

const TYPE_MASK: u8 = 0x7f;

const MAX_CID_LEN: u8 = 18;

#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Type {
    Initial,
    Retry,
    Handshake,
    ZeroRTT,
    VersionNegotiation,
    Application,
}

pub fn has_long_header(b: u8) -> bool {
    b & FORM_BIT != 0
}

pub fn parse_long_header(buf: &mut [u8]) -> Result<Header> {
    let mut b = octets::Bytes::new(buf);
    Header::long_from_bytes(&mut b)
}

#[derive(Clone, Debug)]
pub struct Header {
    pub ty: Type,
    pub version: u32,
    pub flags: u8,
    pub dcid: Vec<u8>,
    pub scid: Vec<u8>,
    pub token: option::Option<Vec<u8>>,
}

impl Header {
    pub fn long_from_bytes(b: &mut octets::Bytes) -> Result<Header> {
        let first = b.get_u8()?;

        if !has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let version = b.get_u32()?;

        let ty = if version == 0 {
            Type::VersionNegotiation
        } else {
            match first & TYPE_MASK {
                0x7f => Type::Initial,
                0x7e => Type::Retry,
                0x7d => Type::Handshake,
                0x7c => Type::ZeroRTT,
                _    => return Err(Error::UnknownPacket),
            }
        };

        let (dcil, scil) = match b.get_u8() {
            Ok(v) => {
                let mut dcil = v >> 4;
                let mut scil = v & 0xf;

                if dcil > MAX_CID_LEN || scil > MAX_CID_LEN {
                    return Err(Error::InvalidPacket);
                }

                if dcil > 0 {
                    dcil += 3;
                }

                if scil > 0 {
                    scil += 3;
                }

                (dcil, scil)
            },

            Err(_) => return Err(Error::BufferTooShort),
        };

        let dcid = b.get_bytes(dcil as usize)?.to_vec();
        let scid = b.get_bytes(scil as usize)?.to_vec();

        // End of invariants.

        let mut token: option::Option<Vec<u8>> = None;

        match ty {
            Type::Initial => {
                token = Some(b.get_bytes_with_varint_length()?.to_vec());
            },

            Type::Retry => {
                panic!("Retry not supported");
            },

            Type::VersionNegotiation => {
                panic!("Retry not supported");
            },

            _ => (),
        };

        Ok(Header {
            ty,
            flags: first & FORM_BIT,
            version,
            dcid,
            scid,
            token,
        })
    }

    pub fn long_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let ty: u8 = match hdr.ty {
                Type::Initial   => 0x7f,
                Type::Retry     => 0x7e,
                Type::Handshake => 0x7d,
                Type::ZeroRTT   => 0x7c,
                // TODO: unify handling of version negotiation
                _               => return Err(Error::UnknownPacket),
        };

        let first = FORM_BIT | ty;

        out.put_u8(first)?;

        out.put_u32(hdr.version)?;

        let mut cil: u8 = 0;

        if hdr.dcid.len() > 0 {
            cil |= ((hdr.dcid.len() - 3) as u8) << 4;
        }

        if hdr.scid.len() > 0 {
            cil |= ((hdr.scid.len() - 3) as u8) & 0xf;
        }

        out.put_u8(cil)?;

        out.put_bytes(&hdr.dcid)?;
        out.put_bytes(&hdr.scid)?;

        // Only Initial packet have a token.
        if hdr.ty == Type::Initial {
            match hdr.token {
                Some(ref v) => {
                    out.put_bytes(v)?;
                },

                None => {
                    // No token, so lemgth = 0.
                    out.put_varint(0)?;
                }
            }
        }

        Ok(())
    }

    pub fn short_from_bytes(b: &mut octets::Bytes, dcil: usize) -> Result<Header> {
        let first = b.get_u8()?;

        if has_long_header(first) {
            return Err(Error::WrongForm);
        }

        let dcid = b.get_bytes(dcil)?;

        Ok(Header {
            ty: Type::Application,
            flags: first & FORM_BIT,
            version: 0,
            dcid: dcid.to_vec(),
            scid: Vec::new(),
            token: None,
        })
    }

    pub fn short_to_bytes(hdr: &Header, out: &mut octets::Bytes) -> Result<()> {
        let mut first = rand::rand_u8();

        // Unset form bit for short header.
        first &= !FORM_BIT;

        // TODO: support key update
        first &= !KEY_PHASE_BIT;

        // "The third bit (0x20) of octet 0 is set to 1."
        first |= 0x20;

        // "The fourth bit (0x10) of octet 0 is set to 1."
        first |= 0x10;

        // Clear Google QUIC demultiplexing bit
        first &= !DEMUX_BIT;

        out.put_u8(first)?;
        out.put_bytes(&hdr.dcid)?;

        Ok(())
    }
}

pub fn pkt_num_len(pn: u64) -> Result<usize> {
    let len = if pn < 128 {
        1
    } else if pn < 16384 {
        2
    } else if pn < 1_073_741_824 {
        4
    } else {
        return Err(Error::InvalidPacket);
    };

    Ok(len)
}

pub fn decrypt_pkt_num(b: &mut octets::Bytes, aead: &crypto::Open)
                                                    -> Result<(u64,usize)> {
    let mut pn_and_sample = b.peek_bytes(20)?;

    let (mut ciphertext, sample) = pn_and_sample.split_at(4).unwrap();

    let ciphertext = ciphertext.as_mut();

    // Decrypt first byte of pkt num into separate buffer to get length.
    let mut first: u8 = ciphertext[0];

    aead.xor_keystream(sample.as_ref(), slice::from_mut(&mut first))?;

    let len = if first >> 7 == 0 {
        1
    } else {
        // Map most significant 2 bits to actual pkt num length.
        match first >> 6 {
            2 => 2,
            3 => 4,
            _ => return Err(Error::InvalidPacket),
        }
    };

    // Decrypt full pkt num in-place.
    aead.xor_keystream(sample.as_ref(), &mut ciphertext[..len])?;

    let mut plaintext: [u8; 4] = [0; 4];
    plaintext.copy_from_slice(&ciphertext[..4]);

    // Mask the 2 most significant bits to remove the encoded length.
    if len > 1 {
        plaintext[0] &= 0x3f;
    }

    let mut b = octets::Bytes::new(&mut plaintext);

    // Extract packet number corresponding to the decoded length.
    let out = match len {
        1 => u64::from(b.get_u8()?),
        2 => u64::from(b.get_u16()?),
        4 => u64::from(b.get_u32()?),
        _ => return Err(Error::InvalidPacket),
    };

    // TODO: implement packet number truncation
    Ok((out as u64, len))
}

pub fn encode_pkt_num(pn: u64, b: &mut octets::Bytes) -> Result<()> {
    let len = pkt_num_len(pn)?;

    match len {
        1 => {
            let mut buf = b.put_u8(pn as u8)?;
            buf[0] &= !0x80;
        },

        2 => {
            let mut buf = b.put_u16(pn as u16)?;
            buf[0] &= !0xc0;
            buf[0] |= 0x80;
        },

        4 => {
            let mut buf = b.put_u32(pn as u32)?;
            buf[0] |= 0xc0;
        },

        _ => return Err(Error::InvalidPacket),
    };

    Ok(())
}

pub fn decrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Open)
                                                            -> Result<usize> {
    aead.open_with_u64_counter(pn, ad, payload)
}

pub fn encrypt_pkt(payload: &mut [u8], pn: u64, ad: &[u8], aead: &crypto::Seal)
                                                            -> Result<usize> {
    aead.seal_with_u64_counter(pn, ad, payload)
}

pub fn negotiate_version(hdr: &Header, out: &mut [u8]) -> Result<usize> {
    let mut b = octets::Bytes::new(out);

    let first = rand::rand_u8() | FORM_BIT;

    b.put_u8(first)?;
    b.put_u32(0)?;

    // Invert client's scid and dcid.
    let mut cil: u8 = 0;
    if hdr.scid.len() > 0 {
        cil |= ((hdr.scid.len() - 3) as u8) << 4;
    }

    if hdr.dcid.len() > 0 {
        cil |= ((hdr.dcid.len() - 3) as u8) & 0xf;
    }

    b.put_u8(cil)?;
    b.put_bytes(&hdr.scid)?;
    b.put_bytes(&hdr.dcid)?;
    b.put_u32(::VERSION_DRAFT14)?;

    Ok(b.off())
}

pub struct PktNumSpace {
    pub pkt_type: Type,

    pub expected_pkt_num: u64,

    pub last_pkt_num: u64,

    pub need_ack: Vec<u64>,

    pub crypto_level: crypto::Level,

    pub crypto_open: option::Option<crypto::Open>,
    pub crypto_seal: option::Option<crypto::Seal>,

    pub crypto_offset: usize,
    pub crypto_buf: Vec<u8>,
}

impl PktNumSpace {
    pub fn new(ty: Type, crypto_level: crypto::Level) -> PktNumSpace {
        PktNumSpace {
            pkt_type: ty,

            expected_pkt_num: 0,

            last_pkt_num: 0,

            need_ack: Vec::new(),

            crypto_level,

            crypto_open: None,
            crypto_seal: None,

            crypto_offset: 0,
            crypto_buf: Vec::new(),
        }
    }

    pub fn pending(&self) -> usize {
        self.crypto_buf[self.crypto_offset..].len()
    }

    pub fn overhead(&self) -> usize {
        self.crypto_seal.as_ref().unwrap().tag_len()
    }

    pub fn get_buf(&self, len: usize) -> &[u8] {
        &self.crypto_buf[self.crypto_offset..len]
    }

    pub fn advance(&mut self, len: usize) -> Result<()> {
        self.crypto_offset += len;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn decrypt_initial() {
        decrypt_initial_helper("test_data/initial_ngtcp2.txt");
        decrypt_initial_helper("test_data/initial_quicly.txt");
    }

    fn decrypt_initial_helper(file_name: &'static str) {
        let mut file = File::open(file_name).unwrap();

        let mut buf = Vec::new();
        file.read_to_end(&mut buf).unwrap();

        let mut b = octets::Bytes::new(&mut buf);

        let hdr = Header::long_from_bytes(&mut b).unwrap();

        let payload_len = b.get_varint().unwrap() as usize;

        let (aead_open, _) =
            crypto::derive_initial_key_material(&hdr.dcid, true).unwrap();

        let (pn, pn_len) = decrypt_pkt_num(&mut b, &aead_open).unwrap();
        b.skip(pn_len).unwrap();

        let payload_offset = b.off();

        let (header, mut payload) = b.split_at(payload_offset).unwrap();

        decrypt_pkt(payload.slice(payload_len - pn_len).unwrap(),
                    pn, header.as_ref(), &aead_open).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true);
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
static COMMENT_RE: &'static str = r"\s*(#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> Regex {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
                 .compile()
                 .unwrap()
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    let captures = try!(regex.captures(line)
                             .ok_or_else(|| Error::from_str(&format!("Can't parse: {}", line))));

    for (name, actual_value) in captures.iter_named() {
        match name {
            "indent" => {
                indent = actual_value.map_or(0, |value| value.len());
            }

            "comment" => {
                comment = actual_value.map(|value| value.to_owned());
            }

            _ => {
                match actual_value {
                    None => {
                        kind = Some(name.to_owned());
                        value = actual_value.map(|value| value.to_owned());
                    }

                    Some(other) => {
                        return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                    }
                }
            }
        }
    }

    match kind {
        None => {
            unimplemented!()
        }

        Some(kind) => {
            let kind = match kind.as_str() {
                "tags" =>
                    LineKind::Tags,

                "feature" =>
                    LineKind::Feature,

                "background" =>
                    LineKind::Background,

                "scenario" =>
                    LineKind::Scenario,

                "outline" =>
                    LineKind::ScenarioOutline,

                "given" =>
                    LineKind::GivenStep,

                "when" =>
                   LineKind::WhenStep,

                "then" =>
                    LineKind::ThenStep,

                "and" =>
                    LineKind::AndStep,

                "but" =>
                    LineKind::ButStep,

                "examples" =>
                    LineKind::Examples,

                "table" =>
                    LineKind::Table,

                "docstring" =>
                    LineKind::DocString,

                "other" =>
                    LineKind::Other,

                _ => {
                    return Err(Error::from_str(&format!("Unknown match: {}", kind)));
                }
            };

            Ok(Line{
                kind: kind,
                value: value,
                indent: indent,
                comment: comment
            })
        }
    }
}
<commit_msg>apply newly obtained knowledge of Option methods<commit_after>use std::fs::File;
use std::io::{
    BufReader,
    BufRead,
};

use regex::{
    Regex,
    RegexBuilder,
};

use super::Error;
use super::Result;

use types::*;

pub enum State {
    Init,
    FeatureAndTags,
    Feature,
    FeatureWithBackground,
    FeatureWithDescription,
    FeatureWithLanguage,
    FeatureWithTags,
}

pub fn parse(filename: &str) -> Result<Feature> {
    let file = try!(File::open(filename));

    let mut feature = Feature {
        filename: filename.to_owned(),
        name: None,
        description: None,
        background: None,
        items: Vec::new(),
    };
    let mut state = State::Init;

    for line in BufReader::new(file).lines() {
        let line = try!(line);

        match state {
            State::Init => {
                lazy_static! {
                    static ref RE: Regex = prepare_regex(&[FEATURE_RE, LANGUAGE_RE, TAGS_RE], true);
                }

                match try!(parse_line(&line, &RE)) {
                    _ =>
                        unimplemented!()
                }
            }

            _ => {
                return Err(Error::from_str("unhandled state"));
            }
        }
    }

    Ok(feature)
}

// nay be used only once and we ignore it
static LANGUAGE_RE: &'static str = r"(Language:\s*(?P<language>\S+))";

static TAGS_RE: &'static str = r"(?P<tags>@\w+(\s+@\w+)*)";

static FEATURE_RE: &'static str = r"(Feature:\s*(?P<feature>.*))";
static BACKGROUND_RE: &'static str = r"(Background:\s*(?P<background>.*))";
static SCENARIO_RE: &'static str = r"(Scenario:\s*(?P<scenario>.*))";
static SCENARIO_OUTLINE_RE: &'static str = r"(Scenario Outline:\s*(?P<outline>.*))";
static GIVEN_STEP_RE: &'static str = r"(Given\s+(?P<given>.*))";
static WHEN_STEP_RE: &'static str = r"(When\s+(?P<when>.*))";
static THEN_STEP_RE: &'static str = r"(Then\s+(?P<then>.*))";
static AND_STEP_RE: &'static str = r"(And\s+(?P<and>.*))";
static BUT_STEP_RE: &'static str = r"(But\s+(?P<but>.*))";
static EXAMPLES_RE: &'static str = r"(Examples:\s*(?P<examples>.*))";

static TABLE_RE: &'static str = r"(?P<table>\|.*\|)";
static DOCSTRING_RE: &'static str = "(?P<docstring>\"\"\"|''')";

static OTHER_RE: &'static str = "(?P<other>[^#]*)";

static INDENT_RE: &'static str = r"(?P<indent>\s*)";
static COMMENT_RE: &'static str = r"\s*(#\s*(?P<comment>.*))?";

fn prepare_regex(bits: &[&str], detect_comment: bool) -> Regex {
    let actual_bits = &bits.join("|");
    let mut pattern: Vec<&str> = vec!("^",
                                      INDENT_RE,
                                      "(",
                                      &actual_bits,
                                      ")");
    if detect_comment {
        pattern.push(COMMENT_RE);
    }

    pattern.push("$");

    RegexBuilder::new(&pattern.join(r""))
                 .case_insensitive(true)
                 .ignore_whitespace(true)
                 .compile()
                 .unwrap()
}

enum LineKind {
    EmptyLine,
    Tags,
    Feature,
    Background,
    Scenario,
    ScenarioOutline,
    GivenStep,
    WhenStep,
    ThenStep,
    AndStep,
    ButStep,
    Examples,
    Table,
    DocString,
    Other,
}

struct Line {
    pub kind: LineKind,
    pub value: Option<String>,
    pub indent: usize,
    pub comment: Option<String>,
}

fn parse_line(line: &str, regex: &Regex) -> Result<Line> {
    let mut kind: Option<String> = None;
    let mut value: Option<String> = None;
    let mut indent: usize = 0;
    let mut comment: Option<String> = None;

    let captures = try!(regex.captures(line)
                             .ok_or_else(|| Error::from_str(&format!("Can't parse: {}", line))));

    for (name, actual_value) in captures.iter_named() {
        match name {
            "indent" => {
                indent = actual_value.map_or(0, |value| value.len());
            }

            "comment" => {
                comment = actual_value.map(|value| value.to_owned());
            }

            _ => {
                match actual_value {
                    None => {
                        kind = Some(name.to_owned());
                        value = actual_value.map(|value| value.to_owned());
                    }

                    Some(other) => {
                        return Err(Error::from_str(&format!("Double match: {} and {}", other, name)));
                    }
                }
            }
        }
    }

    let kind = match try!(kind.ok_or_else(|| Error::from_str(&format!("Could not determine line kind for: {}", line)))).as_str() {
        "tags" =>
            LineKind::Tags,

        "feature" =>
            LineKind::Feature,

        "background" =>
            LineKind::Background,

        "scenario" =>
            LineKind::Scenario,

        "outline" =>
            LineKind::ScenarioOutline,

        "given" =>
            LineKind::GivenStep,

        "when" =>
            LineKind::WhenStep,

        "then" =>
            LineKind::ThenStep,

        "and" =>
            LineKind::AndStep,

        "but" =>
            LineKind::ButStep,

        "examples" =>
            LineKind::Examples,

        "table" =>
            LineKind::Table,

        "docstring" =>
            LineKind::DocString,

        "other" =>
            LineKind::Other,

        kind @ _ => {
            return Err(Error::from_str(&format!("Unknown kind: {}", kind)));
        }
    };

    Ok(Line{
        kind: kind,
        value: value,
        indent: indent,
        comment: comment
    })
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream, value};
use combine::char::{tab, char, crlf, string};
use combine::combinator::{many, none_of};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
  Operation(Operation),
  SelectionSet(SelectionSet),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
  Field(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

make_parser!(
  WhiteSpace(input: char) -> char {
    char(' ').or(tab())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      char('\r')
        .or(char('\n'))
        .parse_stream(input)
    } else {
      crlf()
        .or(char('\r'))
        .or(char('\n'))
        .parse_stream(input)
    }
  }
);

make_parser!(
  LineComment(input: char) -> () {
    value(())
      .skip(char('#'))
      .skip(many::<Vec<_>,_>(none_of("\r\n".chars())))
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

make_parser!(
  OperationTypeP(input: char) -> OperationType {
    string("query").map(|_| OperationType::Query)
      .or(string("mutation").map(|_| OperationType::Mutation))
      .parse_stream(input)
  }
);

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn operation_type<I: U8Input>(i: I) -> SimpleResult<I,OperationType>
// {
//   let op_type = |i,b,r| string(i,b).map(|_| r);
//   parse!{i;
//       op_type(b"query", OperationType::Query) <|>
//       op_type(b"mutation", OperationType::Mutation)
//   }
// }

// pub fn name<I: U8Input>(i: I) -> SimpleResult<I,Name>
// {
//   parse!{i;
//     let start = satisfy(|c| is_alpha(c) || c == b'_');
//     let rest = take_while(|c| is_alphanumeric(c) || c == b'_');

//     ret {
//       let mut start = String::from_utf8(vec![start]).unwrap();
//       let rest = String::from_utf8(rest.to_vec()).unwrap();
//       start.push_str(&rest);
//       start
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

#[cfg(test)]
mod tests {
  use super::*;
  use combine::{Parser,State};

  #[test]
  fn test_parse_comment() {
    assert_eq!(LineComment::new().parse(State::new("#hello world\r\n")).map(|x| x.0), Ok(()));
  }

  #[test]
  fn test_parse_operationtype() {
    assert_eq!(OperationTypeP::new().parse(State::new("query")).map(|x| x.0), Ok(OperationType::Query));
    assert_eq!(OperationTypeP::new().parse(State::new("mutation")).map(|x| x.0), Ok(OperationType::Mutation));
  }
}
<commit_msg>started name; but parse is failing<commit_after>use std::collections::HashMap;

use std::marker::PhantomData;

use combine::{Parser, ParseResult, Stream, value};
use combine::char::{tab, char, crlf, string, letter, alpha_num};
use combine::combinator::{many, none_of, or};

pub type Name = String;
pub type SelectionSet = Vec<Selection>;

#[derive(Debug,PartialEq)]
pub struct Document {
  definitions: Vec<Definition>,
}

#[derive(Debug,PartialEq)]
pub enum Definition {
  Operation(Operation),
  SelectionSet(SelectionSet),
  Fragment(Fragment),
}

#[derive(Debug,PartialEq)]
pub struct Operation {
  op_type: OperationType,
  name: Option<Name>,
  variable_definitions: Vec<VariableDefinition>,
  directives: Vec<Directive>,
}

impl Operation {
  fn new(op_type: OperationType,
         name: Option<Name>,
         variable_definitions: Vec<VariableDefinition>,
         directives: Vec<Directive>)
         -> Operation {
    Operation {
      op_type: op_type,
      name: name,
      variable_definitions: variable_definitions,
      directives: directives,
    }
  }
}

#[derive(Debug,PartialEq)]
pub enum OperationType {
  Query,
  Mutation,
}

#[derive(Debug,PartialEq)]
pub struct VariableDefinition {
  variable: Variable,
  var_type: Type,
  default_value: Option<Value>,
}

type Variable = String;

#[derive(Debug,PartialEq)]
pub enum Type {
  Named(Name),
  List(Box<Type>),
  NonNull(Box<Type>),
}

#[derive(Debug,PartialEq)]
pub enum Value {
  Variable(Variable),
  Int(i32),
  Float(f32),
  String(String),
  Boolean(bool),
  Null,
  Enum(String),
  List(Vec<Value>),
  Object(HashMap<String, Value>),
}

#[derive(Debug,PartialEq)]
pub struct Directive {
  name: Name,
  arguments: Vec<Argument>,
}

#[derive(Debug,PartialEq)]
pub struct Argument {
  name: Name,
  value: Value,
}

#[derive(Debug,PartialEq)]
pub enum Selection {
  Field(Field),
  FragmentSpread(Name, Vec<Directive>),
  InlineFragment(Option<Type>, Vec<Directive>, SelectionSet),
}

#[derive(Debug,PartialEq)]
pub struct Field {
  alias: Option<Name>,
  name: Name,
  arguments: Vec<Argument>,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

impl Field {
  fn new(alias: Option<Name>,
         name: Name,
         arguments: Vec<Argument>,
         directives: Vec<Directive>,
         selection_set: SelectionSet)
         -> Field {
    Field {
      alias: alias,
      name: name,
      arguments: arguments,
      directives: directives,
      selection_set: selection_set,
    }
  }
}

#[derive(Debug,PartialEq)]
pub struct Fragment {
  name: Name,
  type_condition: Type,
  directives: Vec<Directive>,
  selection_set: SelectionSet,
}

macro_rules! make_parser {

    // base case
    () => {};

    ($name:ident ($input_var:ident : $input_item_type:ty) -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

      pub struct $name<T> {
        _phantom: PhantomData<T>,
      }

      impl<T> $name<T> {
          pub fn new() -> Self {
              $name {
                _phantom: PhantomData
              }
          }
      }

      impl<I> Parser for $name<I> where I: Stream<Item=$input_item_type> {
        type Input = I;
        type Output = $output_type;

        fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
          $($tmpl)*
        }
      }

      make_parser!($($rest)*);
    };

    ($name:ident ($input_var:ident : $input_item_type:ty , $($field:ident : &$typ:ty),*)
      -> $output_type:ty { $($tmpl:tt)* } $($rest:tt)*) => {

        pub struct $name<'a, T> {
          _phantom: PhantomData<T>,
          $( $field: &'a $typ),*
        }

        impl<'a, T> $name<'a, T> {
          pub fn new($($field: &'a $typ),*) -> Self {
            $name {
              _phantom: PhantomData,
              $( $field: $field),*
            }
          }
        }

        impl<'a, I> Parser for $name<'a, I> where I: Stream<Item=$input_item_type> {
          type Input = I;
          type Output = $output_type;

          fn parse_stream(&mut self, $input_var: I) -> ParseResult<Self::Output, Self::Input> {
            let &mut $name { _phantom, $($field),* } = self;

            $($tmpl)*
          }
        }

        make_parser!($($rest)*);
    };
}

// TODO graphql and char have a very differing set of code points
// graphql :: [0009,000A,000D, [0020,FFFF] ]
// char :: [0,D7FF] u [E000,10FFFF]
// somehow we need to wrangle char to match the graphql types :)

make_parser!(
  WhiteSpace(input: char) -> char {
    char(' ').or(tab())
      .parse_stream(input)
  }
);

make_parser!(
  LineTerminator(input: char, is_clr: &bool) -> char {

    if !is_clr {
      char('\r')
        .or(char('\n'))
        .parse_stream(input)
    } else {
      crlf()
        .or(char('\r'))
        .or(char('\n'))
        .parse_stream(input)
    }
  }
);

make_parser!(
  LineComment(input: char) -> () {
    value(())
      .skip(char('#'))
      .skip(many::<Vec<_>,_>(none_of("\r\n".chars())))
      .skip(LineTerminator::new(&true))
      .parse_stream(input)
  }
);

make_parser!(
  OperationTypeP(input: char) -> OperationType {
    string("query").map(|_| OperationType::Query)
      .or(string("mutation").map(|_| OperationType::Mutation))
      .parse_stream(input)
  }
);

make_parser!(
  NameP(input: char) -> Name {
    or(letter(),char('_'))
      .with(many(alpha_num().or(char('_'))))
      .parse_stream(input)
  }
);

// pub fn operation_definition<I: U8Input>(i: I) -> SimpleResult<I,Definition>
// {
//   parse!{i;
//     let op_type = operation_type();
//     white_space() <|> line_terminator();
//     let name = option(|i| name(i).map(Some), None);

//     ret {
//       let op = Operation::new(op_type, name, Vec::new(), Vec::new());
//       Definition::OperationDefinition(op)
//     }
//   }
// }

// pub fn alias<I: U8Input>(i: I) -> SimpleResult<I, Option<Name>>
// {
//   let parser = |i: I| {
//       parse!{i;
//         let name = name();

//         either(white_space, line_terminator);
//         token(b':');

//         ret Some(name)
//       }
//   };

//   option(i, parser, None)
// }

#[cfg(test)]
mod tests {
  use super::*;
  use combine::{Parser,State};

  macro_rules! assert_sucessful_parse {
    ($parser:ident,$input:expr,$result:expr) => {
      assert_eq!($parser::new().parse(State::new($input)).map(|x| x.0), Ok($result));
    }
  }

  #[test]
  fn test_parse_comment() {
    assert_sucessful_parse!(LineComment, "#hello world\r\n", ());
  }

  #[test]
  fn test_parse_operationtype() {
    assert_sucessful_parse!(OperationTypeP, "query", OperationType::Query);
    assert_sucessful_parse!(OperationTypeP, "mutation", OperationType::Mutation);
  }

  #[test]
  fn test_parse_name() {
    assert_sucessful_parse!(NameP, "_asd", String::from("_asd"));
  }
}
<|endoftext|>