<commit_before>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

fn deserialize_token(mut data: Json) -> Token {
    let mut obj = data.as_object_mut().unwrap();
    let ty = obj.remove("type").unwrap().into_string();

    match &ty[..] {
        "LBrace"        => Token::LBrace,
        "DecimalInt"    => Token::DecimalInt(obj.remove("value").unwrap().into_string()),
        "String"        => Token::String(obj.remove("value").unwrap().into_string()),
        _               => panic!("invalid token")
    }
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(&s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<commit_msg>flesh out the token deserialization<commit_after>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

fn deserialize_reserved(word: &str) -> ReservedWord {
    match word {
        "Null"       => ReservedWord::Null,
        "True"       => ReservedWord::True,
        "False"      => ReservedWord::False,
        "Arguments"  => ReservedWord::Arguments,
        "Eval"       => ReservedWord::Eval,
        "Break"      => ReservedWord::Break,
        "Case"       => ReservedWord::Case,
        "Catch"      => ReservedWord::Catch,
        "Class"      => ReservedWord::Class,
        "Const"      => ReservedWord::Const,
        "Continue"   => ReservedWord::Continue,
        "Debugger"   => ReservedWord::Debugger,
        "Default"    => ReservedWord::Default,
        "Delete"     => ReservedWord::Delete,
        "Do"         => ReservedWord::Do,
        "Else"       => ReservedWord::Else,
        "Export"     => ReservedWord::Export,
        "Extends"    => ReservedWord::Extends,
        "Finally"    => ReservedWord::Finally,
        "For"        => ReservedWord::For,
        "Function"   => ReservedWord::Function,
        "If"         => ReservedWord::If,
        "Import"     => ReservedWord::Import,
        "In"         => ReservedWord::In,
        "Instanceof" => ReservedWord::Instanceof,
        "Let"        => ReservedWord::Let,
        "New"        => ReservedWord::New,
        "Return"     => ReservedWord::Return,
        "Static"     => ReservedWord::Static,
        "Super"      => ReservedWord::Super,
        "Switch"     => ReservedWord::Switch,
        "This"       => ReservedWord::This,
        "Throw"      => ReservedWord::Throw,
        "Try"        => ReservedWord::Try,
        "Typeof"     => ReservedWord::Typeof,
        "Var"        => ReservedWord::Var,
        "Void"       => ReservedWord::Void,
        "While"      => ReservedWord::While,
        "With"       => ReservedWord::With,
        "Yield"      => ReservedWord::Yield,
        "Enum"       => ReservedWord::Enum,
        "Await"      => ReservedWord::Await,
        "Implements" => ReservedWord::Implements,
        "Interface"  => ReservedWord::Interface,
        "Package"    => ReservedWord::Package,
        "Private"    => ReservedWord::Private,
        "Protected"  => ReservedWord::Protected,
        "Public"     => ReservedWord::Public,
        _            => panic!("invalid reserved word")
    }
}

fn deserialize_token(mut data: Json) -> Token {
    let mut obj = data.as_object_mut().unwrap();
    let ty = obj.remove("type").unwrap().into_string();

    match &ty[..] {
        "Reserved"      => {
            let s = obj.remove("value").unwrap().into_string();
            Token::Reserved(deserialize_reserved(&s[..]))
        }
        "LBrace"        => Token::LBrace,
        "RBrace"        => Token::RBrace,
        "LParen"        => Token::LParen,
        "RParen"        => Token::RParen,
        "LBrack"        => Token::LBrack,
        "RBrack"        => Token::RBrack,
        "Dot"           => Token::Dot,
        //"Ellipsis"    => Token::Ellipsis,
        "Semi"          => Token::Semi,
        "Comma"         => Token::Comma,
        "LAngle"        => Token::LAngle,
        "RAngle"        => Token::RAngle,
        "LEq"           => Token::LEq,
        "GEq"           => Token::GEq,
        "Eq"            => Token::Eq,
        "NEq"           => Token::NEq,
        "StrictEq"      => Token::StrictEq,
        "StrictNEq"     => Token::StrictNEq,
        "Plus"          => Token::Plus,
        "Minus"         => Token::Minus,
        "Star"          => Token::Star,
        "Mod"           => Token::Mod,
        "Slash"         => Token::Slash,
        "Inc"           => Token::Inc,
        "Dec"           => Token::Dec,
        "LShift"        => Token::LShift,
        "RShift"        => Token::RShift,
        "URShift"       => Token::URShift,
        "BitAnd"        => Token::BitAnd,
        "BitOr"         => Token::BitOr,
        "BitXor"        => Token::BitXor,
        "Bang"          => Token::Bang,
        "Tilde"         => Token::Tilde,
        "LogicalAnd"    => Token::LogicalAnd,
        "LogicalOr"     => Token::LogicalOr,
        "Question"      => Token::Question,
        "Colon"         => Token::Colon,
        "Assign"        => Token::Assign,
        "PlusAssign"    => Token::PlusAssign,
        "MinusAssign"   => Token::MinusAssign,
        "StarAssign"    => Token::StarAssign,
        "SlashAssign"   => Token::SlashAssign,
        "ModAssign"     => Token::ModAssign,
        "LShiftAssign"  => Token::LShiftAssign,
        "RShiftAssign"  => Token::RShiftAssign,
        "URShiftAssign" => Token::URShiftAssign,
        "BitAndAssign"  => Token::BitAndAssign,
        "BitOrAssign"   => Token::BitOrAssign,
        "BitXorAssign"  => Token::BitXorAssign,
        "Arrow"         => Token::Arrow,
        "Newline"       => Token::Newline,
        "EOF"           => Token::EOF,
        "DecimalInt"    => Token::DecimalInt(obj.remove("value").unwrap().into_string()),
        "BinaryInt"     => {
            let flag = obj.remove("flag").unwrap().into_string().remove(0);
            Token::BinaryInt(flag, obj.remove("value").unwrap().into_string())
        }
        "OctalInt"      => {
            let flag = obj.remove("flag").unwrap().into_string_opt().map(|mut str| str.remove(0));
            Token::OctalInt(flag, obj.remove("value").unwrap().into_string())
        }
        "HexInt"        => {
            let flag = obj.remove("flag").unwrap().into_string().remove(0);
            Token::HexInt(flag, obj.remove("value").unwrap().into_string())
        }
        "Float"         => {
            let int = obj.remove("int").unwrap().into_string_opt();
            let frac = obj.remove("frac").unwrap().into_string_opt();
            let exp = obj.remove("exp").unwrap().into_string_opt();
            Token::Float(int, frac, exp)
        }
        "String"        => Token::String(obj.remove("value").unwrap().into_string()),
        "RegExp"        => Token::RegExp(obj.remove("value").unwrap().into_string()),
        "Identifier"    => Token::Identifier(obj.remove("value").unwrap().into_string()),
        "LineComment"   => Token::LineComment(obj.remove("value").unwrap().into_string()),
        "BlockComment"  => Token::BlockComment(obj.remove("value").unwrap().into_string()),
        _               => panic!("invalid token")
    }
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(&s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<|endoftext|>


<commit_before>// unix/ctl.rs

use super::funcs::*;
use ctl_error::SysctlError;
use ctl_flags::CtlFlags;
use ctl_info::CtlInfo;
use ctl_type::CtlType;
use ctl_value::CtlValue;
use std::str::FromStr;
use traits::Sysctl;

/// This struct represents a system control.
#[derive(Debug, Clone, PartialEq)]
pub enum Ctl {
    Oid(Vec<libc::c_int>),
    Name(String, CtlType, String),
}

impl Ctl {
    pub fn oid(&self) -> Option<&Vec<libc::c_int>> {
        match self {
            Ctl::Oid(oid) => Some(oid),
            _ => None,
        }
    }
}

impl std::str::FromStr for Ctl {
    type Err = SysctlError;

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::redundant_field_names))]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let oid = name2oid(s)?;

        Ok(Ctl::Oid(oid))
    }
}

