<commit_before>use crate::error::ParseMessageError;
use crate::structs;
use std::fmt;
use std::str::FromStr;

#[derive(Debug)]
pub enum Pw {
    Uid(u64),
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Sp {
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Gr {
    Gid(u64),
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Ent {
    Set(u32),
    Get(u32),
    End(u32),
}

pub struct DividedMessage {
    pub cont: bool,
    pub message: String,
}

impl DividedMessage {
    #[allow(dead_code)]
    pub fn new(msg: &str, size: usize) -> Vec<Self> {
        let mut msgs = vec![];
        let mut idx = 0;
        while idx + size < msg.len() {
            msgs.push(Self { cont: true,
                             message: msg[idx..idx + size].to_owned() });
            idx += size
        }
        msgs.push(Self { cont: false,
                         message: msg[idx..msg.len()].to_owned() });
        msgs
    }
}

impl fmt::Display for DividedMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}", if self.cont { 1 } else { 0 }, self.message)
    }
}

impl FromStr for DividedMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some(msg) = s.strip_prefix("0:") {
            Ok(Self { cont: false,
                      message: msg.to_owned() })
        } else if let Some(msg) = s.strip_prefix("1:") {
            Ok(Self { cont: true,
                      message: msg.to_owned() })
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

#[derive(Debug)]
pub enum ClientMessage {
    Cont,
    Key { user: String },
    Pam { user: String },
    CleanUp,
    RateLimit,
    SectorGroups,
    Pw(Pw),
    Sp(Sp),
    Gr(Gr),
}

#[allow(dead_code)]
#[derive(Debug)]
pub enum DaemonMessage {
    Success,
    Error {
        message: String,
    },
    Key {
        keys: String,
    },
    Pam {
        result: bool,
    },
    RateLimit {
        limit: usize,
        remaining: usize,
        reset: usize,
    },
    SectorGroups {
        sectors: Vec<structs::SectorGroup>,
    },
    Pw {
        login: String,
        uid: u64,
        gid: u64,
        home: String,
        sh: String,
    },
    Sp {
        login: String,
        pass: String,
    },
    Gr {
        sector: structs::SectorGroup,
    },
}

impl fmt::Display for Ent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Ent::Set(pid) => write!(f, "set|{}", pid),
            Ent::Get(pid) => write!(f, "get|{}", pid),
            Ent::End(pid) => write!(f, "end|{}", pid),
        }
    }
}

impl fmt::Display for Pw {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Pw::Uid(uid) => write!(f, "uid={}", uid),
            Pw::Nam(name) => write!(f, "name={}", name),
            Pw::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for Sp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Sp::Nam(name) => write!(f, "name={}", name),
            Sp::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for Gr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Gr::Gid(gid) => write!(f, "gid={}", gid),
            Gr::Nam(name) => write!(f, "name={}", name),
            Gr::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for ClientMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ClientMessage::Cont => write!(f, "c:cont"),
            ClientMessage::Key { user } => write!(f, "c:key:{}", user),
            ClientMessage::Pam { user } => write!(f, "c:pam:{}", user),
            ClientMessage::CleanUp => write!(f, "c:cleanup"),
            ClientMessage::RateLimit => write!(f, "c:ratelimit"),
            ClientMessage::SectorGroups => write!(f, "c:sectors"),
            ClientMessage::Pw(pw) => write!(f, "c:pw:{}", pw),
            ClientMessage::Sp(sp) => write!(f, "c:sp:{}", sp),
            ClientMessage::Gr(gr) => write!(f, "c:gr:{}", gr),
        }
    }
}

impl fmt::Display for DaemonMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DaemonMessage::Error { message } => write!(f, "d:error:{}", message),
            DaemonMessage::Success => write!(f, "d:success"),
            DaemonMessage::Key { keys } => write!(f, "d:key:{}", keys),
            DaemonMessage::Pam { result } => write!(f, "d:pam:{}", result),
            DaemonMessage::RateLimit { limit,
                                       remaining,
                                       reset, } => write!(f, "d:ratelimit:{}:{}:{}", limit, remaining, reset),
            DaemonMessage::SectorGroups { sectors } => {
                let ss: Vec<String> = sectors.iter().map(|s| s.to_string()).collect();
                write!(f, "d:sectors:{}", ss.join("\n"))
            }
            DaemonMessage::Pw { login,
                                uid,
                                gid,
                                home,
                                sh, } => write!(f, "d:pw:{}:{}:{}:{}:{}", login, uid, gid, home, sh),
            DaemonMessage::Sp { login, pass } => write!(f, "d:sp:{}:{}", login, pass),
            DaemonMessage::Gr { sector } => write!(f, "d:gr:{}", sector),
        }
    }
}