impl Sysctl for Ctl {
    fn new(name: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn new_with_type(name: &str, _ctl_type: CtlType, _fmt: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn new_with_type(name: &str, ctl_type: CtlType, fmt: &str) -> Result<Self, SysctlError> {
        let _ = name2oid(name)?;

        Ok(Ctl::Name(name.to_string(), ctl_type, fmt.to_string()))
    }

    fn name(&self) -> Result<String, SysctlError> {
        match self {
            Ctl::Oid(oid) => oid2name(&oid),
            Ctl::Name(name, ..) => Ok(name.clone()),
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value_type(&self) -> Result<CtlType, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let info = oidfmt(oid)?;
                Ok(info.ctl_type)
            }
            Ctl::Name(_, ctl_type, _) => {
                Ok(*ctl_type)
            }
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value_type(&self) -> Result<CtlType, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let info = oidfmt(oid)?;

                Ok(match info.ctl_type {
                    CtlType::Int => match info.fmt.as_str() {
                        "I" => CtlType::Int,
                        "IU" => CtlType::Uint,
                        "L" => CtlType::Long,
                        "LU" => CtlType::Ulong,
                        _ => return Err(SysctlError::MissingImplementation),
                    },
                    ctl_type => ctl_type,
                })
            }
            Ctl::Name(_, ctl_type, fmt) => {
                Ok(match ctl_type {
                    CtlType::Int => match fmt.as_str() {
                        "I" => CtlType::Int,
                        "IU" => CtlType::Uint,
                        "L" => CtlType::Long,
                        "LU" => CtlType::Ulong,
                        _ => return Err(SysctlError::MissingImplementation),
                    },
                    ctl_type => *ctl_type,
                })
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn description(&self) -> Result<String, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        oid2description(oid)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn description(&self) -> Result<String, SysctlError> {
        Ok("[N/A]".to_string())
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        value_oid(oid)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                value_oid(&mut oid)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                value_name(name.as_str(), *ctl_type, fmt.as_str())
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        value_oid_as::<T>(oid)
    }

    fn value_string(&self) -> Result<String, SysctlError> {
        self.value().map(|v| format!("{}", v))
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                value_oid_as::<T>(&mut oid)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                value_name_as::<T>(name.as_str(), *ctl_type, fmt.as_str())
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        set_oid_value(&oid, value)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                set_oid_value(&mut oid, value)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                set_name_value(name.as_str(), *ctl_type, fmt.as_str(), value)
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        let ctl_type = self.value_type()?;
        let _ = match ctl_type {
            CtlType::String => set_oid_value(self.oid(), CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;

        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                let _ = match ctl_type {
                    CtlType::String => set_oid_value(&mut oid, CtlValue::String(value.to_owned())),
                    CtlType::Uint => set_oid_value(
                        &mut oid,
                        CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Int => set_oid_value(
                        &mut oid,
                        CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Ulong => set_oid_value(
                        &mut oid,
                        CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::U8 => set_oid_value(
                        &mut oid,
                        CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    _ => Err(SysctlError::MissingImplementation),
                }?;
            }
            Ctl::Name(name, ctl_type, fmt) => {
                let _ = match ctl_type {
                    CtlType::String => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::String(value.to_owned()),
                    ),
                    CtlType::Uint => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Int => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Ulong => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::U8 => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    _ => Err(SysctlError::MissingImplementation),
                }?;
            }
        }

        self.value_string()
    }

    fn flags(&self) -> Result<CtlFlags, SysctlError> {
        Ok(self.info()?.flags())
    }

    fn info(&self) -> Result<CtlInfo, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        oidfmt(oid)
    }
}

#[cfg(test)]
mod tests {
    use crate::Sysctl;

    #[test]
    fn ctl_new() {
        let _ = super::Ctl::new("kern.ostype").expect("Ctl::new");
    }

    #[test]
    fn ctl_description() {
        let ctl = super::Ctl::new("kern.ostype").expect("Ctl::new");

        let descp = ctl.description();
        assert!(descp.is_ok());

        let descp = descp.unwrap();

        #[cfg(target_os = "freebsd")]
        assert_eq!(descp, "Operating system type");

        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux"))]
        assert_eq!(descp, "[N/A]");
    }
}

#[cfg(all(test, target_os = "freebsd"))]
mod tests_freebsd {}
<commit_msg>should just have been oid instead of self.oid<commit_after>// unix/ctl.rs

use super::funcs::*;
use ctl_error::SysctlError;
use ctl_flags::CtlFlags;
use ctl_info::CtlInfo;
use ctl_type::CtlType;
use ctl_value::CtlValue;
use std::str::FromStr;
use traits::Sysctl;

/// This struct represents a system control.
#[derive(Debug, Clone, PartialEq)]
pub enum Ctl {
    Oid(Vec<libc::c_int>),
    Name(String, CtlType, String),
}

impl Ctl {
    pub fn oid(&self) -> Option<&Vec<libc::c_int>> {
        match self {
            Ctl::Oid(oid) => Some(oid),
            _ => None,
        }
    }
}

impl std::str::FromStr for Ctl {
    type Err = SysctlError;

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::redundant_field_names))]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let oid = name2oid(s)?;

        Ok(Ctl::Oid(oid))
    }
}

impl Sysctl for Ctl {
    fn new(name: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn new_with_type(name: &str, _ctl_type: CtlType, _fmt: &str) -> Result<Self, SysctlError> {
        Ctl::from_str(name)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn new_with_type(name: &str, ctl_type: CtlType, fmt: &str) -> Result<Self, SysctlError> {
        let _ = name2oid(name)?;

        Ok(Ctl::Name(name.to_string(), ctl_type, fmt.to_string()))
    }

    fn name(&self) -> Result<String, SysctlError> {
        match self {
            Ctl::Oid(oid) => oid2name(&oid),
            Ctl::Name(name, ..) => Ok(name.clone()),
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value_type(&self) -> Result<CtlType, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let info = oidfmt(oid)?;
                Ok(info.ctl_type)
            }
            Ctl::Name(_, ctl_type, _) => {
                Ok(*ctl_type)
            }
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value_type(&self) -> Result<CtlType, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let info = oidfmt(oid)?;

                Ok(match info.ctl_type {
                    CtlType::Int => match info.fmt.as_str() {
                        "I" => CtlType::Int,
                        "IU" => CtlType::Uint,
                        "L" => CtlType::Long,
                        "LU" => CtlType::Ulong,
                        _ => return Err(SysctlError::MissingImplementation),
                    },
                    ctl_type => ctl_type,
                })
            }
            Ctl::Name(_, ctl_type, fmt) => {
                Ok(match ctl_type {
                    CtlType::Int => match fmt.as_str() {
                        "I" => CtlType::Int,
                        "IU" => CtlType::Uint,
                        "L" => CtlType::Long,
                        "LU" => CtlType::Ulong,
                        _ => return Err(SysctlError::MissingImplementation),
                    },
                    ctl_type => *ctl_type,
                })
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn description(&self) -> Result<String, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        oid2description(oid)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn description(&self) -> Result<String, SysctlError> {
        Ok("[N/A]".to_string())
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        value_oid(oid)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value(&self) -> Result<CtlValue, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                value_oid(&mut oid)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                value_name(name.as_str(), *ctl_type, fmt.as_str())
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        value_oid_as::<T>(oid)
    }

    fn value_string(&self) -> Result<String, SysctlError> {
        self.value().map(|v| format!("{}", v))
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn value_as<T>(&self) -> Result<Box<T>, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                value_oid_as::<T>(&mut oid)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                value_name_as::<T>(name.as_str(), *ctl_type, fmt.as_str())
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        set_oid_value(&oid, value)
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn set_value(&self, value: CtlValue) -> Result<CtlValue, SysctlError> {
        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                set_oid_value(&mut oid, value)
            }
            Ctl::Name(name, ctl_type, fmt) => {
                set_name_value(name.as_str(), *ctl_type, fmt.as_str(), value)
            }
        }
    }

    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        let ctl_type = self.value_type()?;
        let _ = match ctl_type {
            CtlType::String => set_oid_value(oid, CtlValue::String(value.to_owned())),
            CtlType::Uint => set_oid_value(
                oid,
                CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Int => set_oid_value(
                oid,
                CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::Ulong => set_oid_value(
                oid,
                CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
            ),
            CtlType::U8 => set_oid_value(
                oid,
                CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
            ),
            _ => Err(SysctlError::MissingImplementation),
        }?;
        self.value_string()
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    fn set_value_string(&self, value: &str) -> Result<String, SysctlError> {
        let ctl_type = self.value_type()?;

        match self {
            Ctl::Oid(oid) => {
                let mut oid = oid.clone();
                let _ = match ctl_type {
                    CtlType::String => set_oid_value(&mut oid, CtlValue::String(value.to_owned())),
                    CtlType::Uint => set_oid_value(
                        &mut oid,
                        CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Int => set_oid_value(
                        &mut oid,
                        CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Ulong => set_oid_value(
                        &mut oid,
                        CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::U8 => set_oid_value(
                        &mut oid,
                        CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    _ => Err(SysctlError::MissingImplementation),
                }?;
            }
            Ctl::Name(name, ctl_type, fmt) => {
                let _ = match ctl_type {
                    CtlType::String => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::String(value.to_owned()),
                    ),
                    CtlType::Uint => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Uint(value.parse::<u32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Int => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Int(value.parse::<i32>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::Ulong => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::Ulong(value.parse::<u64>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    CtlType::U8 => set_name_value(
                        name.as_str(),
                        *ctl_type,
                        fmt.as_str(),
                        CtlValue::U8(value.parse::<u8>().map_err(|_| SysctlError::ParseError)?),
                    ),
                    _ => Err(SysctlError::MissingImplementation),
                }?;
            }
        }

        self.value_string()
    }

    fn flags(&self) -> Result<CtlFlags, SysctlError> {
        Ok(self.info()?.flags())
    }

    fn info(&self) -> Result<CtlInfo, SysctlError> {
        let oid = self.oid().ok_or(SysctlError::MissingImplementation)?;
        oidfmt(oid)
    }
}

#[cfg(test)]
mod tests {
    use crate::Sysctl;

    #[test]
    fn ctl_new() {
        let _ = super::Ctl::new("kern.ostype").expect("Ctl::new");
    }

    #[test]
    fn ctl_description() {
        let ctl = super::Ctl::new("kern.ostype").expect("Ctl::new");

        let descp = ctl.description();
        assert!(descp.is_ok());

        let descp = descp.unwrap();

        #[cfg(target_os = "freebsd")]
        assert_eq!(descp, "Operating system type");

        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux"))]
        assert_eq!(descp, "[N/A]");
    }
}

#[cfg(all(test, target_os = "freebsd"))]
mod tests_freebsd {}
<|endoftext|>


<commit_before>//! Structs and methods for pulling user information from Twitter.
//!
//! All the functions in this module eventually return either a [TwitterUser][] struct or the
//! numeric ID of one. The TwitterUser struct itself contains many fields, relating to the user's
//! profile information and a handful of UI settings available to them. See the struct's
//! documention for details.
//!
//! [TwitterUser]: struct.TwitterUser.html
//!
//! ## `UserCursor`/`UserLoader` and `IDCursor`/`IDLoader` (and `UserSearch`)
//!
//! The functions that return the \*Loader structs all return paginated results, implemented over
//! the network as the corresponding \*Cursor structs. The Loader structs both implement
//! `Iterator`, returning an individual user or ID at a time. This allows them to easily be used
//! with regular iterator adaptors and looped over:
//!
//! ```rust,no_run
//! # let consumer_token = egg_mode::Token::new("", "");
//! # let access_token = egg_mode::Token::new("", "");
//! for user in egg_mode::user::friends_of("rustlang", &consumer_token, &access_token)
//!                            .with_page_size(5)
//!                            .map(|resp| resp.unwrap().response)
//!                            .take(5) {
//!     println!("{} (@{})", user.name, user.screen_name);
//! }
//! ```
//!
//! The actual Item returned by the iterator is `Result<Response<TwitterUser>, Error>`; rate-limit
//! information and network errors are passed into the loop as-is.

use std::borrow::Borrow;
use std::collections::HashMap;
use common::*;
use error;
use auth;
use links;

mod structs;

pub use user::structs::*;

///Lookup a set of Twitter users by their numerical ID.
pub fn lookup_ids(ids: &[i64], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = ids.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",");
    add_param(&mut params, "user_id", id_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup a set of Twitter users by their screen name.
pub fn lookup_names<S: Borrow<str>>(names: &[S], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = names.join(",");
    add_param(&mut params, "screen_name", id_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup a set of Twitter users by both ID and screen name, as applicable.
pub fn lookup(accts: &[UserID], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = accts.iter()
                        .filter_map(|x| match x {
                            &UserID::ID(id) => Some(id.to_string()),
                            _ => None,
                        })
                        .collect::<Vec<_>>()
                        .join(",");
    let name_param = accts.iter()
                          .filter_map(|x| match x {
                              &UserID::ScreenName(name) => Some(name),
                              _ => None,
                          })
                          .collect::<Vec<_>>()
                          .join(",");

    add_param(&mut params, "user_id", id_param);
    add_param(&mut params, "screen_name", name_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup user information for a single user.
pub fn show<'a, T: Into<UserID<'a>>>(acct: T, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());

    let mut resp = try!(auth::get(links::users::SHOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup users based on the given search term.
pub fn search<'a>(query: &'a str, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> UserSearch<'a>
{
    UserSearch::new(query, con_token, access_token)
}

///Lookup the users a given account follows, also called their "friends" within the API.
///
///This function returns an iterator over the `TwitterUser` objects returned by Twitter. This
///method defaults to returning 20 users in a single network call; the maximum is 200.
pub fn friends_of<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, UserCursor>
{
    CursorIter::new(links::users::FRIENDS_LIST, con_token, access_token, Some(acct.into()), Some(20))
}

///Lookup the users a given account follows, also called their "friends" within the API, but only
///return their user IDs.
///
///This function returns an iterator over the User IDs returned by Twitter. This method defaults to
///returning 500 IDs in a single network call; the maximum is 5000.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
pub fn friends_ids<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, IDCursor>
{
    CursorIter::new(links::users::FRIENDS_IDS, con_token, access_token, Some(acct.into()), Some(500))
}

///Lookup the users that follow a given account.
///
///This function returns an iterator over the `TwitterUser` objects returned by Twitter. This
///method defaults to returning 20 users in a single network call; the maximum is 200.
pub fn followers_of<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, UserCursor>
{
    CursorIter::new(links::users::FOLLOWERS_LIST, con_token, access_token, Some(acct.into()), Some(20))
}

///Lookup the users that follow a given account, but only return their user IDs.
///
///This function returns an iterator over the User IDs returned by Twitter. This method defaults to
///returning 500 IDs in a single network call; the maximum is 5000.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
pub fn followers_ids<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, IDCursor>
{
    CursorIter::new(links::users::FOLLOWERS_IDS, con_token, access_token, Some(acct.into()), Some(500))
}

///Lookup the users that have been blocked by the authenticated user.
///
///Note that while loading a user's blocks list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn blocks<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    CursorIter::new(links::users::BLOCKS_LIST, con_token, access_token, None, None)
}

///Lookup the users that have been blocked by the authenticated user, but only return their user
///IDs.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
///
///Note that while loading a user's blocks list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn blocks_ids<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, IDCursor> {
    CursorIter::new(links::users::BLOCKS_IDS, con_token, access_token, None, None)
}

///Lookup the users that have been muted by the authenticated user.
///
///Note that while loading a user's mutes list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn mutes<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    CursorIter::new(links::users::MUTES_LIST, con_token, access_token, None, None)
}

///Lookup the users that have been muted by the authenticated user, but only return their user IDs.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
///
///Note that while loading a user's mutes list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn mutes_ids<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, IDCursor> {
    CursorIter::new(links::users::MUTES_IDS, con_token, access_token, None, None)
}

///Follow the given user with the authenticated account, and set whether device notifications
///should be enabled.
///
///Upon success, this function returns `Ok` with the user that was just followed, even when
///following a protected account. In the latter case, this indicates that the follow request was
///successfully sent.
///
///Calling this with an account the user already follows will return success, even though it
///doesn't change any settings.
pub fn follow<'a, T: Into<UserID<'a>>>(acct: T, notifications: bool, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());
    add_param(&mut params, "follow", notifications.to_string());

    let mut resp = try!(auth::post(links::users::FOLLOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Unfollow the given user with the authenticated account.
///
///Upon success, this function returns `Ok` with the user that was just unfollowed.
///
///Calling this with an account the user doesn't follow will return success, even though it doesn't
///change any settings.
pub fn unfollow<'a, T: Into<UserID<'a>>>(acct: T, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());

    let mut resp = try!(auth::post(links::users::UNFOLLOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}
<commit_msg>refine docs for user::follow<commit_after>//! Structs and methods for pulling user information from Twitter.
//!
//! All the functions in this module eventually return either a [TwitterUser][] struct or the
//! numeric ID of one. The TwitterUser struct itself contains many fields, relating to the user's
//! profile information and a handful of UI settings available to them. See the struct's
//! documention for details.
//!
//! [TwitterUser]: struct.TwitterUser.html
//!
//! ## `UserCursor`/`UserLoader` and `IDCursor`/`IDLoader` (and `UserSearch`)
//!
//! The functions that return the \*Loader structs all return paginated results, implemented over
//! the network as the corresponding \*Cursor structs. The Loader structs both implement
//! `Iterator`, returning an individual user or ID at a time. This allows them to easily be used
//! with regular iterator adaptors and looped over:
//!
//! ```rust,no_run
//! # let consumer_token = egg_mode::Token::new("", "");
//! # let access_token = egg_mode::Token::new("", "");
//! for user in egg_mode::user::friends_of("rustlang", &consumer_token, &access_token)
//!                            .with_page_size(5)
//!                            .map(|resp| resp.unwrap().response)
//!                            .take(5) {
//!     println!("{} (@{})", user.name, user.screen_name);
//! }
//! ```
//!
//! The actual Item returned by the iterator is `Result<Response<TwitterUser>, Error>`; rate-limit
//! information and network errors are passed into the loop as-is.

use std::borrow::Borrow;
use std::collections::HashMap;
use common::*;
use error;
use auth;
use links;

mod structs;

pub use user::structs::*;

///Lookup a set of Twitter users by their numerical ID.
pub fn lookup_ids(ids: &[i64], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = ids.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",");
    add_param(&mut params, "user_id", id_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup a set of Twitter users by their screen name.
pub fn lookup_names<S: Borrow<str>>(names: &[S], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = names.join(",");
    add_param(&mut params, "screen_name", id_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup a set of Twitter users by both ID and screen name, as applicable.
pub fn lookup(accts: &[UserID], con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<Vec<TwitterUser>>, error::Error>
{
    let mut params = HashMap::new();
    let id_param = accts.iter()
                        .filter_map(|x| match x {
                            &UserID::ID(id) => Some(id.to_string()),
                            _ => None,
                        })
                        .collect::<Vec<_>>()
                        .join(",");
    let name_param = accts.iter()
                          .filter_map(|x| match x {
                              &UserID::ScreenName(name) => Some(name),
                              _ => None,
                          })
                          .collect::<Vec<_>>()
                          .join(",");

    add_param(&mut params, "user_id", id_param);
    add_param(&mut params, "screen_name", name_param);

    let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup user information for a single user.
pub fn show<'a, T: Into<UserID<'a>>>(acct: T, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());

    let mut resp = try!(auth::get(links::users::SHOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup users based on the given search term.
pub fn search<'a>(query: &'a str, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> UserSearch<'a>
{
    UserSearch::new(query, con_token, access_token)
}

///Lookup the users a given account follows, also called their "friends" within the API.
///
///This function returns an iterator over the `TwitterUser` objects returned by Twitter. This
///method defaults to returning 20 users in a single network call; the maximum is 200.
pub fn friends_of<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, UserCursor>
{
    CursorIter::new(links::users::FRIENDS_LIST, con_token, access_token, Some(acct.into()), Some(20))
}

///Lookup the users a given account follows, also called their "friends" within the API, but only
///return their user IDs.
///
///This function returns an iterator over the User IDs returned by Twitter. This method defaults to
///returning 500 IDs in a single network call; the maximum is 5000.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
pub fn friends_ids<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, IDCursor>
{
    CursorIter::new(links::users::FRIENDS_IDS, con_token, access_token, Some(acct.into()), Some(500))
}

///Lookup the users that follow a given account.
///
///This function returns an iterator over the `TwitterUser` objects returned by Twitter. This
///method defaults to returning 20 users in a single network call; the maximum is 200.
pub fn followers_of<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, UserCursor>
{
    CursorIter::new(links::users::FOLLOWERS_LIST, con_token, access_token, Some(acct.into()), Some(20))
}

///Lookup the users that follow a given account, but only return their user IDs.
///
///This function returns an iterator over the User IDs returned by Twitter. This method defaults to
///returning 500 IDs in a single network call; the maximum is 5000.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
pub fn followers_ids<'a, T: Into<UserID<'a>>>(acct: T, con_token: &'a auth::Token, access_token: &'a auth::Token)
    -> CursorIter<'a, IDCursor>
{
    CursorIter::new(links::users::FOLLOWERS_IDS, con_token, access_token, Some(acct.into()), Some(500))
}

///Lookup the users that have been blocked by the authenticated user.
///
///Note that while loading a user's blocks list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn blocks<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    CursorIter::new(links::users::BLOCKS_LIST, con_token, access_token, None, None)
}

///Lookup the users that have been blocked by the authenticated user, but only return their user
///IDs.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
///
///Note that while loading a user's blocks list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn blocks_ids<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, IDCursor> {
    CursorIter::new(links::users::BLOCKS_IDS, con_token, access_token, None, None)
}

///Lookup the users that have been muted by the authenticated user.
///
///Note that while loading a user's mutes list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn mutes<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    CursorIter::new(links::users::MUTES_LIST, con_token, access_token, None, None)
}

///Lookup the users that have been muted by the authenticated user, but only return their user IDs.
///
///Choosing only to load the user IDs instead of the full user information results in a call that
///can return more accounts per-page, which can be useful if you anticipate having to page through
///several results and don't need all the user information.
///
///Note that while loading a user's mutes list is a cursored search, it does not allow you to set
///the page size. Calling `with_page_size` on the iterator returned by this function will not
///change the page size used by the network call. Setting `page_size` manually may result in an
///error from Twitter.
pub fn mutes_ids<'a>(con_token: &'a auth::Token, access_token: &'a auth::Token) -> CursorIter<'a, IDCursor> {
    CursorIter::new(links::users::MUTES_IDS, con_token, access_token, None, None)
}

///Follow the given user with the authenticated account, and set whether device notifications
///should be enabled.
///
///Upon success, this function returns `Ok` with the user that was just followed, even when
///following a protected account. In the latter case, this indicates that the follow request was
///successfully sent.
///
///Calling this with an account the user already follows may return an error, or ("for performance
///reasons") may return success without changing any account settings.
pub fn follow<'a, T: Into<UserID<'a>>>(acct: T, notifications: bool, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());
    add_param(&mut params, "follow", notifications.to_string());

    let mut resp = try!(auth::post(links::users::FOLLOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Unfollow the given user with the authenticated account.
///
///Upon success, this function returns `Ok` with the user that was just unfollowed.
///
///Calling this with an account the user doesn't follow will return success, even though it doesn't
///change any settings.
pub fn unfollow<'a, T: Into<UserID<'a>>>(acct: T, con_token: &auth::Token, access_token: &auth::Token)
    -> Result<Response<TwitterUser>, error::Error>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, &acct.into());

    let mut resp = try!(auth::post(links::users::UNFOLLOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}
<|endoftext|>


<commit_before>//! Input validation API (Multi-line editing)

use crate::keymap::Invoke;
use crate::Result;

/// Input validation result
#[non_exhaustive]
pub enum ValidationResult {
    /// Incomplete input
    Incomplete,
    /// Validation fails with an optional error message. User must fix the
    /// input.
    Invalid(Option<String>),
    /// Validation succeeds with an optional message
    Valid(Option<String>),
}

/// Give access to user input.
pub struct ValidationContext<'i> {
    i: &'i mut dyn Invoke,
}

impl<'i> ValidationContext<'i> {
    pub(crate) fn new(i: &'i mut dyn Invoke) -> Self {
        ValidationContext { i }
    }

    /// Returns user input.
    pub fn input(&self) -> &str {
        self.i.input()
    }

    // TODO
    //fn invoke(&mut self, cmd: Cmd) -> Result<?> {
    //    self.i.invoke(cmd)
    //}
}

/// This trait provides an extension interface for determining whether
/// the current input buffer is valid. Rustyline uses the method
/// provided by this trait to decide whether hitting the enter key
/// will end the current editing session and return the current line
/// buffer to the caller of `Editor::readline` or variants.
pub trait Validator {
    /// Takes the currently edited `input` and returns a
    /// `ValidationResult` indicating whether it is valid or not along
    /// with an option message to display about the result. The most
    /// common validity check to implement is probably whether the
    /// input is complete or not, for instance ensuring that all
    /// delimiters are fully balanced.
    ///
    /// If you implement more complex validation checks it's probably
    /// a good idea to also implement a `Hinter` to provide feedback
    /// about what is invalid.
    ///
    /// For auto-correction like a missing closing quote or to reject invalid
    /// char while typing, the input will be mutable (TODO).
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        let _ = ctx;
        Ok(ValidationResult::Valid(None))
    }

    /// Configure whether validation is performed while typing or only
    /// when user presses the Enter key.
    ///
    /// Default is `false`.
    // TODO we can implement this later.
    fn validate_while_typing(&self) -> bool {
        false
    }
}

impl Validator for () {}

impl<'v, V: ?Sized + Validator> Validator for &'v V {
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        (**self).validate(ctx)
    }

    fn validate_while_typing(&self) -> bool {
        (**self).validate_while_typing()
    }
}

/// Simple matching bracket validator.
#[derive(Default)]
pub struct MatchingBracketValidator {
    _priv: (),
}

impl MatchingBracketValidator {
    /// Constructor
    pub fn new() -> Self {
        Self { _priv: () }
    }
}

impl Validator for MatchingBracketValidator {
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        Ok(validate_brackets(ctx.input()))
    }
}

fn validate_brackets(input: &str) -> ValidationResult {
    let mut stack = vec![];
    for c in input.chars() {
        match c {
            '(' | '[' | '{' => stack.push(c),
            ')' | ']' | '}' => match (stack.pop(), c) {
                (Some('('), ')') | (Some('['), ']') | (Some('{'), '}') => {}
                (Some(wanted), _) => {
                    return ValidationResult::Invalid(Some(format!(
                        "Mismatched brackets: {:?} is not properly closed",
                        wanted
                    )))
                }
                (None, c) => {
                    return ValidationResult::Invalid(Some(format!(
                        "Mismatched brackets: {:?} is unpaired",
                        c
                    )))
                }
            },
            _ => {}
        }
    }
    if stack.is_empty() {
        ValidationResult::Valid(None)
    } else {
        ValidationResult::Incomplete
    }
}
<commit_msg>Document Validator::validate_while_typing not being implemented<commit_after>//! Input validation API (Multi-line editing)

use crate::keymap::Invoke;
use crate::Result;

/// Input validation result
#[non_exhaustive]
pub enum ValidationResult {
    /// Incomplete input
    Incomplete,
    /// Validation fails with an optional error message. User must fix the
    /// input.
    Invalid(Option<String>),
    /// Validation succeeds with an optional message
    Valid(Option<String>),
}

/// Give access to user input.
pub struct ValidationContext<'i> {
    i: &'i mut dyn Invoke,
}

impl<'i> ValidationContext<'i> {
    pub(crate) fn new(i: &'i mut dyn Invoke) -> Self {
        ValidationContext { i }
    }

    /// Returns user input.
    pub fn input(&self) -> &str {
        self.i.input()
    }

    // TODO
    //fn invoke(&mut self, cmd: Cmd) -> Result<?> {
    //    self.i.invoke(cmd)
    //}
}

/// This trait provides an extension interface for determining whether
/// the current input buffer is valid. Rustyline uses the method
/// provided by this trait to decide whether hitting the enter key
/// will end the current editing session and return the current line
/// buffer to the caller of `Editor::readline` or variants.
pub trait Validator {
    /// Takes the currently edited `input` and returns a
    /// `ValidationResult` indicating whether it is valid or not along
    /// with an option message to display about the result. The most
    /// common validity check to implement is probably whether the
    /// input is complete or not, for instance ensuring that all
    /// delimiters are fully balanced.
    ///
    /// If you implement more complex validation checks it's probably
    /// a good idea to also implement a `Hinter` to provide feedback
    /// about what is invalid.
    ///
    /// For auto-correction like a missing closing quote or to reject invalid
    /// char while typing, the input will be mutable (TODO).
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        let _ = ctx;
        Ok(ValidationResult::Valid(None))
    }

    /// Configure whether validation is performed while typing or only
    /// when user presses the Enter key.
    ///
    /// Default is `false`.
    ///
    /// This feature is not yet implemented, so this function is currently a no-op
    fn validate_while_typing(&self) -> bool {
        false
    }
}

impl Validator for () {}

impl<'v, V: ?Sized + Validator> Validator for &'v V {
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        (**self).validate(ctx)
    }

    fn validate_while_typing(&self) -> bool {
        (**self).validate_while_typing()
    }
}

/// Simple matching bracket validator.
#[derive(Default)]
pub struct MatchingBracketValidator {
    _priv: (),
}

impl MatchingBracketValidator {
    /// Constructor
    pub fn new() -> Self {
        Self { _priv: () }
    }
}

impl Validator for MatchingBracketValidator {
    fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
        Ok(validate_brackets(ctx.input()))
    }
}

fn validate_brackets(input: &str) -> ValidationResult {
    let mut stack = vec![];
    for c in input.chars() {
        match c {
            '(' | '[' | '{' => stack.push(c),
            ')' | ']' | '}' => match (stack.pop(), c) {
                (Some('('), ')') | (Some('['), ']') | (Some('{'), '}') => {}
                (Some(wanted), _) => {
                    return ValidationResult::Invalid(Some(format!(
                        "Mismatched brackets: {:?} is not properly closed",
                        wanted
                    )))
                }
                (None, c) => {
                    return ValidationResult::Invalid(Some(format!(
                        "Mismatched brackets: {:?} is unpaired",
                        c
                    )))
                }
            },
            _ => {}
        }
    }
    if stack.is_empty() {
        ValidationResult::Valid(None)
    } else {
        ValidationResult::Incomplete
    }
}
<|endoftext|>


<commit_before>//! Base elements required to build views.
//!
//! Views are the main building blocks of your UI.
//!
//! A view can delegate part or all of its responsabilities to child views,
//! forming a view tree. The root of this tree is a `StackView` handled
//! directly by the `Cursive` element.
//!
//! # Layout
//!
//! The layout phase is when the size and location of each view is computed.
//!
//! Each view is given an area of the screen by the `View::layout()` method.
//! With this, the view is free to plan its content, including calling
//! `View::layout()` on its own children.
//!
//! In order to determine how much space should be given each child, parents
//! can use `View::required_size()` on them.
//!
//!
//! ### Contracts
//!
//! When building new Views, you should respect these contracts:
//!
//! * By default, `View::layout()` should be called before any call to
//!   `View::draw()` with the same available size. The only exceptions is
//!   when both following conditions are met:
//!     * The available size has not changed since the last call to
//!       `View::layout()`
//!     * `View::needs_relayout()` returns `false`
//!
//!   In this case, it is safe to omit the call to `View::layout()`.
//!
//! * The value returned by `required_size` should be an actually viable size,
//!   no matter what the request is. This means calling `View::layout()` with
//!   a size returned by `required_size` is **never** an error.

#[macro_use]
mod view_wrapper;

// Essentials components
mod position;
mod size_cache;
mod size_constraint;
mod view_path;

// Helper bases
mod scroll;
mod identifiable;
mod boxable;

pub use self::boxable::Boxable;
pub use self::identifiable::Identifiable;

pub use self::position::{Offset, Position};

pub use self::scroll::{ScrollBase, ScrollStrategy};

pub use self::size_cache::SizeCache;
pub use self::size_constraint::SizeConstraint;
pub use self::view_path::ViewPath;
pub use self::view_wrapper::ViewWrapper;
use Printer;

use direction::Direction;
use event::{Event, EventResult};
use vec::Vec2;
use views::IdView;

use std::any::Any;

/// Main trait defining a view behaviour.
pub trait View {
    /// Called when a key was pressed.
    ///
    /// Default implementation just ignores it.
    fn on_event(&mut self, Event) -> EventResult {
        EventResult::Ignored
    }

    /// Returns the minimum size the view requires with the given restrictions.
    ///
    /// If the view is flexible (it has multiple size options), it can try
    /// to return one that fits the given `constraint`.
    /// It's also fine to ignore it and return a fixed value.
    ///
    /// Default implementation always return `(1,1)`.
    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        let _ = constraint;
        Vec2::new(1, 1)
    }

    /// Returns `true` if the view content changed since last layout phase.
    ///
    /// This is mostly an optimisation for views where the layout phase is
    /// expensive.
    ///
    /// * Views can ignore it and always return true (default implementation).
    ///   They will always be assumed to have changed.
    /// * View Groups can ignore it and always re-layout their children.
    ///     * If they call `required_size` or `layout` with stable parameters,
    ///       the children may cache the result themselves and speed up the
    ///       process anyway.
    fn needs_relayout(&self) -> bool {
        true
    }

    /// Called once the size for this view has been decided,
    ///
    /// View groups should propagate the information to their children.
    fn layout(&mut self, Vec2) {}

    /// Draws the view with the given printer (includes bounds) and focus.
    fn draw(&self, printer: &Printer);

    /// Runs a closure on the view identified by the given selector.
    ///
    /// See [`Finder::call_on`] for a nicer interface, implemented for all views.
    ///
    /// [`Finder::call_on`]: trait.Finder.html#method.call_on
    ///
    /// If the selector doesn't find a match, the closure will not be run.
    ///
    /// Default implementation is a no-op.
    fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
        // TODO: FnMut -> FnOnce once it works
    }

    /// Moves the focus to the view identified by the given selector.
    ///
    /// Returns `Ok(())` if the view was found and selected.
    ///
    /// Default implementation simply returns `Err(())`.
    fn focus_view(&mut self, &Selector) -> Result<(), ()> {
        Err(())
    }

    /// This view is offered focus. Will it take it?
    ///
    /// `source` indicates where the focus comes from.
    /// When the source is unclear, `Front` is usually used.
    ///
    /// Default implementation always return `false`.
    fn take_focus(&mut self, source: Direction) -> bool {
        let _ = source;
        false
    }
}

/// Provides `call_on<V: View>` to views.
///
/// This trait is mostly a wrapper around [`View::call_on_any`].
///
/// It provides a nicer interface to find a view when you know its type.
///
/// [`View::call_on_any`]: ./trait.View.html#method.call_on_any
pub trait Finder {
    /// Tries to find the view pointed to by the given selector.
    ///
    /// If the view is not found, or if it is not of the asked type,
    /// it returns None.
    fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R;

    /// Convenient method to use `call_on` with a `view::Selector::Id`.
    fn find_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R
    {
        self.call_on(&Selector::Id(id), callback)
    }
}

impl<T: View> Finder for T {
    fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R
    {
        let mut result = None;
        {
            let result_ref = &mut result;

            let mut callback = Some(callback);
            let callback = |v: &mut Any| if let Some(callback) =
                callback.take() {
                if v.is::<V>() {
                    *result_ref = v.downcast_mut::<V>().map(|v| callback(v));
                } else if v.is::<IdView<V>>() {
                    *result_ref = v.downcast_mut::<IdView<V>>()
                        .and_then(|v| v.with_view_mut(callback));
                }
            };
            self.call_on_any(sel, Box::new(callback));
        }
        result
    }
}

/// Selects a single view (if any) in the tree.
pub enum Selector<'a> {
    /// Selects a view from its ID.
    Id(&'a str),
    /// Selects a view from its path.
    Path(&'a ViewPath),
}
<commit_msg>Implement View for Box<View><commit_after>//! Base elements required to build views.
//!
//! Views are the main building blocks of your UI.
//!
//! A view can delegate part or all of its responsabilities to child views,
//! forming a view tree. The root of this tree is a `StackView` handled
//! directly by the `Cursive` element.
//!
//! # Layout
//!
//! The layout phase is when the size and location of each view is computed.
//!
//! Each view is given an area of the screen by the `View::layout()` method.
//! With this, the view is free to plan its content, including calling
//! `View::layout()` on its own children.
//!
//! In order to determine how much space should be given each child, parents
//! can use `View::required_size()` on them.
//!
//!
//! ### Contracts
//!
//! When building new Views, you should respect these contracts:
//!
//! * By default, `View::layout()` should be called before any call to
//!   `View::draw()` with the same available size. The only exceptions is
//!   when both following conditions are met:
//!     * The available size has not changed since the last call to
//!       `View::layout()`
//!     * `View::needs_relayout()` returns `false`
//!
//!   In this case, it is safe to omit the call to `View::layout()`.
//!
//! * The value returned by `required_size` should be an actually viable size,
//!   no matter what the request is. This means calling `View::layout()` with
//!   a size returned by `required_size` is **never** an error.

#[macro_use]
mod view_wrapper;

// Essentials components
mod position;
mod size_cache;
mod size_constraint;
mod view_path;

// Helper bases
mod scroll;
mod identifiable;
mod boxable;

pub use self::boxable::Boxable;
pub use self::identifiable::Identifiable;

pub use self::position::{Offset, Position};

pub use self::scroll::{ScrollBase, ScrollStrategy};

pub use self::size_cache::SizeCache;
pub use self::size_constraint::SizeConstraint;
pub use self::view_path::ViewPath;
pub use self::view_wrapper::ViewWrapper;
use Printer;

use direction::Direction;
use event::{Event, EventResult};
use vec::Vec2;
use views::IdView;

use std::any::Any;

/// Main trait defining a view behaviour.
pub trait View {
    /// Called when a key was pressed.
    ///
    /// Default implementation just ignores it.
    fn on_event(&mut self, Event) -> EventResult {
        EventResult::Ignored
    }

    /// Returns the minimum size the view requires with the given restrictions.
    ///
    /// If the view is flexible (it has multiple size options), it can try
    /// to return one that fits the given `constraint`.
    /// It's also fine to ignore it and return a fixed value.
    ///
    /// Default implementation always return `(1,1)`.
    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        let _ = constraint;
        Vec2::new(1, 1)
    }

    /// Returns `true` if the view content changed since last layout phase.
    ///
    /// This is mostly an optimisation for views where the layout phase is
    /// expensive.
    ///
    /// * Views can ignore it and always return true (default implementation).
    ///   They will always be assumed to have changed.
    /// * View Groups can ignore it and always re-layout their children.
    ///     * If they call `required_size` or `layout` with stable parameters,
    ///       the children may cache the result themselves and speed up the
    ///       process anyway.
    fn needs_relayout(&self) -> bool {
        true
    }

    /// Called once the size for this view has been decided,
    ///
    /// View groups should propagate the information to their children.
    fn layout(&mut self, Vec2) {}

    /// Draws the view with the given printer (includes bounds) and focus.
    fn draw(&self, printer: &Printer);

    /// Runs a closure on the view identified by the given selector.
    ///
    /// See [`Finder::call_on`] for a nicer interface, implemented for all views.
    ///
    /// [`Finder::call_on`]: trait.Finder.html#method.call_on
    ///
    /// If the selector doesn't find a match, the closure will not be run.
    ///
    /// Default implementation is a no-op.
    fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
        // TODO: FnMut -> FnOnce once it works
    }

    /// Moves the focus to the view identified by the given selector.
    ///
    /// Returns `Ok(())` if the view was found and selected.
    ///
    /// Default implementation simply returns `Err(())`.
    fn focus_view(&mut self, &Selector) -> Result<(), ()> {
        Err(())
    }

    /// This view is offered focus. Will it take it?
    ///
    /// `source` indicates where the focus comes from.
    /// When the source is unclear, `Front` is usually used.
    ///
    /// Default implementation always return `false`.
    fn take_focus(&mut self, source: Direction) -> bool {
        let _ = source;
        false
    }
}

use std::ops::{Deref, DerefMut};
impl View for Box<View> {
    fn draw(&self, printer: &Printer) {
        self.deref().draw(printer)
    }

    fn required_size(&mut self, req: Vec2) -> Vec2 {
        self.deref_mut().required_size(req)
    }

    fn on_event(&mut self, ch: Event) -> EventResult {
        self.deref_mut().on_event(ch)
    }

    fn layout(&mut self, size: Vec2) {
        self.deref_mut().layout(size);
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        self.deref_mut().take_focus(source)
    }

    fn call_on_any<'a>(&mut self, selector: &Selector,
                    callback: Box<FnMut(&mut Any) + 'a>) {
        self.deref_mut().call_on_any(selector, callback)
    }

    fn needs_relayout(&self) -> bool {
        self.deref().needs_relayout()
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        self.deref_mut().focus_view(selector)
    }
}

/// Provides `call_on<V: View>` to views.
///
/// This trait is mostly a wrapper around [`View::call_on_any`].
///
/// It provides a nicer interface to find a view when you know its type.
///
/// [`View::call_on_any`]: ./trait.View.html#method.call_on_any
pub trait Finder {
    /// Tries to find the view pointed to by the given selector.
    ///
    /// If the view is not found, or if it is not of the asked type,
    /// it returns None.
    fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R;

    /// Convenient method to use `call_on` with a `view::Selector::Id`.
    fn find_id<V, F, R>(&mut self, id: &str, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R
    {
        self.call_on(&Selector::Id(id), callback)
    }
}

impl<T: View> Finder for T {
    fn call_on<V, F, R>(&mut self, sel: &Selector, callback: F) -> Option<R>
        where V: View + Any,
              F: FnOnce(&mut V) -> R
    {
        let mut result = None;
        {
            let result_ref = &mut result;

            let mut callback = Some(callback);
            let callback = |v: &mut Any| if let Some(callback) =
                callback.take() {
                if v.is::<V>() {
                    *result_ref = v.downcast_mut::<V>().map(|v| callback(v));
                } else if v.is::<IdView<V>>() {
                    *result_ref = v.downcast_mut::<IdView<V>>()
                        .and_then(|v| v.with_view_mut(callback));
                }
            };
            self.call_on_any(sel, Box::new(callback));
        }
        result
    }
}

/// Selects a single view (if any) in the tree.
pub enum Selector<'a> {
    /// Selects a view from its ID.
    Id(&'a str),
    /// Selects a view from its path.
    Path(&'a ViewPath),
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub};

pub struct Wrapping<T>(pub T);

impl<Lhs: WrappingAdd<Rhs>, Rhs> Add<Wrapping<Rhs>> for Wrapping<Lhs> {
    type Output = Wrapping<<Lhs as WrappingAdd<Rhs>>::Output>;
    fn add(self, rhs: Wrapping<Rhs>) -> Self::Output {
        Wrapping(self.0.wrapping_add(rhs.0))
    }
}

impl<Lhs: WrappingSub<Rhs>, Rhs> Sub<Wrapping<Rhs>> for Wrapping<Lhs> {
    type Output = Wrapping<<Lhs as WrappingSub<Rhs>>::Output>;
    fn sub(self, rhs: Wrapping<Rhs>) -> Self::Output {
        Wrapping(self.0.wrapping_sub(rhs.0))
    }
}

pub trait WrappingAdd<Rhs> {
    type Output;
    fn wrapping_add(self, rhs: Rhs) -> Self::Output;
}

pub trait WrappingSub<Rhs> {
    type Output;
    fn wrapping_sub(self, rhs: Rhs) -> Self::Output;
}

macro_rules! pod_impl {
    { $t:ty } => {
        impl WrappingAdd<$t> for $t {
            type Output = $t;
            fn wrapping_add(self, rhs: $t) -> $t {
                self.wrapping_add(rhs)
            }
        }

        impl WrappingSub<$t> for $t {
            type Output = $t;
            fn wrapping_sub(self, rhs: $t) -> $t {
                self.wrapping_sub(rhs)
            }
        }
    };
}

pod_impl! { u8 }
pod_impl! { u16 }
pod_impl! { u32 }
pod_impl! { u64 }
pod_impl! { usize }
pod_impl! { i8 }
pod_impl! { i16 }
pod_impl! { i32 }
pod_impl! { i64 }
pod_impl! { isize }
<commit_msg>Add test to make sure that the bad-looking wrapping impls don't loop<commit_after>use std::ops::{Add, Sub};

pub struct Wrapping<T>(pub T);

impl<Lhs: WrappingAdd<Rhs>, Rhs> Add<Wrapping<Rhs>> for Wrapping<Lhs> {
    type Output = Wrapping<<Lhs as WrappingAdd<Rhs>>::Output>;
    fn add(self, rhs: Wrapping<Rhs>) -> Self::Output {
        Wrapping(self.0.wrapping_add(rhs.0))
    }
}

impl<Lhs: WrappingSub<Rhs>, Rhs> Sub<Wrapping<Rhs>> for Wrapping<Lhs> {
    type Output = Wrapping<<Lhs as WrappingSub<Rhs>>::Output>;
    fn sub(self, rhs: Wrapping<Rhs>) -> Self::Output {
        Wrapping(self.0.wrapping_sub(rhs.0))
    }
}

pub trait WrappingAdd<Rhs> {
    type Output;
    fn wrapping_add(self, rhs: Rhs) -> Self::Output;
}

pub trait WrappingSub<Rhs> {
    type Output;
    fn wrapping_sub(self, rhs: Rhs) -> Self::Output;
}

macro_rules! pod_impl {
    { $t:ty } => {
        impl WrappingAdd<$t> for $t {
            type Output = $t;
            fn wrapping_add(self, rhs: $t) -> $t {
                self.wrapping_add(rhs)
            }
        }

        impl WrappingSub<$t> for $t {
            type Output = $t;
            fn wrapping_sub(self, rhs: $t) -> $t {
                self.wrapping_sub(rhs)
            }
        }
    };
}

pod_impl! { u8 }
pod_impl! { u16 }
pod_impl! { u32 }
pod_impl! { u64 }
pod_impl! { usize }
pod_impl! { i8 }
pod_impl! { i16 }
pod_impl! { i32 }
pod_impl! { i64 }
pod_impl! { isize }

#[cfg(test)]
mod tests {
    use super::{WrappingAdd, WrappingSub};

    #[test]
    fn no_loop() {
        assert_eq!(WrappingAdd::wrapping_add(0u8, 0u8), 0);
        assert_eq!(WrappingAdd::wrapping_add(0u16, 0u16), 0);
        assert_eq!(WrappingAdd::wrapping_add(0u32, 0u32), 0);
        assert_eq!(WrappingAdd::wrapping_add(0u64, 0u64), 0);
        assert_eq!(WrappingAdd::wrapping_add(0usize, 0usize), 0);
        assert_eq!(WrappingAdd::wrapping_add(0i8, 0i8), 0);
        assert_eq!(WrappingAdd::wrapping_add(0i16, 0i16), 0);
        assert_eq!(WrappingAdd::wrapping_add(0i32, 0i32), 0);
        assert_eq!(WrappingAdd::wrapping_add(0i64, 0i64), 0);
        assert_eq!(WrappingAdd::wrapping_add(0isize, 0isize), 0);

        assert_eq!(WrappingSub::wrapping_sub(0u8, 0u8), 0);
        assert_eq!(WrappingSub::wrapping_sub(0u16, 0u16), 0);
        assert_eq!(WrappingSub::wrapping_sub(0u32, 0u32), 0);
        assert_eq!(WrappingSub::wrapping_sub(0u64, 0u64), 0);
        assert_eq!(WrappingSub::wrapping_sub(0usize, 0usize), 0);
        assert_eq!(WrappingSub::wrapping_sub(0i8, 0i8), 0);
        assert_eq!(WrappingSub::wrapping_sub(0i16, 0i16), 0);
        assert_eq!(WrappingSub::wrapping_sub(0i32, 0i32), 0);
        assert_eq!(WrappingSub::wrapping_sub(0i64, 0i64), 0);
        assert_eq!(WrappingSub::wrapping_sub(0isize, 0isize), 0);
    }
}
<|endoftext|>


<commit_before>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::{InstBuilder, InstructionData, Opcode};
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };

        // TODO: Insert stack slot for FP and CSRs we will push
        let meta_stack_size = word_size; // TODO: this needs to change depending on CSRs
        let stack_offset = -(meta_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: meta_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = total_stack_size - meta_stack_size;

        // Append frame pointer to function signature
        let rbp_arg = ir::AbiParam::special_reg(
            ir::types::I64,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        );
        func.signature.params.push(rbp_arg);
        func.signature.returns.push(rbp_arg);

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        func.dfg.append_ebb_param(entry_ebb, ir::types::I64);

        // Find our frame pointer parameter Value
        let fp = func.special_param(ir::ArgumentPurpose::FramePointer)
            .expect("missing frame pointer");

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rbp as RegUnit,
                RU::rsp as RegUnit,
            );
            pos.ins().adjust_sp_imm(-(local_stack_size as i32));
        }

        let mut return_insts = Vec::new();

        for ebb in func.layout.ebbs() {
            for inst in func.layout.ebb_insts(ebb) {
                if let InstructionData::MultiAry { opcode, .. } = func.dfg[inst] {
                    if opcode == Opcode::Return {
                        return_insts.push(inst);
                    }
                }

            }
        }

        for inst in return_insts {
            let fp_ret = self.insert_epilogue(inst, local_stack_size as i32, func);
            func.dfg.append_inst_arg(inst, fp_ret);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i32,
        func: &mut ir::Function,
    ) -> ir::Value {
        let mut pos = EncCursor::new(func, self).at_inst(inst);
        pos.ins().adjust_sp_imm(stack_size);
        pos.ins().x86_pop(ir::types::I64)
    }
}
<commit_msg>Assign explicit register location to result of frame-pointer pop.<commit_after>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::{InstBuilder, InstructionData, Opcode};
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };

        // TODO: Insert stack slot for FP and CSRs we will push
        let meta_stack_size = word_size; // TODO: this needs to change depending on CSRs
        let stack_offset = -(meta_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: meta_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = total_stack_size - meta_stack_size;

        // Append frame pointer to function signature
        let rbp_arg = ir::AbiParam::special_reg(
            ir::types::I64,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        );
        func.signature.params.push(rbp_arg);
        func.signature.returns.push(rbp_arg);

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        func.dfg.append_ebb_param(entry_ebb, ir::types::I64);

        // Find our frame pointer parameter Value
        let fp = func.special_param(ir::ArgumentPurpose::FramePointer)
            .expect("missing frame pointer");

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rbp as RegUnit,
                RU::rsp as RegUnit,
            );
            pos.ins().adjust_sp_imm(-(local_stack_size as i32));
        }

        let mut return_insts = Vec::new();

        for ebb in func.layout.ebbs() {
            for inst in func.layout.ebb_insts(ebb) {
                if let InstructionData::MultiAry { opcode, .. } = func.dfg[inst] {
                    if opcode == Opcode::Return {
                        return_insts.push(inst);
                    }
                }

            }
        }

        for inst in return_insts {
            let fp_ret = self.insert_epilogue(inst, local_stack_size as i32, func);
            func.locations[fp_ret] = ir::ValueLoc::Reg(RU::rbp as RegUnit);
            func.dfg.append_inst_arg(inst, fp_ret);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i32,
        func: &mut ir::Function,
    ) -> ir::Value {
        let mut pos = EncCursor::new(func, self).at_inst(inst);
        pos.ins().adjust_sp_imm(stack_size);
        pos.ins().x86_pop(ir::types::I64)
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use gl;
use glh = gl_helpers;
use gl_types::{
    Color3,
    VertexCoord,
    TextureCoord,
    TextureId,
    ShaderId,
    VboId,
};
use core_types::Int;

pub struct Mesh {
    vertex_coords_vbo: VboId,
    color_vbo: Option<VboId>,
    texture_coords_vbo: Option<VboId>,
    texture_id: Option<TextureId>,
    length: Int,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertex_coords_vbo: 0,
            color_vbo: None,
            texture_coords_vbo: None,
            texture_id: None,
            length: 0,
        }
    }

    pub fn set_vertex_coords(&mut self, data: &[VertexCoord]) {
        self.length = data.len() as Int;
        self.vertex_coords_vbo = glh::gen_buffer();
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_coords_vbo);
        glh::fill_current_coord_vbo(data);
    }

    pub fn set_color(&mut self, data: &[Color3]) {
        assert_eq!(self.length, data.len() as Int);
        self.color_vbo = Some(glh::gen_buffer());
        gl::BindBuffer(gl::ARRAY_BUFFER, self.color_vbo.unwrap());
        glh::fill_current_color_vbo(data);
    }

    pub fn set_texture_coords(&mut self, data: &[TextureCoord]) {
        assert_eq!(self.length, data.len() as Int);
        self.texture_coords_vbo = Some(glh::gen_buffer());
        gl::BindBuffer(gl::ARRAY_BUFFER, self.texture_coords_vbo.unwrap());
        glh::fill_current_texture_coords_vbo(data);
    }

    pub fn set_texture(&mut self, texture_id: TextureId) {
        self.texture_id = Some(texture_id);
    }

    pub fn draw(&self, program: ShaderId) {
        if !self.texture_id.is_none() {
            let basic_texture_loc = glh::get_uniform(program, "basic_texture");
            gl::Uniform1ui(basic_texture_loc, 0);
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, self.texture_id.unwrap());
        }
        if !self.texture_coords_vbo.is_none() {
            gl::BindBuffer(gl::ARRAY_BUFFER, self.texture_coords_vbo.unwrap());
            let p = glh::get_attr(program, "in_texture_coordinates");
            glh::vertex_attrib_pointer(p, 2);
        }
        if !self.color_vbo.is_none() {
            gl::BindBuffer(gl::ARRAY_BUFFER, self.color_vbo.unwrap());
            let p = glh::get_attr(program, "color");
            glh::vertex_attrib_pointer(p, 3);
        }
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_coords_vbo);
        let p = glh::get_attr(program, "in_vertex_coordinates");
        glh::vertex_attrib_pointer(p, 3);
        glh::draw_mesh(self.length);
    }
}

impl Drop for Mesh {
    fn drop(&mut self) {
        glh::delete_buffer(self.vertex_coords_vbo);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Mesh: priv fields<commit_after>// See LICENSE file for copyright and license details.

use gl;
use glh = gl_helpers;
use gl_types::{
    Color3,
    VertexCoord,
    TextureCoord,
    TextureId,
    ShaderId,
    VboId,
};
use core_types::Int;

pub struct Mesh {
    priv vertex_coords_vbo: VboId,
    priv color_vbo: Option<VboId>,
    priv texture_coords_vbo: Option<VboId>,
    priv texture_id: Option<TextureId>,
    priv length: Int,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertex_coords_vbo: 0,
            color_vbo: None,
            texture_coords_vbo: None,
            texture_id: None,
            length: 0,
        }
    }

    pub fn set_vertex_coords(&mut self, data: &[VertexCoord]) {
        self.length = data.len() as Int;
        self.vertex_coords_vbo = glh::gen_buffer();
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_coords_vbo);
        glh::fill_current_coord_vbo(data);
    }

    pub fn set_color(&mut self, data: &[Color3]) {
        assert_eq!(self.length, data.len() as Int);
        self.color_vbo = Some(glh::gen_buffer());
        gl::BindBuffer(gl::ARRAY_BUFFER, self.color_vbo.unwrap());
        glh::fill_current_color_vbo(data);
    }

    pub fn set_texture_coords(&mut self, data: &[TextureCoord]) {
        assert_eq!(self.length, data.len() as Int);
        self.texture_coords_vbo = Some(glh::gen_buffer());
        gl::BindBuffer(gl::ARRAY_BUFFER, self.texture_coords_vbo.unwrap());
        glh::fill_current_texture_coords_vbo(data);
    }

    pub fn set_texture(&mut self, texture_id: TextureId) {
        self.texture_id = Some(texture_id);
    }

    pub fn draw(&self, program: ShaderId) {
        if !self.texture_id.is_none() {
            let basic_texture_loc = glh::get_uniform(program, "basic_texture");
            gl::Uniform1ui(basic_texture_loc, 0);
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, self.texture_id.unwrap());
        }
        if !self.texture_coords_vbo.is_none() {
            gl::BindBuffer(gl::ARRAY_BUFFER, self.texture_coords_vbo.unwrap());
            let p = glh::get_attr(program, "in_texture_coordinates");
            glh::vertex_attrib_pointer(p, 2);
        }
        if !self.color_vbo.is_none() {
            gl::BindBuffer(gl::ARRAY_BUFFER, self.color_vbo.unwrap());
            let p = glh::get_attr(program, "color");
            glh::vertex_attrib_pointer(p, 3);
        }
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_coords_vbo);
        let p = glh::get_attr(program, "in_vertex_coordinates");
        glh::vertex_attrib_pointer(p, 3);
        glh::draw_mesh(self.length);
    }
}

impl Drop for Mesh {
    fn drop(&mut self) {
        glh::delete_buffer(self.vertex_coords_vbo);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>