impl FromStr for Ent {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("set|") {
            Ok(Ent::Set(s.get(4..).unwrap_or_default().parse::<u32>().unwrap()))
        } else if s.starts_with("get|") {
            Ok(Ent::Get(s.get(4..).unwrap_or_default().parse::<u32>().unwrap()))
        } else if s.starts_with("end|") {
            Ok(Ent::End(s.get(4..).unwrap_or_default().parse::<u32>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Pw {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("uid=") {
            Ok(Pw::Uid(s.get(4..).unwrap_or_default().parse::<u64>().unwrap()))
        } else if s.starts_with("name=") {
            Ok(Pw::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Pw::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Sp {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("name=") {
            Ok(Sp::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Sp::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Gr {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("gid=") {
            Ok(Gr::Gid(s.get(4..).unwrap_or_default().parse::<u64>().unwrap()))
        } else if s.starts_with("name=") {
            Ok(Gr::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Gr::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for ClientMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("c:cont") {
            Ok(ClientMessage::Cont)
        } else if s.starts_with("c:key:") {
            Ok(ClientMessage::Key { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("c:pam:") {
            Ok(ClientMessage::Pam { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s == "c:cleanup" {
            Ok(ClientMessage::CleanUp)
        } else if s == "c:ratelimit" {
            Ok(ClientMessage::RateLimit)
        } else if s == "c:sectors" {
            Ok(ClientMessage::SectorGroups)
        } else if s.starts_with("c:pw:") {
            Ok(ClientMessage::Pw(s.get(5..).unwrap_or_default().parse::<Pw>()?))
        } else if s.starts_with("c:sp:") {
            Ok(ClientMessage::Sp(s.get(5..).unwrap_or_default().parse::<Sp>()?))
        } else if s.starts_with("c:gr:") {
            Ok(ClientMessage::Gr(s.get(5..).unwrap_or_default().parse::<Gr>()?))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for DaemonMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("d:key:") {
            Ok(DaemonMessage::Key { keys: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("d:pam:") {
            Ok(DaemonMessage::Pam { result: FromStr::from_str(s.get(6..).unwrap_or("false")).unwrap_or(false) })
        } else if s == "d:success" {
            Ok(DaemonMessage::Success)
        } else if s.starts_with("d:ratelimit:") {
            let fields: Vec<String> = s.get(12..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 3 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let limit = fields[0].clone().parse().unwrap_or(0);
            let remaining = fields[1].clone().parse().unwrap_or(0);
            let reset = fields[2].clone().parse().unwrap_or(0);
            Ok(DaemonMessage::RateLimit { limit,
                                          remaining,
                                          reset })
        } else if s.starts_with("d:sectors:") {
            let sectors = s.get(10..)
                           .unwrap_or_default()
                           .split('\n')
                           .filter_map(|l| l.parse::<structs::SectorGroup>().ok())
                           .collect();
            Ok(DaemonMessage::SectorGroups { sectors })
        } else if s.starts_with("d:pw:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 5 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let login: String = fields[0].clone();
            let home: String = fields[3].clone();
            let sh: String = fields[4].clone();
            match (fields[1].parse::<u64>(), fields[2].parse::<u64>()) {
                (Ok(uid), Ok(gid)) => Ok(DaemonMessage::Pw { login,
                                                             uid,
                                                             gid,
                                                             home,
                                                             sh }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else if s.starts_with("d:sp:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 2 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            Ok(DaemonMessage::Sp { login: fields[0].clone(),
                                   pass: fields[1].clone() })
        } else if s.starts_with("d:gr:") {
            match s.get(5..).unwrap_or_default().parse::<structs::SectorGroup>() {
                Ok(sector) => Ok(DaemonMessage::Gr { sector }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else {
            Err(ParseMessageError::ParseDaemonMessageError)
        }
    }
}
<commit_msg>Remove manual strips in Ent<commit_after>use crate::error::ParseMessageError;
use crate::structs;
use std::fmt;
use std::str::FromStr;

#[derive(Debug)]
pub enum Pw {
    Uid(u64),
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Sp {
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Gr {
    Gid(u64),
    Nam(String),
    Ent(Ent),
}

#[derive(Debug)]
pub enum Ent {
    Set(u32),
    Get(u32),
    End(u32),
}

pub struct DividedMessage {
    pub cont: bool,
    pub message: String,
}

impl DividedMessage {
    #[allow(dead_code)]
    pub fn new(msg: &str, size: usize) -> Vec<Self> {
        let mut msgs = vec![];
        let mut idx = 0;
        while idx + size < msg.len() {
            msgs.push(Self { cont: true,
                             message: msg[idx..idx + size].to_owned() });
            idx += size
        }
        msgs.push(Self { cont: false,
                         message: msg[idx..msg.len()].to_owned() });
        msgs
    }
}

impl fmt::Display for DividedMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}", if self.cont { 1 } else { 0 }, self.message)
    }
}

impl FromStr for DividedMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some(msg) = s.strip_prefix("0:") {
            Ok(Self { cont: false,
                      message: msg.to_owned() })
        } else if let Some(msg) = s.strip_prefix("1:") {
            Ok(Self { cont: true,
                      message: msg.to_owned() })
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

#[derive(Debug)]
pub enum ClientMessage {
    Cont,
    Key { user: String },
    Pam { user: String },
    CleanUp,
    RateLimit,
    SectorGroups,
    Pw(Pw),
    Sp(Sp),
    Gr(Gr),
}

#[allow(dead_code)]
#[derive(Debug)]
pub enum DaemonMessage {
    Success,
    Error {
        message: String,
    },
    Key {
        keys: String,
    },
    Pam {
        result: bool,
    },
    RateLimit {
        limit: usize,
        remaining: usize,
        reset: usize,
    },
    SectorGroups {
        sectors: Vec<structs::SectorGroup>,
    },
    Pw {
        login: String,
        uid: u64,
        gid: u64,
        home: String,
        sh: String,
    },
    Sp {
        login: String,
        pass: String,
    },
    Gr {
        sector: structs::SectorGroup,
    },
}

impl fmt::Display for Ent {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Ent::Set(pid) => write!(f, "set|{}", pid),
            Ent::Get(pid) => write!(f, "get|{}", pid),
            Ent::End(pid) => write!(f, "end|{}", pid),
        }
    }
}

impl fmt::Display for Pw {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Pw::Uid(uid) => write!(f, "uid={}", uid),
            Pw::Nam(name) => write!(f, "name={}", name),
            Pw::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for Sp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Sp::Nam(name) => write!(f, "name={}", name),
            Sp::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for Gr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Gr::Gid(gid) => write!(f, "gid={}", gid),
            Gr::Nam(name) => write!(f, "name={}", name),
            Gr::Ent(ent) => write!(f, "ent={}", ent),
        }
    }
}

impl fmt::Display for ClientMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ClientMessage::Cont => write!(f, "c:cont"),
            ClientMessage::Key { user } => write!(f, "c:key:{}", user),
            ClientMessage::Pam { user } => write!(f, "c:pam:{}", user),
            ClientMessage::CleanUp => write!(f, "c:cleanup"),
            ClientMessage::RateLimit => write!(f, "c:ratelimit"),
            ClientMessage::SectorGroups => write!(f, "c:sectors"),
            ClientMessage::Pw(pw) => write!(f, "c:pw:{}", pw),
            ClientMessage::Sp(sp) => write!(f, "c:sp:{}", sp),
            ClientMessage::Gr(gr) => write!(f, "c:gr:{}", gr),
        }
    }
}

impl fmt::Display for DaemonMessage {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DaemonMessage::Error { message } => write!(f, "d:error:{}", message),
            DaemonMessage::Success => write!(f, "d:success"),
            DaemonMessage::Key { keys } => write!(f, "d:key:{}", keys),
            DaemonMessage::Pam { result } => write!(f, "d:pam:{}", result),
            DaemonMessage::RateLimit { limit,
                                       remaining,
                                       reset, } => write!(f, "d:ratelimit:{}:{}:{}", limit, remaining, reset),
            DaemonMessage::SectorGroups { sectors } => {
                let ss: Vec<String> = sectors.iter().map(|s| s.to_string()).collect();
                write!(f, "d:sectors:{}", ss.join("\n"))
            }
            DaemonMessage::Pw { login,
                                uid,
                                gid,
                                home,
                                sh, } => write!(f, "d:pw:{}:{}:{}:{}:{}", login, uid, gid, home, sh),
            DaemonMessage::Sp { login, pass } => write!(f, "d:sp:{}:{}", login, pass),
            DaemonMessage::Gr { sector } => write!(f, "d:gr:{}", sector),
        }
    }
}

impl FromStr for Ent {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Some(msg) = s.strip_prefix("set|") {
            Ok(Ent::Set(msg.parse::<u32>().unwrap()))
        } else if let Some(msg) = s.strip_prefix("get|") {
            Ok(Ent::Get(msg.parse::<u32>().unwrap()))
        } else if let Some(msg) = s.strip_prefix("end|") {
            Ok(Ent::End(msg.parse::<u32>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Pw {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("uid=") {
            Ok(Pw::Uid(s.get(4..).unwrap_or_default().parse::<u64>().unwrap()))
        } else if s.starts_with("name=") {
            Ok(Pw::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Pw::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Sp {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("name=") {
            Ok(Sp::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Sp::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for Gr {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("gid=") {
            Ok(Gr::Gid(s.get(4..).unwrap_or_default().parse::<u64>().unwrap()))
        } else if s.starts_with("name=") {
            Ok(Gr::Nam(String::from(s.get(5..).unwrap_or_default())))
        } else if s.starts_with("ent=") {
            Ok(Gr::Ent(s.get(4..).unwrap_or_default().parse::<Ent>().unwrap()))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for ClientMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("c:cont") {
            Ok(ClientMessage::Cont)
        } else if s.starts_with("c:key:") {
            Ok(ClientMessage::Key { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("c:pam:") {
            Ok(ClientMessage::Pam { user: String::from(s.get(6..).unwrap_or_default()) })
        } else if s == "c:cleanup" {
            Ok(ClientMessage::CleanUp)
        } else if s == "c:ratelimit" {
            Ok(ClientMessage::RateLimit)
        } else if s == "c:sectors" {
            Ok(ClientMessage::SectorGroups)
        } else if s.starts_with("c:pw:") {
            Ok(ClientMessage::Pw(s.get(5..).unwrap_or_default().parse::<Pw>()?))
        } else if s.starts_with("c:sp:") {
            Ok(ClientMessage::Sp(s.get(5..).unwrap_or_default().parse::<Sp>()?))
        } else if s.starts_with("c:gr:") {
            Ok(ClientMessage::Gr(s.get(5..).unwrap_or_default().parse::<Gr>()?))
        } else {
            Err(ParseMessageError::ParseClientMessageError)
        }
    }
}

impl FromStr for DaemonMessage {
    type Err = ParseMessageError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.starts_with("d:key:") {
            Ok(DaemonMessage::Key { keys: String::from(s.get(6..).unwrap_or_default()) })
        } else if s.starts_with("d:pam:") {
            Ok(DaemonMessage::Pam { result: FromStr::from_str(s.get(6..).unwrap_or("false")).unwrap_or(false) })
        } else if s == "d:success" {
            Ok(DaemonMessage::Success)
        } else if s.starts_with("d:ratelimit:") {
            let fields: Vec<String> = s.get(12..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 3 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let limit = fields[0].clone().parse().unwrap_or(0);
            let remaining = fields[1].clone().parse().unwrap_or(0);
            let reset = fields[2].clone().parse().unwrap_or(0);
            Ok(DaemonMessage::RateLimit { limit,
                                          remaining,
                                          reset })
        } else if s.starts_with("d:sectors:") {
            let sectors = s.get(10..)
                           .unwrap_or_default()
                           .split('\n')
                           .filter_map(|l| l.parse::<structs::SectorGroup>().ok())
                           .collect();
            Ok(DaemonMessage::SectorGroups { sectors })
        } else if s.starts_with("d:pw:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 5 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            let login: String = fields[0].clone();
            let home: String = fields[3].clone();
            let sh: String = fields[4].clone();
            match (fields[1].parse::<u64>(), fields[2].parse::<u64>()) {
                (Ok(uid), Ok(gid)) => Ok(DaemonMessage::Pw { login,
                                                             uid,
                                                             gid,
                                                             home,
                                                             sh }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else if s.starts_with("d:sp:") {
            let fields: Vec<String> = s.get(5..)
                                       .unwrap_or_default()
                                       .split(':')
                                       .map(|s| s.to_string())
                                       .collect();
            if fields.len() < 2 {
                return Err(ParseMessageError::ParseDaemonMessageError);
            }
            Ok(DaemonMessage::Sp { login: fields[0].clone(),
                                   pass: fields[1].clone() })
        } else if s.starts_with("d:gr:") {
            match s.get(5..).unwrap_or_default().parse::<structs::SectorGroup>() {
                Ok(sector) => Ok(DaemonMessage::Gr { sector }),
                _ => Err(ParseMessageError::ParseDaemonMessageError),
            }
        } else {
            Err(ParseMessageError::ParseDaemonMessageError)
        }
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug, PartialEq)]
pub enum NumericReply {
    RPL_WELCOME = 1,
    RPL_YOURHOST,
    RPL_CREATED,
    RPL_MYINFO,
    RPL_BOUNCE_OR_SERVER_INFO = 5,
    RPL_MOTDSTART = 375,
    RPL_MOTD = 372,
    RPL_ENDOFMOTD = 376,
    ERR_NOSUCHNICK = 401,
    PING = 65533,
    PRIVMSG = 65534,
    NOTICE = 65535,
    NONE = -1,
}

impl FromStr for NumericReply {
    type Err = ();

    fn from_str(s: &str) -> Result<NumericReply, ()> {
        match s {
            "PRIVMSG" => Ok(NumericReply::PRIVMSG),
            "NOTICE" => Ok(NumericReply::NOTICE),
            "001" => Ok(NumericReply::RPL_WELCOME),
            "002" => Ok(NumericReply::RPL_YOURHOST),
            "003" => Ok(NumericReply::RPL_CREATED),
            "004" => Ok(NumericReply::RPL_MYINFO),
            "005" => Ok(NumericReply::RPL_BOUNCE_OR_SERVER_INFO),
            "372" => Ok(NumericReply::RPL_MOTD),
            "PING" => Ok(NumericReply::PING),
            _ => Ok(NumericReply::NONE)
        }
    }
}

trait Substring {
    fn substr(&self, start: u32, length: u32) -> &str;
}

impl Substring for str {
    fn substr(&self, start: u32, length: u32) -> &str {
        return &self[start as usize .. start as usize + length as usize];
    }
}

#[derive(Debug)]
pub struct IrcMessage {
    pub raw: String,
    pub prefix: String,
    pub command: NumericReply,
    pub params: Vec<String>
}

impl PartialEq for IrcMessage {
    fn eq(&self, other: &IrcMessage) -> bool {
        self.raw == other.raw
    }
}

// Thanks SirCmpwn for his awesome and simple way to parse IRC messages!
// https://github.com/SirCmpwn/ChatSharp/blob/master/ChatSharp/IrcMessage.cs
impl FromStr for IrcMessage {
    type Err = String;
    fn from_str(s: &str) -> Result<IrcMessage, String> {
        let mut msg = s.trim_right_matches(|c: char| c == '\r' || c == '\n');
        let raw_message_clone = String::from(msg);

        let mut prefix = String::new();
        let mut command: NumericReply = NumericReply::NONE;
        let mut params: Vec<String> = Vec::new();

        if msg.starts_with(":") {
            let whitespace: u32 = match msg.find(' ') {
                Some(x) => x as u32,
                None => 0u32
            };
            prefix = match String::from_str(msg.substr(1, whitespace - 1)) {
                Ok(x) => x,
                Err(_) => return Err(String::from("error parsing message prefix"))
            };
            msg = msg.substr(whitespace + 1, msg.len() as u32 - (whitespace+1));
        }

        if msg.contains(' ') {
            let idx = match msg.find(' ') {
                Some(x) => x as u32,
                None => 0u32
            };
            command = match NumericReply::from_str(msg.substr(0, idx)) {
                    Ok(x) => x,
                    Err(_) => return Err(format!("error parsing irc message {}", msg))
            };
            msg = msg.substr(idx + 1, msg.len() as u32 - (idx+1));

            // Parse parameters
            while msg != "" {
                if msg.starts_with(":") {
                    params.push(String::from(msg.substr(1, msg.len() as u32 - 1)));
                    break;
                }

                if !msg.contains(' ') {
                    params.push(String::from(msg));
                    msg = "";
                    break;
                }

                let idx = match msg.find(' ') {
                    Some(x) => x as u32,
                    None => 0u32
                };
                params.push(String::from(msg.substr(0, idx)));
                msg = msg.substr(idx+1, msg.len() as u32 - (idx+1));
            }
        }

        Ok(IrcMessage {
            raw: raw_message_clone,
            prefix: prefix,
            command: command,
            params: params
        })
    }
}
<commit_msg>Add WHOIS messages to numeric replies<commit_after>use std::str::FromStr;

#[derive(Debug, PartialEq)]
pub enum NumericReply {
    RPL_WELCOME = 1,
    RPL_YOURHOST,
    RPL_CREATED,
    RPL_MYINFO,
    RPL_BOUNCE_OR_SERVER_INFO = 5,
    RPL_WHOISUSER = 311,
    RPL_WHOISSERVER = 312,
    RPL_ENDOFWHOIS = 318,
    RPL_MOTDSTART = 375,
    RPL_MOTD = 372,
    RPL_ENDOFMOTD = 376,
    ERR_NOSUCHNICK = 401,
    PING = 65533,
    PRIVMSG = 65534,
    NOTICE = 65535,
    NONE = -1,
}

impl FromStr for NumericReply {
    type Err = ();

    fn from_str(s: &str) -> Result<NumericReply, ()> {
        match s {
            "PRIVMSG" => Ok(NumericReply::PRIVMSG),
            "NOTICE" => Ok(NumericReply::NOTICE),
            "001" => Ok(NumericReply::RPL_WELCOME),
            "002" => Ok(NumericReply::RPL_YOURHOST),
            "003" => Ok(NumericReply::RPL_CREATED),
            "004" => Ok(NumericReply::RPL_MYINFO),
            "005" => Ok(NumericReply::RPL_BOUNCE_OR_SERVER_INFO),
            "372" => Ok(NumericReply::RPL_MOTD),
            "311" => Ok(NumericReply::RPL_WHOISUSER),
            "312" => Ok(NumericReply::RPL_WHOISSERVER),
            "318" => Ok(NumericReply::RPL_ENDOFWHOIS),
            "PING" => Ok(NumericReply::PING),
            _ => Ok(NumericReply::NONE)
        }
    }
}

trait Substring {
    fn substr(&self, start: u32, length: u32) -> &str;
}

impl Substring for str {
    fn substr(&self, start: u32, length: u32) -> &str {
        return &self[start as usize .. start as usize + length as usize];
    }
}

#[derive(Debug)]
pub struct IrcMessage {
    pub raw: String,
    pub prefix: String,
    pub command: NumericReply,
    pub params: Vec<String>
}

impl PartialEq for IrcMessage {
    fn eq(&self, other: &IrcMessage) -> bool {
        self.raw == other.raw
    }
}

// Thanks SirCmpwn for his awesome and simple way to parse IRC messages!
// https://github.com/SirCmpwn/ChatSharp/blob/master/ChatSharp/IrcMessage.cs
impl FromStr for IrcMessage {
    type Err = String;
    fn from_str(s: &str) -> Result<IrcMessage, String> {
        let mut msg = s.trim_right_matches(|c: char| c == '\r' || c == '\n');
        let raw_message_clone = String::from(msg);

        let mut prefix = String::new();
        let mut command: NumericReply = NumericReply::NONE;
        let mut params: Vec<String> = Vec::new();

        if msg.starts_with(":") {
            let whitespace: u32 = match msg.find(' ') {
                Some(x) => x as u32,
                None => 0u32
            };
            prefix = match String::from_str(msg.substr(1, whitespace - 1)) {
                Ok(x) => x,
                Err(_) => return Err(String::from("error parsing message prefix"))
            };
            msg = msg.substr(whitespace + 1, msg.len() as u32 - (whitespace+1));
        }

        if msg.contains(' ') {
            let idx = match msg.find(' ') {
                Some(x) => x as u32,
                None => 0u32
            };
            command = match NumericReply::from_str(msg.substr(0, idx)) {
                    Ok(x) => x,
                    Err(_) => return Err(format!("error parsing irc message {}", msg))
            };
            msg = msg.substr(idx + 1, msg.len() as u32 - (idx+1));

            // Parse parameters
            while msg != "" {
                if msg.starts_with(":") {
                    params.push(String::from(msg.substr(1, msg.len() as u32 - 1)));
                    break;
                }

                if !msg.contains(' ') {
                    params.push(String::from(msg));
                    msg = "";
                    break;
                }

                let idx = match msg.find(' ') {
                    Some(x) => x as u32,
                    None => 0u32
                };
                params.push(String::from(msg.substr(0, idx)));
                msg = msg.substr(idx+1, msg.len() as u32 - (idx+1));
            }
        }

        Ok(IrcMessage {
            raw: raw_message_clone,
            prefix: prefix,
            command: command,
            params: params
        })
    }
}
<|endoftext|>


<commit_before>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Mir {
    blocks: Vec<Rc<RefCell<Block>>>,
    vars: Vec<VarDecl>,
    temps: Vec<TempDecl>,
}

impl Debug for Mir {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "mir.fct")
    }
}

impl Mir {
    pub fn new() -> Mir {
        Mir {
            blocks: Vec::new(),
            vars: Vec::new(),
            temps: Vec::new()
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut VarDecl {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &VarDecl {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, ty: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(VarDecl {
            name: name,
            ty: ty,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct VarDecl {
    name: Name,
    ty: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

pub struct TempDecl {
    ty: BuiltinType
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Mir::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<commit_msg>MIR: added Lvalue and Rvalue<commit_after>pub mod gen;
pub mod dump;

use std::cell::RefCell;
use std::rc::Rc;
use std::slice::{Iter, IterMut};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use ast::{BinOp, UnOp};
use interner::Name;
use sym::BuiltinType;

pub struct Mir {
    blocks: Vec<Rc<RefCell<Block>>>,
    vars: Vec<VarDecl>,
    temps: Vec<TempDecl>,
}

impl Debug for Mir {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "mir.fct")
    }
}

impl Mir {
    pub fn new() -> Mir {
        Mir {
            blocks: Vec::new(),
            vars: Vec::new(),
            temps: Vec::new()
        }
    }

    pub fn block(&self, id: BlockId) -> Rc<RefCell<Block>> {
        self.blocks[id.0].clone()
    }

    pub fn increase_var(&mut self, id: VarId) -> u32 {
        let var = self.var_mut(id);
        var.next_ssa += 1;

        var.next_ssa
    }

    pub fn var_mut(&mut self, id: VarId) -> &mut VarDecl {
        &mut self.vars[id.0]
    }

    pub fn var(&self, id: VarId) -> &VarDecl {
        &self.vars[id.0]
    }

    pub fn add_block(&mut self) -> BlockId {
        let id = BlockId(self.blocks.len());
        self.blocks.push(Rc::new(RefCell::new(Block::new(id))));

        id
    }

    pub fn add_var(&mut self, name: Name, ty: BuiltinType) -> VarId {
        let id = VarId(self.vars.len());
        self.vars.push(VarDecl {
            name: name,
            ty: ty,
            cur_ssa: 0,
            next_ssa: 0
        });

        id
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct VarId(usize);

impl ToString for VarId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct VarDecl {
    name: Name,
    ty: BuiltinType,
    cur_ssa: u32,
    next_ssa: u32,
}

pub struct TempDecl {
    ty: BuiltinType
}

pub enum Lvalue {
    Var(u32),
    Temp(u32)
}

pub enum Rvalue {
    Use(Operand),
    Un(UnOp, Operand),
    Bin(BinOp, Operand, Operand),
}

pub enum Operand {
    Consume(Lvalue),
    Const(u32)
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct BlockId(usize);

impl ToString for BlockId {
    fn to_string(&self) -> String {
        format!("{}", self.0)
    }
}

pub struct Block {
    id: BlockId,
    instructions: Vec<Instr>,
    predecessors: Vec<BlockId>,
}

impl Block {
    fn new(id: BlockId) -> Block {
        Block {
            id: id,
            instructions: Vec::new(),
            predecessors: Vec::new()
        }
    }

    fn add_instr(&mut self, instr: Instr) {
        self.instructions.push(instr);
    }

    fn last_instr(&self) -> Option<&Instr> {
        self.instructions.last()
    }

    fn add_predecessor(&mut self, id: BlockId) {
        self.predecessors.push(id);
    }

    fn find_phi_mut(&mut self, id: VarId) -> Option<&mut InstrPhiType> {
        for instr in &mut self.instructions {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                if phi.var_id == id {
                    return Some(phi);
                }

            } else {
                return None;
            }
        }

        None
    }

    fn add_phi(&mut self, phi: InstrPhiType) {
        let mut ind : usize = 0;

        for instr in &self.instructions {
            if let Instr::InstrPhi(ref instr_phi) = *instr {
                if instr_phi.var_id == phi.var_id {
                    panic!("phi-instruction for var {} already exists.",
                        phi.var_id.to_string());
                }

                ind += 1;
            } else {
                break;
            }
        }

        self.instructions.insert(ind, Instr::InstrPhi(phi));
    }

    fn phi_iter(&self) -> PhiIter {
        PhiIter {
            iter: self.instructions.iter()
        }
    }

    fn phi_iter_mut(&mut self) -> PhiIterMut {
        PhiIterMut {
            iter: self.instructions.iter_mut()
        }
    }
}

struct PhiIter<'a> {
    iter: Iter<'a, Instr>
}

impl<'a> Iterator for PhiIter<'a> {
    type Item = &'a InstrPhiType;

    fn next(&mut self) -> Option<&'a InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct PhiIterMut<'a> {
    iter: IterMut<'a, Instr>
}

impl<'a> Iterator for PhiIterMut<'a> {
    type Item = &'a mut InstrPhiType;

    fn next(&mut self) -> Option<&'a mut InstrPhiType> {
        if let Some(instr) = self.iter.next() {
            if let Instr::InstrPhi(ref mut phi) = *instr {
                Some(phi)
            } else {
                None
            }
        } else {
            None
        }
    }
}

pub enum Terminator {
    Ret,

    If {
        cond: Operand,
        targets: (BlockId, BlockId)
    },

    Goto {
        target: BlockId
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Instr {
    InstrRet(Option<Opnd>),
    InstrTest(InstrTestType),
    InstrBin(InstrBinType),
    InstrUn(InstrUnType),
    InstrAssign(InstrAssignType),
    InstrPhi(InstrPhiType),
    InstrCall(InstrCallType),
    InstrStr(InstrStrType),
    InstrGoto(BlockId),
}

impl Instr {
    fn ret() -> Instr {
        Instr::InstrRet(None)
    }

    fn ret_value(opnd: Opnd) -> Instr {
        Instr::InstrRet(Some(opnd))
    }

    fn test(opnd: Opnd, true_block: BlockId, false_block: BlockId) -> Instr {
        Instr::InstrTest(InstrTestType {
            opnd: opnd,
            true_block: true_block,
            false_block: false_block,
        })
    }

    fn bin(dest: Opnd, lhs: Opnd, op: BinOp, rhs: Opnd) -> Instr {
        Instr::InstrBin(InstrBinType {
            dest: dest,
            lhs: lhs,
            op: op,
            rhs: rhs,
        })
    }

    fn un(dest: Opnd, op: UnOp, src: Opnd) -> Instr {
        Instr::InstrUn(InstrUnType {
            dest: dest,
            op: op,
            src: src,
        })
    }

    fn assign(dest: Opnd, src: Opnd) -> Instr {
        Instr::InstrAssign(InstrAssignType {
            dest: dest,
            src: src,
        })
    }

    fn call(dest: Opnd, name: String, args: Vec<Opnd>) -> Instr {
        Instr::InstrCall(InstrCallType {
            dest: dest,
            name: name,
            args: args,
        })
    }

    fn str(dest: Opnd, value: String) -> Instr {
        Instr::InstrStr(InstrStrType {
            dest: dest,
            value: value,
        })
    }

    fn goto(target: BlockId) -> Instr {
        Instr::InstrGoto(target)
    }

    fn phi(var_id: VarId, dest: u32, opnds: Vec<u32>, backup: u32) -> Instr {
        Instr::InstrPhi(InstrPhiType {
            var_id: var_id,
            dest: dest,
            opnds: opnds,
            backup: backup,
        })
    }
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrTestType {
    pub opnd: Opnd,
    pub true_block: BlockId,
    pub false_block: BlockId,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrBinType {
    pub dest: Opnd,
    pub lhs: Opnd,
    pub op: BinOp,
    pub rhs: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrUnType {
    pub dest: Opnd,
    pub op: UnOp,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrAssignType {
    pub dest: Opnd,
    pub src: Opnd,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrCallType {
    pub dest: Opnd,
    pub name: String,
    pub args: Vec<Opnd>,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrPhiType {
    pub var_id: VarId,
    pub dest: u32,
    pub opnds: Vec<u32>,
    pub backup: u32,
}

#[derive(PartialEq, Eq, Debug)]
pub struct InstrStrType {
    pub dest: Opnd,
    pub value: String,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Opnd {
    OpndReg(u32),
    OpndVar(VarId, u32),
    OpndInt(i32),
    OpndBool(bool),
}

#[cfg(test)]
mod tests {
    use interner::Name;
    use mir::*;
    use mir::Instr::*;
    use sym::BuiltinType;

    #[test]
    fn find_phi_fails() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.find_phi_mut(VarId(0)));
    }

    #[test]
    fn find_phi_succeeds() {
        let mut block = Block::new(BlockId(0));
        let phi = Instr::phi(VarId(0), 0, Vec::new(), 0);
        block.add_instr(phi);

        assert!(block.find_phi_mut(VarId(0)).is_some());
        assert_eq!(None, block.find_phi_mut(VarId(1)));
    }

    #[test]
    fn increase_var() {
        let mut fct = Mir::new();
        let var_id = fct.add_var(Name(0), BuiltinType::Int);

        assert_eq!(1, fct.increase_var(var_id));
    }

    #[test]
    #[should_panic]
    fn add_phi_panics() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(0));
        block.add_phi(phi(0));
    }

    #[test]
    fn add_phi() {
        let mut block = Block::new(BlockId(0));

        block.add_instr(Instr::ret());
        block.add_phi(phi(0));
        block.add_phi(phi(1));
        block.add_phi(phi(2));

        let instrs = &block.instructions;

        assert_eq!(phi_instr(0), instrs[0]);
        assert_eq!(phi_instr(1), instrs[1]);
        assert_eq!(phi_instr(2), instrs[2]);
        assert_eq!(Instr::ret(), instrs[3]);
    }

    #[test]
    fn phi_iterator_empty() {
        let mut block = Block::new(BlockId(0));
        assert_eq!(None, block.phi_iter().next());
    }

    #[test]
    fn phi_iterator_single() {
        let mut block = Block::new(BlockId(0));
        block.add_phi(phi(3));
        block.add_instr(Instr::ret());

        let mut iter = block.phi_iter();
        assert_eq!(Some(&phi(3)), iter.next());
        assert_eq!(None, iter.next());
    }

    fn phi_instr(var: usize) -> Instr {
        InstrPhi(phi(var))
    }

    fn phi(var: usize) -> InstrPhiType {
        InstrPhiType {
            var_id: VarId(var),
            dest: 0,
            opnds: Vec::new(),
            backup: 0
        }
    }
}
<|endoftext|>


<commit_before>use messages::outgoing;
use mio;
use node::Node;
use node;
use routing_table::RoutingTable;
use routing_table;
use std::io::Cursor;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    RefreshBucket(u16)
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap
}

enum Status {
    Bootstrapped,
    Bootstrapping,
    Idle
}

impl Status {
    fn is_bootstrapping(&self) -> bool {
        match self {
            &Status::Bootstrapping => true,
            _ => false
        }
    }
}

pub struct Handler {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status
}

impl Handler {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<Node>>) -> Handler {
        let address = self_node.get_address();
        let routing_table = routing_table::RoutingTable::new(8, address, routers);

        Handler {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new()
        }
    }

    pub fn run(mut self) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let loop_channel = event_loop.channel();

        create_incoming_udp_channel(self.port, loop_channel.clone());
        loop_channel.send(OneshotTask::StartBootstrap).unwrap();
        event_loop.run(&mut self).unwrap();
    }

    fn handle_incoming(&mut self, data: Vec<u8>) {
        use messages::incoming;
        use messages::incoming::*;
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();
        println!("Message: {:?}", message);

        match message {
            Message::Query(transaction_id, query) => {
                match query {
                    Query::FindNode(origin, target) => {
                        {
                            let nodes: Vec<&Box<node::Node>> = self.routing_table.nearest_to(&target);
                            let response = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                nodes);
                            origin.send(response);
                        }

                        self.routing_table.insert(origin);
                    }
                }
            }
            Message::Response(_transaction_id, response) => {
                match response {
                    Response::FindNode(origin, nodes) => {
                        self.routing_table.insert(origin);

                        for node in nodes {
                            self.routing_table.insert(node);
                        }
                    }
                }
            }
        }
    }

    fn handle_start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        self.find_self(event_loop);
        self.status = Status::Bootstrapping;
    }

    fn find_self(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let query = outgoing::create_find_node_query(
            self.transaction_ids.generate(),
            &self.self_node,
            self.self_node.get_address());
        if let Some(node) = self.routing_table.nearest_to(&self.self_node.get_address()).get(0) {
            node.send(query);
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ();
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.handle_incoming(data),
            OneshotTask::StartBootstrap => {
                self.handle_start_bootstrap(event_loop);
            }
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: mio::Sender<OneshotTask>) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<commit_msg>Implement bootstrapping<commit_after>use messages::outgoing;
use mio;
use node::Node;
use node;
use routing_table::{InsertOutcome, RoutingTable};
use routing_table;
use std::collections::HashMap;
use std::io::Cursor;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    ContinueBootstrap
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap
}

enum TableAction {
    Bootstrap(mio::Timeout)
}

enum Status {
    Bootstrapped,
    Bootstrapping,
    Idle
}

pub struct Handler {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>
}

impl Handler {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<Node>>) -> Handler {
        let self_address = self_node.get_address();
        let routing_table = routing_table::RoutingTable::new(8, self_address, routers);

        Handler {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new()
        }
    }

    pub fn run(mut self) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let loop_channel = event_loop.channel();

        create_incoming_udp_channel(self.port, loop_channel.clone());
        loop_channel.send(OneshotTask::StartBootstrap).unwrap();
        event_loop.run(&mut self).unwrap();
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming;
        use messages::incoming::*;
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();
        println!("Routing table: {:?}", self.routing_table);

        match message {
            Message::Query(transaction_id, query) => {
                match query {
                    Query::FindNode(origin, target) => {
                        {
                            let nodes: Vec<&Box<node::Node>> = self.routing_table.nearest_to(&target);
                            let response = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                nodes);
                            origin.send(response);
                        }

                        self.routing_table.insert(origin).unwrap();
                    }
                }
            }
            Message::Response(transaction_id, response) => {
                match response {
                    Response::FindNode(origin, mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.routing_table.insert(node) {
                                Ok(InsertOutcome::Inserted) => { encounted_new_node = true; }
                                _ => { }
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                if encounted_new_node {
                                    // Continue botstrapping
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.status = Status::Bootstrapped;
                                }
                            }
                            _ => { }
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Self>) {
        let transaction_id = self.find_self();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn find_self(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            self.self_node.get_address());
        if let Some(node) = self.routing_table.nearest().get(0) {
            node.send(query);
        }
        transaction_id
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.start_bootstrap(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.continue_bootstrap(event_loop)
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: mio::Sender<OneshotTask>) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<|endoftext|>


<commit_before>use bindgen::{Builder, CodegenConfig, builder};
use clap::{App, Arg};
use std::fs::File;
use std::io::{self, Error, ErrorKind};

/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
pub fn builder_from_flags<I>
    (args: I)
     -> Result<(Builder, Box<io::Write>, bool), io::Error>
    where I: Iterator<Item = String>,
{
    let matches = App::new("bindgen")
        .version(env!("CARGO_PKG_VERSION"))
        .about("Generates Rust bindings from C/C++ headers.")
        .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
        .args(&[
            Arg::with_name("header")
                .help("C or C++ header file")
                .required(true),
            Arg::with_name("bitfield-enum")
                .long("bitfield-enum")
                .help("Mark any enum whose name matches <regex> as a set of \
                       bitfield flags instead of an enumeration.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("constified-enum")
                .long("constified-enum")
                .help("Mark any enum whose name matches <regex> as a set of \
                       constants instead of an enumeration.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("blacklist-type")
                .long("blacklist-type")
                .help("Mark a type as hidden.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("no-layout-tests")
                .long("no-layout-tests")
                .help("Avoid generating layout tests for any type."),
            Arg::with_name("no-derive-debug")
                .long("no-derive-debug")
                .help("Avoid deriving Debug on any type."),
            Arg::with_name("no-derive-default")
                .long("no-derive-default")
                .hidden(true)
                .help("Avoid deriving Default on any type."),
            Arg::with_name("with-derive-default")
                .long("with-derive-default")
                .help("Deriving Default on any type."),
            Arg::with_name("no-doc-comments")
                .long("no-doc-comments")
                .help("Avoid including doc comments in the output, see: \
                      https://github.com/servo/rust-bindgen/issues/426"),
            Arg::with_name("no-recursive-whitelist")
                .long("no-recursive-whitelist")
                .help("Avoid whitelisting types recursively"),
            Arg::with_name("objc-extern-crate")
                .long("objc-extern-crate")
                .help("Use extern crate instead of use for objc"),
            Arg::with_name("distrust-clang-mangling")
                .long("distrust-clang-mangling")
                .help("Do not trust the libclang-provided mangling"),
            Arg::with_name("builtins")
                .long("builtins")
                .help("Output bindings for builtin definitions, e.g. \
                       __builtin_va_list."),
            Arg::with_name("ctypes-prefix")
                .long("ctypes-prefix")
                .help("Use the given prefix before raw types instead of \
                      ::std::os::raw.")
                .value_name("prefix")
                .takes_value(true),
            // All positional arguments after the end of options marker, `--`
            Arg::with_name("clang-args")
                .multiple(true),
            Arg::with_name("dummy-uses")
                .long("dummy-uses")
                .help("For testing purposes, generate a C/C++ file containing \
                       dummy uses of all types defined in the input header.")
                .takes_value(true),
            Arg::with_name("emit-clang-ast")
                .long("emit-clang-ast")
                .help("Output the Clang AST for debugging purposes."),
            Arg::with_name("emit-ir")
                .long("emit-ir")
                .help("Output our internal IR for debugging purposes."),
            Arg::with_name("emit-ir-graphviz")
                .long("emit-ir-graphviz")
                .help("Dump graphviz dot file.")
                .value_name("path")
                .takes_value(true),
            Arg::with_name("enable-cxx-namespaces")
                .long("enable-cxx-namespaces")
                .help("Enable support for C++ namespaces."),
            Arg::with_name("disable-name-namespacing")
                .long("disable-name-namespacing")
                .help("Disable name namespacing if namespaces are disabled."),
            Arg::with_name("framework")
                .long("framework-link")
                .help("Link to framework.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("ignore-functions")
                .long("ignore-functions")
                .help("Do not generate bindings for functions or methods. This \
                       is useful when you only care about struct layouts."),
            Arg::with_name("generate")
                .long("generate")
                .help("Generate a given kind of items, split by commas. \
                       Valid values are \"functions\",\"types\", \"vars\", \
                       \"methods\", \"constructors\" and \"destructors\".")
                .takes_value(true),
            Arg::with_name("ignore-methods")
                .long("ignore-methods")
                .help("Do not generate bindings for methods."),
            Arg::with_name("dynamic")
                .short("l")
                .long("link")
                .help("Link to dynamic library.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("no-convert-floats")
                .long("no-convert-floats")
                .help("Don't automatically convert floats to f32/f64."),
            Arg::with_name("no-prepend-enum-name")
                .long("no-prepend-enum-name")
                .help("Do not prepend the enum name to bitfield or constant variants"),
            Arg::with_name("no-unstable-rust")
                .long("no-unstable-rust")
                .help("Do not generate unstable Rust code.")
                .multiple(true), // FIXME: Pass legacy test suite
            Arg::with_name("opaque-type")
                .long("opaque-type")
                .help("Mark a type as opaque.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("output")
                .short("o")
                .long("output")
                .help("Write Rust bindings to <output>.")
                .takes_value(true),
            Arg::with_name("raw-line")
                .long("raw-line")
                .help("Add a raw line of Rust code at the beginning of output.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("static")
                .long("static-link")
                .help("Link to static library.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("use-core")
                .long("use-core")
                .help("Use types from Rust core instead of std."),
            Arg::with_name("conservative-inline-namespaces")
                .long("conservative-inline-namespaces")
                .help("Conservatively generate inline namespaces to avoid name \
                       conflicts."),
            Arg::with_name("use-msvc-mangling")
                .long("use-msvc-mangling")
                .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."),
            Arg::with_name("whitelist-function")
                .long("whitelist-function")
                .help("Whitelist all the free-standing functions matching \
                       <regex>. Other non-whitelisted functions will not be \
                       generated.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("generate-inline-functions")
                .long("generate-inline-functions")
                .help("Whether inline functions should be generated."),
            Arg::with_name("whitelist-type")
                .long("whitelist-type")
                .help("Whitelist the type. Other non-whitelisted types will \
                       not be generated.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("whitelist-var")
                .long("whitelist-var")
                .help("Whitelist all the free-standing variables matching \
                       <regex>. Other non-whitelisted variables will not be \
                       generated.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("verbose")
                .long("verbose")
                .help("Print verbose error messages"),
        ]) // .args()
        .get_matches_from(args);

    let mut builder = builder();

    if let Some(header) = matches.value_of("header") {
        builder = builder.header(header);
    } else {
        return Err(Error::new(ErrorKind::Other, "Header not found"));
    }

    if let Some(bitfields) = matches.values_of("bitfield-enum") {
        for regex in bitfields {
            builder = builder.bitfield_enum(regex);
        }
    }

    if let Some(bitfields) = matches.values_of("constified-enum") {
        for regex in bitfields {
            builder = builder.constified_enum(regex);
        }
    }

    if let Some(hidden_types) = matches.values_of("blacklist-type") {
        for ty in hidden_types {
            builder = builder.hide_type(ty);
        }
    }

    if matches.is_present("builtins") {
        builder = builder.emit_builtins();
    }

    if matches.is_present("no-layout-tests") {
        builder = builder.layout_tests(false);
    }

    if matches.is_present("no-derive-debug") {
        builder = builder.derive_debug(false);
    }

    if matches.is_present("with-derive-default") {
        builder = builder.derive_default(true);
    }

    if matches.is_present("no-derive-default") {
        builder = builder.derive_default(false);
    }

    if matches.is_present("no-prepend-enum-name") {
        builder = builder.prepend_enum_name(false);
    }

    if let Some(prefix) = matches.value_of("ctypes-prefix") {
        builder = builder.ctypes_prefix(prefix);
    }

    if let Some(dummy) = matches.value_of("dummy-uses") {
        builder = builder.dummy_uses(dummy);
    }

    if let Some(links) = matches.values_of("dynamic") {
        for library in links {
            builder = builder.link(library);
        }
    }

    if let Some(what_to_generate) = matches.value_of("generate") {
        let mut config = CodegenConfig::nothing();
        for what in what_to_generate.split(",") {
            match what {
                "functions" => config.functions = true,
                "types" => config.types = true,
                "vars" => config.vars = true,
                "methods" => config.methods = true,
                "constructors" => config.constructors = true,
                "destructors" => config.destructors = true,
                _ => {
                    return Err(Error::new(ErrorKind::Other,
                                          "Unknown generate item"));
                }
            }
        }
        builder = builder.with_codegen_config(config);
    }

    if matches.is_present("emit-clang-ast") {
        builder = builder.emit_clang_ast();
    }

    if matches.is_present("emit-ir") {
        builder = builder.emit_ir();
    }

    if let Some(path) = matches.value_of("emit-ir-graphviz") {
        builder = builder.emit_ir_graphviz(path);
    }

    if matches.is_present("enable-cxx-namespaces") {
        builder = builder.enable_cxx_namespaces();
    }

    if matches.is_present("disable-name-namespacing") {
        builder = builder.disable_name_namespacing();
    }

    if let Some(links) = matches.values_of("framework") {
        for framework in links {
            builder = builder.link_framework(framework);
        }
    }

    if matches.is_present("ignore-functions") {
        builder = builder.ignore_functions();
    }

    if matches.is_present("ignore-methods") {
        builder = builder.ignore_methods();
    }

    if matches.is_present("no-unstable-rust") {
        builder = builder.no_unstable_rust();
    }

    if matches.is_present("no-convert-floats") {
        builder = builder.no_convert_floats();
    }

    if matches.is_present("no-doc-comments") {
        builder = builder.generate_comments(false);
    }

    if matches.is_present("no-recursive-whitelist") {
        builder = builder.whitelist_recursively(false);
    }

    if let Some(opaque_types) = matches.values_of("opaque-type") {
        for ty in opaque_types {
            builder = builder.opaque_type(ty);
        }
    }

    if let Some(lines) = matches.values_of("raw-line") {
        for line in lines {
            builder = builder.raw_line(line);
        }
    }

    if let Some(links) = matches.values_of("static") {
        for library in links {
            builder = builder.link_static(library);
        }
    }

    if matches.is_present("use-core") {
        builder = builder.use_core();
    }

    if matches.is_present("distrust-clang-mangling") {
        builder = builder.trust_clang_mangling(false);
    }

    if matches.is_present("conservative-inline-namespaces") {
        builder = builder.conservative_inline_namespaces();
    }

    if matches.is_present("generate-inline-functions") {
        builder = builder.generate_inline_functions(true);
    }

    if let Some(whitelist) = matches.values_of("whitelist-function") {
        for regex in whitelist {
            builder = builder.whitelisted_function(regex);
        }
    }

    if let Some(whitelist) = matches.values_of("whitelist-type") {
        for regex in whitelist {
            builder = builder.whitelisted_type(regex);
        }
    }

    if let Some(whitelist) = matches.values_of("whitelist-var") {
        for regex in whitelist {
            builder = builder.whitelisted_var(regex);
        }
    }

    if let Some(args) = matches.values_of("clang-args") {
        for arg in args {
            builder = builder.clang_arg(arg);
        }
    }

    let output = if let Some(path) = matches.value_of("output") {
        let file = try!(File::create(path));
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    let verbose = matches.is_present("verbose");

    Ok((builder, output, verbose))
}
<commit_msg>Auto merge of #670 - tmfink:doc-fix, r=emilio<commit_after>use bindgen::{Builder, CodegenConfig, builder};
use clap::{App, Arg};
use std::fs::File;
use std::io::{self, Error, ErrorKind};

/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
pub fn builder_from_flags<I>
    (args: I)
     -> Result<(Builder, Box<io::Write>, bool), io::Error>
    where I: Iterator<Item = String>,
{
    let matches = App::new("bindgen")
        .version(env!("CARGO_PKG_VERSION"))
        .about("Generates Rust bindings from C/C++ headers.")
        .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
        .args(&[
            Arg::with_name("header")
                .help("C or C++ header file")
                .required(true),
            Arg::with_name("bitfield-enum")
                .long("bitfield-enum")
                .help("Mark any enum whose name matches <regex> as a set of \
                       bitfield flags instead of an enumeration.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("constified-enum")
                .long("constified-enum")
                .help("Mark any enum whose name matches <regex> as a set of \
                       constants instead of an enumeration.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("blacklist-type")
                .long("blacklist-type")
                .help("Mark <type> as hidden.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("no-layout-tests")
                .long("no-layout-tests")
                .help("Avoid generating layout tests for any type."),
            Arg::with_name("no-derive-debug")
                .long("no-derive-debug")
                .help("Avoid deriving Debug on any type."),
            Arg::with_name("no-derive-default")
                .long("no-derive-default")
                .hidden(true)
                .help("Avoid deriving Default on any type."),
            Arg::with_name("with-derive-default")
                .long("with-derive-default")
                .help("Derive Default on any type."),
            Arg::with_name("no-doc-comments")
                .long("no-doc-comments")
                .help("Avoid including doc comments in the output, see: \
                      https://github.com/servo/rust-bindgen/issues/426"),
            Arg::with_name("no-recursive-whitelist")
                .long("no-recursive-whitelist")
                .help("Avoid whitelisting types recursively."),
            Arg::with_name("objc-extern-crate")
                .long("objc-extern-crate")
                .help("Use extern crate instead of use for objc."),
            Arg::with_name("distrust-clang-mangling")
                .long("distrust-clang-mangling")
                .help("Do not trust the libclang-provided mangling"),
            Arg::with_name("builtins")
                .long("builtins")
                .help("Output bindings for builtin definitions, e.g. \
                       __builtin_va_list."),
            Arg::with_name("ctypes-prefix")
                .long("ctypes-prefix")
                .help("Use the given prefix before raw types instead of \
                      ::std::os::raw.")
                .value_name("prefix")
                .takes_value(true),
            // All positional arguments after the end of options marker, `--`
            Arg::with_name("clang-args")
                .multiple(true),
            Arg::with_name("dummy-uses")
                .long("dummy-uses")
                .help("For testing purposes, generate a C/C++ file containing \
                       dummy uses of all types defined in the input header.")
                .takes_value(true),
            Arg::with_name("emit-clang-ast")
                .long("emit-clang-ast")
                .help("Output the Clang AST for debugging purposes."),
            Arg::with_name("emit-ir")
                .long("emit-ir")
                .help("Output our internal IR for debugging purposes."),
            Arg::with_name("emit-ir-graphviz")
                .long("emit-ir-graphviz")
                .help("Dump graphviz dot file.")
                .value_name("path")
                .takes_value(true),
            Arg::with_name("enable-cxx-namespaces")
                .long("enable-cxx-namespaces")
                .help("Enable support for C++ namespaces."),
            Arg::with_name("disable-name-namespacing")
                .long("disable-name-namespacing")
                .help("Disable namespacing via mangling, causing bindgen to \
                       generate names like \"Baz\" instead of \"foo_bar_Baz\" \
                       for an input name \"foo::bar::Baz\"."),
            Arg::with_name("framework")
                .long("framework-link")
                .help("Link to framework.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("ignore-functions")
                .long("ignore-functions")
                .help("Do not generate bindings for functions or methods. This \
                       is useful when you only care about struct layouts."),
            Arg::with_name("generate")
                .long("generate")
                .help("Generate only given items, split by commas. \
                       Valid values are \"functions\",\"types\", \"vars\", \
                       \"methods\", \"constructors\" and \"destructors\".")
                .takes_value(true),
            Arg::with_name("ignore-methods")
                .long("ignore-methods")
                .help("Do not generate bindings for methods."),
            Arg::with_name("dynamic")
                .short("l")
                .long("link")
                .help("Link to dynamic library.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("no-convert-floats")
                .long("no-convert-floats")
                .help("Do not automatically convert floats to f32/f64."),
            Arg::with_name("no-prepend-enum-name")
                .long("no-prepend-enum-name")
                .help("Do not prepend the enum name to bitfield or constant variants."),
            Arg::with_name("no-unstable-rust")
                .long("no-unstable-rust")
                .help("Do not generate unstable Rust code.")
                .multiple(true), // FIXME: Pass legacy test suite
            Arg::with_name("opaque-type")
                .long("opaque-type")
                .help("Mark <type> as opaque.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("output")
                .short("o")
                .long("output")
                .help("Write Rust bindings to <output>.")
                .takes_value(true),
            Arg::with_name("raw-line")
                .long("raw-line")
                .help("Add a raw line of Rust code at the beginning of output.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("static")
                .long("static-link")
                .help("Link to static library.")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("use-core")
                .long("use-core")
                .help("Use types from Rust core instead of std."),
            Arg::with_name("conservative-inline-namespaces")
                .long("conservative-inline-namespaces")
                .help("Conservatively generate inline namespaces to avoid name \
                       conflicts."),
            Arg::with_name("use-msvc-mangling")
                .long("use-msvc-mangling")
                .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."),
            Arg::with_name("whitelist-function")
                .long("whitelist-function")
                .help("Whitelist all the free-standing functions matching \
                       <regex>. Other non-whitelisted functions will not be \
                       generated.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("generate-inline-functions")
                .long("generate-inline-functions")
                .help("Generate inline functions."),
            Arg::with_name("whitelist-type")
                .long("whitelist-type")
                .help("Whitelist the type. Other non-whitelisted types will \
                       not be generated.")
                .value_name("type")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("whitelist-var")
                .long("whitelist-var")
                .help("Whitelist all the free-standing variables matching \
                       <regex>. Other non-whitelisted variables will not be \
                       generated.")
                .value_name("regex")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
            Arg::with_name("verbose")
                .long("verbose")
                .help("Print verbose error messages."),
        ]) // .args()
        .get_matches_from(args);

    let mut builder = builder();

    if let Some(header) = matches.value_of("header") {
        builder = builder.header(header);
    } else {
        return Err(Error::new(ErrorKind::Other, "Header not found"));
    }

    if let Some(bitfields) = matches.values_of("bitfield-enum") {
        for regex in bitfields {
            builder = builder.bitfield_enum(regex);
        }
    }

    if let Some(bitfields) = matches.values_of("constified-enum") {
        for regex in bitfields {
            builder = builder.constified_enum(regex);
        }
    }

    if let Some(hidden_types) = matches.values_of("blacklist-type") {
        for ty in hidden_types {
            builder = builder.hide_type(ty);
        }
    }

    if matches.is_present("builtins") {
        builder = builder.emit_builtins();
    }

    if matches.is_present("no-layout-tests") {
        builder = builder.layout_tests(false);
    }

    if matches.is_present("no-derive-debug") {
        builder = builder.derive_debug(false);
    }

    if matches.is_present("with-derive-default") {
        builder = builder.derive_default(true);
    }

    if matches.is_present("no-derive-default") {
        builder = builder.derive_default(false);
    }

    if matches.is_present("no-prepend-enum-name") {
        builder = builder.prepend_enum_name(false);
    }

    if let Some(prefix) = matches.value_of("ctypes-prefix") {
        builder = builder.ctypes_prefix(prefix);
    }

    if let Some(dummy) = matches.value_of("dummy-uses") {
        builder = builder.dummy_uses(dummy);
    }

    if let Some(links) = matches.values_of("dynamic") {
        for library in links {
            builder = builder.link(library);
        }
    }

    if let Some(what_to_generate) = matches.value_of("generate") {
        let mut config = CodegenConfig::nothing();
        for what in what_to_generate.split(",") {
            match what {
                "functions" => config.functions = true,
                "types" => config.types = true,
                "vars" => config.vars = true,
                "methods" => config.methods = true,
                "constructors" => config.constructors = true,
                "destructors" => config.destructors = true,
                _ => {
                    return Err(Error::new(ErrorKind::Other,
                                          "Unknown generate item"));
                }
            }
        }
        builder = builder.with_codegen_config(config);
    }

    if matches.is_present("emit-clang-ast") {
        builder = builder.emit_clang_ast();
    }

    if matches.is_present("emit-ir") {
        builder = builder.emit_ir();
    }

    if let Some(path) = matches.value_of("emit-ir-graphviz") {
        builder = builder.emit_ir_graphviz(path);
    }

    if matches.is_present("enable-cxx-namespaces") {
        builder = builder.enable_cxx_namespaces();
    }

    if matches.is_present("disable-name-namespacing") {
        builder = builder.disable_name_namespacing();
    }

    if let Some(links) = matches.values_of("framework") {
        for framework in links {
            builder = builder.link_framework(framework);
        }
    }

    if matches.is_present("ignore-functions") {
        builder = builder.ignore_functions();
    }

    if matches.is_present("ignore-methods") {
        builder = builder.ignore_methods();
    }

    if matches.is_present("no-unstable-rust") {
        builder = builder.no_unstable_rust();
    }

    if matches.is_present("no-convert-floats") {
        builder = builder.no_convert_floats();
    }

    if matches.is_present("no-doc-comments") {
        builder = builder.generate_comments(false);
    }

    if matches.is_present("no-recursive-whitelist") {
        builder = builder.whitelist_recursively(false);
    }

    if let Some(opaque_types) = matches.values_of("opaque-type") {
        for ty in opaque_types {
            builder = builder.opaque_type(ty);
        }
    }

    if let Some(lines) = matches.values_of("raw-line") {
        for line in lines {
            builder = builder.raw_line(line);
        }
    }

    if let Some(links) = matches.values_of("static") {
        for library in links {
            builder = builder.link_static(library);
        }
    }

    if matches.is_present("use-core") {
        builder = builder.use_core();
    }

    if matches.is_present("distrust-clang-mangling") {
        builder = builder.trust_clang_mangling(false);
    }

    if matches.is_present("conservative-inline-namespaces") {
        builder = builder.conservative_inline_namespaces();
    }

    if matches.is_present("generate-inline-functions") {
        builder = builder.generate_inline_functions(true);
    }

    if let Some(whitelist) = matches.values_of("whitelist-function") {
        for regex in whitelist {
            builder = builder.whitelisted_function(regex);
        }
    }

    if let Some(whitelist) = matches.values_of("whitelist-type") {
        for regex in whitelist {
            builder = builder.whitelisted_type(regex);
        }
    }

    if let Some(whitelist) = matches.values_of("whitelist-var") {
        for regex in whitelist {
            builder = builder.whitelisted_var(regex);
        }
    }

    if let Some(args) = matches.values_of("clang-args") {
        for arg in args {
            builder = builder.clang_arg(arg);
        }
    }

    let output = if let Some(path) = matches.value_of("output") {
        let file = try!(File::create(path));
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    let verbose = matches.is_present("verbose");

    Ok((builder, output, verbose))
}
<|endoftext|>