<commit_before>use std::fmt;
use {SdpLine, SdpBandwidth, SdpConnection};
use attribute_type::SdpAttribute;
use error::SdpParserError;

#[derive(Clone)]
pub struct SdpMediaLine {
    pub media: SdpMediaValue,
    pub port: u32,
    pub port_count: u32,
    pub proto: SdpProtocolValue,
    pub formats: SdpFormatList,
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpMediaValue {
    Audio,
    Video,
    Application,
}

impl fmt::Display for SdpMediaValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpMediaValue::Audio => "Audio",
            SdpMediaValue::Video => "Video",
            SdpMediaValue::Application => "Application",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpProtocolValue {
    RtpSavpf,
    UdpTlsRtpSavpf,
    TcpTlsRtpSavpf,
    DtlsSctp,
    UdpDtlsSctp,
    TcpDtlsSctp,
}

impl fmt::Display for SdpProtocolValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
            SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
            SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
            SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
            SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
            SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone)]
pub enum SdpFormatList {
    Integers(Vec<u32>),
    Strings(Vec<String>),
}

impl fmt::Display for SdpFormatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
            SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
        }
    }
}

pub struct SdpMedia {
    media: SdpMediaLine,
    information: Option<String>,
    connection: Option<SdpConnection>,
    bandwidth: Vec<SdpBandwidth>,
    key: Option<String>,
    attribute: Vec<SdpAttribute>,
}

impl SdpMedia {
    pub fn new(media: SdpMediaLine) -> SdpMedia {
        SdpMedia {
            media,
            information: None,
            connection: None,
            bandwidth: Vec::new(),
            key: None,
            attribute: Vec::new(),
        }
    }

    pub fn get_type(&self) -> &SdpMediaValue {
        &self.media.media
    }

    pub fn get_port(&self) -> u32 {
        self.media.port
    }

    pub fn get_port_count(&self) -> u32 {
        self.media.port_count
    }

    pub fn get_proto(&self) -> &SdpProtocolValue {
        &self.media.proto
    }

    pub fn get_formats(&self) -> &SdpFormatList {
        &self.media.formats
    }

    pub fn has_connection(&self) -> bool {
        self.connection.is_some()
    }

    pub fn has_bandwidth(&self) -> bool {
        !self.bandwidth.is_empty()
    }

    pub fn get_bandwidth(&self) -> &Vec<SdpBandwidth> {
        &self.bandwidth
    }

    pub fn has_attributes(&self) -> bool {
        !self.attribute.is_empty()
    }

    pub fn add_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserError> {
        if !attr.allowed_at_media_level() {
            return Err(SdpParserError::Line {
                           message: format!("{} not allowed at media level", attr),
                           line: "".to_string(),
                       });
        }
        Ok(self.attribute.push(attr.clone()))
    }

    pub fn add_bandwidth(&mut self, bw: &SdpBandwidth) {
        self.bandwidth.push(bw.clone())
    }

    pub fn set_connection(&mut self, c: &SdpConnection) -> Result<(), SdpParserError> {
        if self.connection.is_some() {
            return Err(SdpParserError::Line {
                           message: "connection type already exists at this media level"
                               .to_string(),
                           line: "".to_string(),
                       });
        }
        Ok(self.connection = Some(c.clone()))
    }
}
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserError> {
    Ok(match value.to_lowercase().as_ref() {
           "audio" => SdpMediaValue::Audio,
           "video" => SdpMediaValue::Video,
           "application" => SdpMediaValue::Application,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported media value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_media_token() {
    let audio = parse_media_token("audio");
    assert!(audio.is_ok());
    assert_eq!(audio.unwrap(), SdpMediaValue::Audio);
    let video = parse_media_token("VIDEO");
    assert!(video.is_ok());
    assert_eq!(video.unwrap(), SdpMediaValue::Video);
    let app = parse_media_token("aPplIcatIOn");
    assert!(app.is_ok());
    assert_eq!(app.unwrap(), SdpMediaValue::Application);

    assert!(parse_media_token("").is_err());
    assert!(parse_media_token("foobar").is_err());
}

fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserError> {
    Ok(match value.to_uppercase().as_ref() {
           "RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
           "UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
           "TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
           "DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
           "UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
           "TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported protocol value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_protocol_token() {
    let rtps = parse_protocol_token("rtp/savpf");
    assert!(rtps.is_ok());
    assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
    let udps = parse_protocol_token("udp/tls/rtp/savpf");
    assert!(udps.is_ok());
    assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
    let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
    assert!(tcps.is_ok());
    assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
    let dtls = parse_protocol_token("dtLs/ScTP");
    assert!(dtls.is_ok());
    assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
    let usctp = parse_protocol_token("udp/DTLS/sctp");
    assert!(usctp.is_ok());
    assert_eq!(usctp.unwrap(), SdpProtocolValue::UdpDtlsSctp);
    let tsctp = parse_protocol_token("tcp/dtls/SCTP");
    assert!(tsctp.is_ok());
    assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);

    assert!(parse_protocol_token("").is_err());
    assert!(parse_protocol_token("foobar").is_err());
}

pub fn parse_media(value: &str) -> Result<SdpLine, SdpParserError> {
    let mv: Vec<&str> = value.split_whitespace().collect();
    if mv.len() < 4 {
        return Err(SdpParserError::Line {
                       message: "media attribute must have at least four tokens".to_string(),
                       line: value.to_string(),
                   });
    }
    let media = parse_media_token(mv[0])?;
    let mut ptokens = mv[1].split('/');
    let port = match ptokens.next() {
        None => {
            return Err(SdpParserError::Line {
                           message: "missing port token".to_string(),
                           line: value.to_string(),
                       })
        }
        Some(p) => p.parse::<u32>()?,
    };
    if port > 65535 {
        return Err(SdpParserError::Line {
                       message: "media port token is too big".to_string(),
                       line: value.to_string(),
                   });
    }
    let port_count = match ptokens.next() {
        None => 0,
        Some(c) => c.parse::<u32>()?,
    };
    let proto = parse_protocol_token(mv[2])?;
    let fmt_slice: &[&str] = &mv[3..];
    let formats = match media {
        SdpMediaValue::Audio | SdpMediaValue::Video => {
            let mut fmt_vec: Vec<u32> = vec![];
            for num in fmt_slice {
                let fmt_num = num.parse::<u32>()?;
                match fmt_num {
                    0  |  // PCMU
                    8  |  // PCMA
                    9  |  // G722
                    13 |  // Comfort Noise
                    96 ... 127 => (),  // dynamic range
                    _ => return Err(SdpParserError::Line {
                          message: "format number in media line is out of range".to_string(),
                          line: value.to_string() }),
                };
                fmt_vec.push(fmt_num);
            }
            SdpFormatList::Integers(fmt_vec)
        }
        SdpMediaValue::Application => {
            let mut fmt_vec: Vec<String> = vec![];
            // TODO enforce length == 1 and content 'webrtc-datachannel' only?
            for token in fmt_slice {
                fmt_vec.push(String::from(*token));
            }
            SdpFormatList::Strings(fmt_vec)
        }
    };
    let m = SdpMediaLine {
        media,
        port,
        port_count,
        proto,
        formats,
    };
    println!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
    Ok(SdpLine::Media(m))
}

#[test]
fn test_media_works() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
    assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
    assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());

    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
    assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
    assert!(parse_media("audio 9/2 UDP/TLS/RTP/SAVPF 8").is_ok());
}

#[test]
fn test_media_missing_token() {
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
}

#[test]
fn test_media_invalid_port_number() {
    assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_type() {
    assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_port() {
    assert!(parse_media("audio / UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_transport() {
    assert!(parse_media("audio 9 invalid/invalid 8").is_err());
}

#[test]
fn test_media_invalid_payload() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
}

pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
    let mut media_sections: Vec<SdpMedia> = Vec::new();
    let mut sdp_media = match lines[0] {
        SdpLine::Media(ref v) => SdpMedia::new(v.clone()),
        _ => {
            return Err(SdpParserError::Sequence {
                           message: "first line in media section needs to be a media line"
                               .to_string(),
                           line: None,
                       })
        }
    };
    for line in lines.iter().skip(1) {
        match *line {
            SdpLine::Connection(ref c) => sdp_media.set_connection(c)?,
            SdpLine::Bandwidth(ref b) => sdp_media.add_bandwidth(b),
            SdpLine::Attribute(ref a) => sdp_media.add_attribute(a)?,
            SdpLine::Media(ref v) => {
                media_sections.push(sdp_media);
                sdp_media = SdpMedia::new(v.clone());
            }

            SdpLine::Information(_) |
            SdpLine::Key(_) => {
                return Err(SdpParserError::Unsupported {
                               message: "unsupported type found".to_string(),
                               line: "".to_string(),
                           })
            }

            SdpLine::Email(_) |
            SdpLine::Phone(_) |
            SdpLine::Origin(_) |
            SdpLine::Repeat(_) |
            SdpLine::Session(_) |
            SdpLine::Timing(_) |
            SdpLine::Uri(_) |
            SdpLine::Version(_) |
            SdpLine::Zone(_) => {
                return Err(SdpParserError::Sequence {
                               message: "invalid type in media section".to_string(),
                               line: None,
                           })
            }
        };
    }
    media_sections.push(sdp_media);
    Ok(media_sections)
}
// TODO add unit tests for parse_media_vector
<commit_msg>Fixes #58: Implement getter for attribute on SdpMedia (#59)<commit_after>use std::fmt;
use {SdpLine, SdpBandwidth, SdpConnection};
use attribute_type::SdpAttribute;
use error::SdpParserError;

#[derive(Clone)]
pub struct SdpMediaLine {
    pub media: SdpMediaValue,
    pub port: u32,
    pub port_count: u32,
    pub proto: SdpProtocolValue,
    pub formats: SdpFormatList,
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpMediaValue {
    Audio,
    Video,
    Application,
}

impl fmt::Display for SdpMediaValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpMediaValue::Audio => "Audio",
            SdpMediaValue::Video => "Video",
            SdpMediaValue::Application => "Application",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum SdpProtocolValue {
    RtpSavpf,
    UdpTlsRtpSavpf,
    TcpTlsRtpSavpf,
    DtlsSctp,
    UdpDtlsSctp,
    TcpDtlsSctp,
}

impl fmt::Display for SdpProtocolValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match *self {
            SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
            SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
            SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
            SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
            SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
            SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
        };
        write!(f, "{}", printable)
    }
}

#[derive(Clone)]
pub enum SdpFormatList {
    Integers(Vec<u32>),
    Strings(Vec<String>),
}

impl fmt::Display for SdpFormatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
            SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
        }
    }
}

pub struct SdpMedia {
    media: SdpMediaLine,
    information: Option<String>,
    connection: Option<SdpConnection>,
    bandwidth: Vec<SdpBandwidth>,
    key: Option<String>,
    attribute: Vec<SdpAttribute>,
}

impl SdpMedia {
    pub fn new(media: SdpMediaLine) -> SdpMedia {
        SdpMedia {
            media,
            information: None,
            connection: None,
            bandwidth: Vec::new(),
            key: None,
            attribute: Vec::new(),
        }
    }

    pub fn get_type(&self) -> &SdpMediaValue {
        &self.media.media
    }

    pub fn get_port(&self) -> u32 {
        self.media.port
    }

    pub fn get_port_count(&self) -> u32 {
        self.media.port_count
    }

    pub fn get_proto(&self) -> &SdpProtocolValue {
        &self.media.proto
    }

    pub fn get_formats(&self) -> &SdpFormatList {
        &self.media.formats
    }

    pub fn has_connection(&self) -> bool {
        self.connection.is_some()
    }

    pub fn has_bandwidth(&self) -> bool {
        !self.bandwidth.is_empty()
    }

    pub fn get_bandwidth(&self) -> &Vec<SdpBandwidth> {
        &self.bandwidth
    }

    pub fn has_attributes(&self) -> bool {
        !self.attribute.is_empty()
    }

    pub fn get_attributes(&self) -> &[SdpAttribute] {
        &self.attribute
    }

    pub fn add_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserError> {
        if !attr.allowed_at_media_level() {
            return Err(SdpParserError::Line {
                           message: format!("{} not allowed at media level", attr),
                           line: "".to_string(),
                       });
        }
        Ok(self.attribute.push(attr.clone()))
    }

    pub fn add_bandwidth(&mut self, bw: &SdpBandwidth) {
        self.bandwidth.push(bw.clone())
    }

    pub fn set_connection(&mut self, c: &SdpConnection) -> Result<(), SdpParserError> {
        if self.connection.is_some() {
            return Err(SdpParserError::Line {
                           message: "connection type already exists at this media level"
                               .to_string(),
                           line: "".to_string(),
                       });
        }
        Ok(self.connection = Some(c.clone()))
    }
}
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserError> {
    Ok(match value.to_lowercase().as_ref() {
           "audio" => SdpMediaValue::Audio,
           "video" => SdpMediaValue::Video,
           "application" => SdpMediaValue::Application,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported media value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_media_token() {
    let audio = parse_media_token("audio");
    assert!(audio.is_ok());
    assert_eq!(audio.unwrap(), SdpMediaValue::Audio);
    let video = parse_media_token("VIDEO");
    assert!(video.is_ok());
    assert_eq!(video.unwrap(), SdpMediaValue::Video);
    let app = parse_media_token("aPplIcatIOn");
    assert!(app.is_ok());
    assert_eq!(app.unwrap(), SdpMediaValue::Application);

    assert!(parse_media_token("").is_err());
    assert!(parse_media_token("foobar").is_err());
}

fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserError> {
    Ok(match value.to_uppercase().as_ref() {
           "RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
           "UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
           "TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
           "DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
           "UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
           "TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
           _ => {
               return Err(SdpParserError::Unsupported {
                              message: "unsupported protocol value".to_string(),
                              line: value.to_string(),
                          })
           }
       })
}

#[test]
fn test_parse_protocol_token() {
    let rtps = parse_protocol_token("rtp/savpf");
    assert!(rtps.is_ok());
    assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
    let udps = parse_protocol_token("udp/tls/rtp/savpf");
    assert!(udps.is_ok());
    assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
    let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
    assert!(tcps.is_ok());
    assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
    let dtls = parse_protocol_token("dtLs/ScTP");
    assert!(dtls.is_ok());
    assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
    let usctp = parse_protocol_token("udp/DTLS/sctp");
    assert!(usctp.is_ok());
    assert_eq!(usctp.unwrap(), SdpProtocolValue::UdpDtlsSctp);
    let tsctp = parse_protocol_token("tcp/dtls/SCTP");
    assert!(tsctp.is_ok());
    assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);

    assert!(parse_protocol_token("").is_err());
    assert!(parse_protocol_token("foobar").is_err());
}

pub fn parse_media(value: &str) -> Result<SdpLine, SdpParserError> {
    let mv: Vec<&str> = value.split_whitespace().collect();
    if mv.len() < 4 {
        return Err(SdpParserError::Line {
                       message: "media attribute must have at least four tokens".to_string(),
                       line: value.to_string(),
                   });
    }
    let media = parse_media_token(mv[0])?;
    let mut ptokens = mv[1].split('/');
    let port = match ptokens.next() {
        None => {
            return Err(SdpParserError::Line {
                           message: "missing port token".to_string(),
                           line: value.to_string(),
                       })
        }
        Some(p) => p.parse::<u32>()?,
    };
    if port > 65535 {
        return Err(SdpParserError::Line {
                       message: "media port token is too big".to_string(),
                       line: value.to_string(),
                   });
    }
    let port_count = match ptokens.next() {
        None => 0,
        Some(c) => c.parse::<u32>()?,
    };
    let proto = parse_protocol_token(mv[2])?;
    let fmt_slice: &[&str] = &mv[3..];
    let formats = match media {
        SdpMediaValue::Audio | SdpMediaValue::Video => {
            let mut fmt_vec: Vec<u32> = vec![];
            for num in fmt_slice {
                let fmt_num = num.parse::<u32>()?;
                match fmt_num {
                    0  |  // PCMU
                    8  |  // PCMA
                    9  |  // G722
                    13 |  // Comfort Noise
                    96 ... 127 => (),  // dynamic range
                    _ => return Err(SdpParserError::Line {
                          message: "format number in media line is out of range".to_string(),
                          line: value.to_string() }),
                };
                fmt_vec.push(fmt_num);
            }
            SdpFormatList::Integers(fmt_vec)
        }
        SdpMediaValue::Application => {
            let mut fmt_vec: Vec<String> = vec![];
            // TODO enforce length == 1 and content 'webrtc-datachannel' only?
            for token in fmt_slice {
                fmt_vec.push(String::from(*token));
            }
            SdpFormatList::Strings(fmt_vec)
        }
    };
    let m = SdpMediaLine {
        media,
        port,
        port_count,
        proto,
        formats,
    };
    println!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
    Ok(SdpLine::Media(m))
}

#[test]
fn test_media_works() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
    assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
    assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());

    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
    assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
    assert!(parse_media("audio 9/2 UDP/TLS/RTP/SAVPF 8").is_ok());
}

#[test]
fn test_media_missing_token() {
    assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
}

#[test]
fn test_media_invalid_port_number() {
    assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_type() {
    assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_port() {
    assert!(parse_media("audio / UDP/TLS/RTP/SAVPF 8").is_err());
}

#[test]
fn test_media_invalid_transport() {
    assert!(parse_media("audio 9 invalid/invalid 8").is_err());
}

#[test]
fn test_media_invalid_payload() {
    assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
}

pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
    let mut media_sections: Vec<SdpMedia> = Vec::new();
    let mut sdp_media = match lines[0] {
        SdpLine::Media(ref v) => SdpMedia::new(v.clone()),
        _ => {
            return Err(SdpParserError::Sequence {
                           message: "first line in media section needs to be a media line"
                               .to_string(),
                           line: None,
                       })
        }
    };
    for line in lines.iter().skip(1) {
        match *line {
            SdpLine::Connection(ref c) => sdp_media.set_connection(c)?,
            SdpLine::Bandwidth(ref b) => sdp_media.add_bandwidth(b),
            SdpLine::Attribute(ref a) => sdp_media.add_attribute(a)?,
            SdpLine::Media(ref v) => {
                media_sections.push(sdp_media);
                sdp_media = SdpMedia::new(v.clone());
            }

            SdpLine::Information(_) |
            SdpLine::Key(_) => {
                return Err(SdpParserError::Unsupported {
                               message: "unsupported type found".to_string(),
                               line: "".to_string(),
                           })
            }

            SdpLine::Email(_) |
            SdpLine::Phone(_) |
            SdpLine::Origin(_) |
            SdpLine::Repeat(_) |
            SdpLine::Session(_) |
            SdpLine::Timing(_) |
            SdpLine::Uri(_) |
            SdpLine::Version(_) |
            SdpLine::Zone(_) => {
                return Err(SdpParserError::Sequence {
                               message: "invalid type in media section".to_string(),
                               line: None,
                           })
            }
        };
    }
    media_sections.push(sdp_media);
    Ok(media_sections)
}
// TODO add unit tests for parse_media_vector
<|endoftext|>


<commit_before>#![allow(dead_code)]
use tag::TagType;

#[repr(C)]
pub struct MemoryMapTag {
	tag_type: u32,
	size: u32,
	entry_size: u32,
	/// This is currently set to `0`.
	entry_version: u32,
	first_entry: MemoryMapEntry
}

impl MemoryMapTag {
	pub fn memory_regions(&self) -> MemoryMapIter {
		let ptr = self as *const MemoryMapTag;
		let first_entry = (&self.first_entry) as *const MemoryMapEntry;
		let final_entry = ((ptr as u64) + (self.size as u64)) as *const MemoryMapEntry;

		MemoryMapIter::new(first_entry, final_entry, self.entry_size)
	}

	fn is_valid(&self) -> bool {
		self.tag_type == TagType::MemoryMap as u32
	}
}

#[derive(Debug)]
#[repr(C, packed)]
pub struct MemoryMapEntry {
	/// The starting physical address
	base_addr: u64,
	/// The size of the memory region, in bytes.
	length: u64,
	/// The type of memory region contained.
	entry_type: u32,
	/// This should be set to `0` and ignored by the bootloader.
	reserved: u32
}

#[derive(Debug, PartialEq, Eq)]
pub enum MemoryType {
	Usable         = 1,
	UsableWithACPI = 3,
	Unusable       = 4,
}

impl MemoryMapEntry {
	pub fn base_address(&self) -> usize {
		self.base_addr as usize
	}

	pub fn length(&self) -> usize {
		self.length as usize
	}

	fn memory_type(&self) -> MemoryType {
		match self.entry_type {
			1 => MemoryType::Usable,
			3 => MemoryType::UsableWithACPI,
			_ => MemoryType::Unusable
		}
	}

	fn is_usable_region(&self) -> bool {
		self.memory_type() == MemoryType::Usable
	}
}

pub struct MemoryMapIter {
	current_entry: *const MemoryMapEntry,
	final_entry: *const MemoryMapEntry,
	// We need to know the entry size so we can calculate the
	// address of the next memory map entry.
	entry_size: u32,
}

impl MemoryMapIter {
	fn new(current_entry: *const MemoryMapEntry,
		   final_entry: *const MemoryMapEntry,
		   entry_size: u32) -> MemoryMapIter
	{
		MemoryMapIter {
			current_entry: current_entry,
			final_entry: final_entry,
			entry_size: entry_size,
		}
	}
}

impl Iterator for MemoryMapIter {
	type Item = &'static MemoryMapEntry;

	fn next(&mut self) -> Option<Self::Item> {
		// Loop until the next usable memory region. We ignore the unusable regions
		// per the Multiboot2 standard requirements.
		loop {
			if self.current_entry <= self.final_entry {
				let current_entry = unsafe { &*self.current_entry };
				let next_entry = (self.current_entry as u64) + (self.entry_size as u64);

				self.current_entry = next_entry as *const MemoryMapEntry;

				if current_entry.is_usable_region() {
					return Some(current_entry);
				}

			} else {
				// We have fallen off the end of the memory map.
				return None;
			}
		}
	}
}
<commit_msg>Write verification code for memory map.<commit_after>#![allow(dead_code)]
use tag::{TagType, VerifyTag};

#[repr(C)]
pub struct MemoryMapTag {
    tag_type: u32,
    size: u32,
    entry_size: u32,
    /// This is currently set to `0`.
    entry_version: u32,
    first_entry: MemoryMapEntry
}

impl MemoryMapTag {
    pub fn memory_regions(&self) -> MemoryMapIter {
        let ptr = self as *const MemoryMapTag;
        let first_entry = (&self.first_entry) as *const MemoryMapEntry;
        let final_entry = ((ptr as u64) + (self.size as u64)) as *const MemoryMapEntry;

        MemoryMapIter::new(first_entry, final_entry, self.entry_size)
    }

    fn all_memory_regions(&self) -> VerifyMemoryMapIter {
        let ptr = self as *const MemoryMapTag;
        let first_entry = (&self.first_entry) as *const MemoryMapEntry;
        let final_entry = ((ptr as u64) + (self.size as u64)) as *const MemoryMapEntry;

        VerifyMemoryMapIter::new(first_entry, final_entry, self.entry_size)
    }
}

impl VerifyTag for MemoryMapTag {
    fn is_valid(&self) -> bool {
        let mut entries = self.all_memory_regions();

        (self.tag_type == TagType::MemoryMap as u32) &&
        (self.entry_size % 8 == 0) &&
        (self.entry_version == 0) &&
        entries.all(|entry| entry.is_valid())
    }
}

#[derive(Debug)]
#[repr(C, packed)]
pub struct MemoryMapEntry {
    /// The starting physical address
    base_addr: u64,
    /// The size of the memory region, in bytes.
    length: u64,
    /// The type of memory region contained.
    entry_type: u32,
    /// This should be set to `0` and ignored by the bootloader.
    reserved: u32
}

#[derive(Debug, PartialEq, Eq)]
pub enum MemoryType {
    Usable         = 1,
    UsableWithACPI = 3,
    Unusable       = 4,
}

impl MemoryMapEntry {
    pub fn base_address(&self) -> usize {
        self.base_addr as usize
    }

    pub fn length(&self) -> usize {
        self.length as usize
    }

    fn memory_type(&self) -> MemoryType {
        match self.entry_type {
            1 => MemoryType::Usable,
            3 => MemoryType::UsableWithACPI,
            _ => MemoryType::Unusable
        }
    }

    fn is_usable_region(&self) -> bool {
        self.memory_type() == MemoryType::Usable
    }

    fn is_valid(&self) -> bool {
        self.reserved == 0
    }
}

pub struct MemoryMapIter {
    current_entry: *const MemoryMapEntry,
    final_entry: *const MemoryMapEntry,
    // We need to know the entry size so we can calculate the
    // address of the next memory map entry.
    entry_size: u32,
}

impl MemoryMapIter {
    fn new(current_entry: *const MemoryMapEntry,
           final_entry: *const MemoryMapEntry,
           entry_size: u32) -> MemoryMapIter
    {
        MemoryMapIter {
            current_entry: current_entry,
            final_entry: final_entry,
            entry_size: entry_size,
        }
    }
}

impl Iterator for MemoryMapIter {
    type Item = &'static MemoryMapEntry;

    fn next(&mut self) -> Option<Self::Item> {
        // Loop until the next usable memory region. We ignore the unusable regions
        // per the Multiboot2 standard requirements.
        loop {
            if self.current_entry <= self.final_entry {
                let current_entry = unsafe { &*self.current_entry };
                let next_entry = (self.current_entry as u64) + (self.entry_size as u64);

                self.current_entry = next_entry as *const MemoryMapEntry;

                if current_entry.is_usable_region() {
                    return Some(current_entry);
                }

            } else {
                // We have fallen off the end of the memory map.
                return None;
            }
        }
    }
}

// This iterator is for supporting verification of the memory map. This iterator
// also iterates over the unusable memory regions.
struct VerifyMemoryMapIter {
    current_entry: *const MemoryMapEntry,
    final_entry: *const MemoryMapEntry,
    // We need to know the entry size so we can calculate the
    // address of the next memory map entry.
    entry_size: u32,
}

impl VerifyMemoryMapIter {
    fn new(current_entry: *const MemoryMapEntry,
           final_entry: *const MemoryMapEntry,
           entry_size: u32) -> VerifyMemoryMapIter
    {
        VerifyMemoryMapIter {
            current_entry: current_entry,
            final_entry: final_entry,
            entry_size: entry_size,
        }
    }
}

impl Iterator for VerifyMemoryMapIter {
    type Item = &'static MemoryMapEntry;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_entry <= self.final_entry {
            let current_entry = unsafe { &*self.current_entry };
            let next_entry = (self.current_entry as u64) + (self.entry_size as u64);

            self.current_entry = next_entry as *const MemoryMapEntry;

            return Some(current_entry);

        } else {
            // We have fallen off the end of the memory map.
            return None;
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Update stop-instance.rs<commit_after><|endoftext|>


<commit_before>//! Ratio (dimensionless quantity).

#[cfg(feature = "std")]
use super::angle::{Angle, radian};

quantity! {
    /// Ratio (dimensionless quantity).
    quantity: Ratio; "ratio";
    /// Dimension of ratio, 1 (dimensionless).
    dimension: ISQ<
        Z0,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @ratio: 1.0; "", "", "";
        @part_per_hundred: 1.0_E-2; "parts per hundred", "part per hundred", "parts per hundred";
        @percent: 1.0_E-2; "%", "percent", "percent";
        @part_per_thousand: 1.0_E-3; "parts per thousand", "part per thousand",
            "parts per thousand";
        @per_mille: 1.0_E-3; "‰", "per mille", "per mille";
        @part_per_ten_thousand: 1.0_E-4; "parts per ten thousand", "part per then thousand",
            "parts per ten thousand"; // ‱, doesn't display properly.
        @basis_point: 1.0_E-4; "bp", "basis point", "basis points";
        @part_per_million: 1.0_E-6; "ppm", "part per million", "parts per million";
        @part_per_billion: 1.0_E-9; "ppb", "part per billion", "parts per billion";
        @part_per_trillion: 1.0_E-12; "ppt", "part per trillion", "parts per trillion";
        @part_per_quadrillion: 1.0_E-15; "ppq", "part per quadrillion", "parts per quadrillion";
    }
}

/// Implementation of various stdlib functions.
#[cfg(feature = "std")]
impl<U, V> Ratio<U, V>
where
    U: crate::si::Units<V> + ?Sized,
    V: crate::num::Float + crate::Conversion<V>,
    radian: crate::Conversion<V, T = V::T>,
    ratio: crate::Conversion<V, T = V::T>,
{
    /// Computes the value of the inverse cosine of the ratio.
    #[inline(always)]
    pub fn acos(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.acos())
    }

    /// Computes the value of the inverse hyperbolic cosine of the ratio.
    #[inline(always)]
    pub fn acosh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.acosh())
    }

    /// Computes the value of the inverse sine of the ratio.
    #[inline(always)]
    pub fn asin(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.asin())
    }

    /// Computes the value of the inverse hyperbolic sine of the ratio.
    #[inline(always)]
    pub fn asinh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.asinh())
    }

    /// Computes the value of the inverse tangent of the ratio.
    #[inline(always)]
    pub fn atan(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atan())
    }

    /// Computes the value of the inverse hyperbolic tangent of the ratio.
    #[inline(always)]
    pub fn atanh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atanh())
    }

    /// Returns `e^(self)`, (the exponential function).
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp())
    }

    /// Returns 2^(self).
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp2(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp2())
    }

    /// Returns the natural logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn ln(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.ln())
    }

    /// Returns the logarithm of the number with respect to an arbitrary base.
    ///
    /// The result might not be correctly rounded owing to implementation
    /// details; self.log2() can produce more accurate results for base 2, and
    /// self.log10() can produce more accurate results for base 10.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log(self, base: V) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log(base))
    }

    /// Returns the base 2 logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log2(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log2())
    }

    /// Returns the base 10 logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log10(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log10())
    }

    /// Returns e^(self) - 1 in a way that is accurate even if the number is close to zero.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp_m1(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp_m1())
    }

    /// Returns ln(1+n) (natural logarithm) more accurately than if the
    /// operations were performed separately.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn ln_1p(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.ln_1p())
    }
}

mod convert {
    use super::*;

    impl<U, V> From<V> for Ratio<U, V>
    where
        U: crate::si::Units<V> + ?Sized,
        V: crate::num::Num + crate::Conversion<V>,
    {
        fn from(t: V) -> Self {
            Ratio {
                dimension: crate::lib::marker::PhantomData,
                units: crate::lib::marker::PhantomData,
                value: t,
            }
        }
    }

    storage_types! {
        use super::*;

        impl<U> From<Ratio<U, V>> for V
        where
            U: crate::si::Units<V> + ?Sized,
            V: crate::num::Num + crate::Conversion<V>,
        {
            fn from(t: Ratio<U, V>) -> Self {
                t.value
            }
        }
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use crate::num::{FromPrimitive, One};
        use crate::si::quantities::*;
        use crate::si::ratio as r;
        use crate::tests::Test;

        #[test]
        fn from() {
            let r1: Ratio<V> = Ratio::<V>::from(V::one());
            let r2: Ratio<V> = V::one().into();
            let _: V = V::from(r1);
            let _: V = r2.into();
        }

        #[test]
        fn check_units() {
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E2).unwrap()),
                &Ratio::new::<r::part_per_hundred>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E2).unwrap()),
                &Ratio::new::<r::percent>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E3).unwrap()),
                &Ratio::new::<r::part_per_thousand>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E3).unwrap()),
                &Ratio::new::<r::per_mille>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E4).unwrap()),
                &Ratio::new::<r::part_per_ten_thousand>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E4).unwrap()),
                &Ratio::new::<r::basis_point>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E6).unwrap()),
                &Ratio::new::<r::part_per_million>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E9).unwrap()),
                &Ratio::new::<r::part_per_billion>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one()
                    / V::from_f64(1.0_E12).unwrap()),
                &Ratio::new::<r::part_per_trillion>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one()
                    / V::from_f64(1.0_E15).unwrap()),
                &Ratio::new::<r::part_per_quadrillion>(V::one()));
        }
    }

    #[cfg(feature = "std")]
    mod float {
        storage_types! {
            types: Float;

            use crate::si::angle as a;
            use crate::si::ratio as r;
            use crate::si::quantities::*;
            use crate::tests::Test;

            quickcheck! {
                fn acos(x: V) -> bool {
                    Test::eq(&x.acos(), &Ratio::from(x).acos().get::<a::radian>())
                }

                fn acosh(x: V) -> bool {
                    Test::eq(&x.acosh(), &Ratio::from(x).acosh().get::<a::radian>())
                }

                fn asin(x: V) -> bool {
                    Test::eq(&x.asin(), &Ratio::from(x).asin().get::<a::radian>())
                }

                fn asinh(x: V) -> bool {
                    Test::eq(&x.asinh(), &Ratio::from(x).asinh().get::<a::radian>())
                }

                fn atan(x: V) -> bool {
                    Test::eq(&x.atan(), &Ratio::from(x).atan().get::<a::radian>())
                }

                fn atanh(x: V) -> bool {
                    Test::eq(&x.atanh(), &Ratio::from(x).atanh().get::<a::radian>())
                }

                fn exp(x: V) -> bool {
                    Test::eq(&x.exp(), &Ratio::from(x).exp().get::<r::ratio>())
                }

                fn exp2(x: V) -> bool {
                    Test::eq(&x.exp2(), &Ratio::from(x).exp2().get::<r::ratio>())
                }

                fn ln(x: V) -> bool {
                    Test::eq(&x.ln(), &Ratio::from(x).ln().get::<r::ratio>())
                }

                fn log(x: V, y: V) -> bool {
                    Test::eq(&x.log(y), &Ratio::from(x).log(y).get::<r::ratio>())
                }

                fn log2(x: V) -> bool {
                    Test::eq(&x.log2(), &Ratio::from(x).log2().get::<r::ratio>())
                }

                fn log10(x: V) -> bool {
                    Test::eq(&x.log10(), &Ratio::from(x).log10().get::<r::ratio>())
                }

                fn exp_m1(x: V) -> bool {
                    Test::eq(&x.exp_m1(), &Ratio::from(x).exp_m1().get::<r::ratio>())
                }

                fn ln_1p(x: V) -> bool {
                    Test::eq(&x.ln_1p(), &Ratio::from(x).ln_1p().get::<r::ratio>())
                }
            }
        }
    }
}
<commit_msg>Add must_use attribute to existing inverse-trig fns<commit_after>//! Ratio (dimensionless quantity).

#[cfg(feature = "std")]
use super::angle::{Angle, radian};

quantity! {
    /// Ratio (dimensionless quantity).
    quantity: Ratio; "ratio";
    /// Dimension of ratio, 1 (dimensionless).
    dimension: ISQ<
        Z0,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @ratio: 1.0; "", "", "";
        @part_per_hundred: 1.0_E-2; "parts per hundred", "part per hundred", "parts per hundred";
        @percent: 1.0_E-2; "%", "percent", "percent";
        @part_per_thousand: 1.0_E-3; "parts per thousand", "part per thousand",
            "parts per thousand";
        @per_mille: 1.0_E-3; "‰", "per mille", "per mille";
        @part_per_ten_thousand: 1.0_E-4; "parts per ten thousand", "part per then thousand",
            "parts per ten thousand"; // ‱, doesn't display properly.
        @basis_point: 1.0_E-4; "bp", "basis point", "basis points";
        @part_per_million: 1.0_E-6; "ppm", "part per million", "parts per million";
        @part_per_billion: 1.0_E-9; "ppb", "part per billion", "parts per billion";
        @part_per_trillion: 1.0_E-12; "ppt", "part per trillion", "parts per trillion";
        @part_per_quadrillion: 1.0_E-15; "ppq", "part per quadrillion", "parts per quadrillion";
    }
}

/// Implementation of various stdlib functions.
#[cfg(feature = "std")]
impl<U, V> Ratio<U, V>
where
    U: crate::si::Units<V> + ?Sized,
    V: crate::num::Float + crate::Conversion<V>,
    radian: crate::Conversion<V, T = V::T>,
    ratio: crate::Conversion<V, T = V::T>,
{
    /// Computes the value of the inverse cosine of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn acos(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.acos())
    }

    /// Computes the value of the inverse hyperbolic cosine of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn acosh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.acosh())
    }

    /// Computes the value of the inverse sine of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn asin(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.asin())
    }

    /// Computes the value of the inverse hyperbolic sine of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn asinh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.asinh())
    }

    /// Computes the value of the inverse tangent of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn atan(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atan())
    }

    /// Computes the value of the inverse hyperbolic tangent of the ratio.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn atanh(self) -> Angle<U, V> {
        Angle::new::<radian>(self.value.atanh())
    }

    /// Returns `e^(self)`, (the exponential function).
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp())
    }

    /// Returns 2^(self).
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp2(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp2())
    }

    /// Returns the natural logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn ln(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.ln())
    }

    /// Returns the logarithm of the number with respect to an arbitrary base.
    ///
    /// The result might not be correctly rounded owing to implementation
    /// details; self.log2() can produce more accurate results for base 2, and
    /// self.log10() can produce more accurate results for base 10.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log(self, base: V) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log(base))
    }

    /// Returns the base 2 logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log2(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log2())
    }

    /// Returns the base 10 logarithm of the number.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn log10(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.log10())
    }

    /// Returns e^(self) - 1 in a way that is accurate even if the number is close to zero.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn exp_m1(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.exp_m1())
    }

    /// Returns ln(1+n) (natural logarithm) more accurately than if the
    /// operations were performed separately.
    #[must_use = "method returns a new number and does not mutate the original value"]
    #[inline(always)]
    pub fn ln_1p(self) -> Ratio<U, V> {
        Ratio::new::<ratio>(self.value.ln_1p())
    }
}

mod convert {
    use super::*;

    impl<U, V> From<V> for Ratio<U, V>
    where
        U: crate::si::Units<V> + ?Sized,
        V: crate::num::Num + crate::Conversion<V>,
    {
        fn from(t: V) -> Self {
            Ratio {
                dimension: crate::lib::marker::PhantomData,
                units: crate::lib::marker::PhantomData,
                value: t,
            }
        }
    }

    storage_types! {
        use super::*;

        impl<U> From<Ratio<U, V>> for V
        where
            U: crate::si::Units<V> + ?Sized,
            V: crate::num::Num + crate::Conversion<V>,
        {
            fn from(t: Ratio<U, V>) -> Self {
                t.value
            }
        }
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use crate::num::{FromPrimitive, One};
        use crate::si::quantities::*;
        use crate::si::ratio as r;
        use crate::tests::Test;

        #[test]
        fn from() {
            let r1: Ratio<V> = Ratio::<V>::from(V::one());
            let r2: Ratio<V> = V::one().into();
            let _: V = V::from(r1);
            let _: V = r2.into();
        }

        #[test]
        fn check_units() {
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E2).unwrap()),
                &Ratio::new::<r::part_per_hundred>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E2).unwrap()),
                &Ratio::new::<r::percent>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E3).unwrap()),
                &Ratio::new::<r::part_per_thousand>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E3).unwrap()),
                &Ratio::new::<r::per_mille>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E4).unwrap()),
                &Ratio::new::<r::part_per_ten_thousand>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E4).unwrap()),
                &Ratio::new::<r::basis_point>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E6).unwrap()),
                &Ratio::new::<r::part_per_million>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one() / V::from_f64(1.0_E9).unwrap()),
                &Ratio::new::<r::part_per_billion>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one()
                    / V::from_f64(1.0_E12).unwrap()),
                &Ratio::new::<r::part_per_trillion>(V::one()));
            Test::assert_eq(&Ratio::new::<r::ratio>(V::one()
                    / V::from_f64(1.0_E15).unwrap()),
                &Ratio::new::<r::part_per_quadrillion>(V::one()));
        }
    }

    #[cfg(feature = "std")]
    mod float {
        storage_types! {
            types: Float;

            use crate::si::angle as a;
            use crate::si::ratio as r;
            use crate::si::quantities::*;
            use crate::tests::Test;

            quickcheck! {
                fn acos(x: V) -> bool {
                    Test::eq(&x.acos(), &Ratio::from(x).acos().get::<a::radian>())
                }

                fn acosh(x: V) -> bool {
                    Test::eq(&x.acosh(), &Ratio::from(x).acosh().get::<a::radian>())
                }

                fn asin(x: V) -> bool {
                    Test::eq(&x.asin(), &Ratio::from(x).asin().get::<a::radian>())
                }

                fn asinh(x: V) -> bool {
                    Test::eq(&x.asinh(), &Ratio::from(x).asinh().get::<a::radian>())
                }

                fn atan(x: V) -> bool {
                    Test::eq(&x.atan(), &Ratio::from(x).atan().get::<a::radian>())
                }

                fn atanh(x: V) -> bool {
                    Test::eq(&x.atanh(), &Ratio::from(x).atanh().get::<a::radian>())
                }

                fn exp(x: V) -> bool {
                    Test::eq(&x.exp(), &Ratio::from(x).exp().get::<r::ratio>())
                }

                fn exp2(x: V) -> bool {
                    Test::eq(&x.exp2(), &Ratio::from(x).exp2().get::<r::ratio>())
                }

                fn ln(x: V) -> bool {
                    Test::eq(&x.ln(), &Ratio::from(x).ln().get::<r::ratio>())
                }

                fn log(x: V, y: V) -> bool {
                    Test::eq(&x.log(y), &Ratio::from(x).log(y).get::<r::ratio>())
                }

                fn log2(x: V) -> bool {
                    Test::eq(&x.log2(), &Ratio::from(x).log2().get::<r::ratio>())
                }

                fn log10(x: V) -> bool {
                    Test::eq(&x.log10(), &Ratio::from(x).log10().get::<r::ratio>())
                }

                fn exp_m1(x: V) -> bool {
                    Test::eq(&x.exp_m1(), &Ratio::from(x).exp_m1().get::<r::ratio>())
                }

                fn ln_1p(x: V) -> bool {
                    Test::eq(&x.ln_1p(), &Ratio::from(x).ln_1p().get::<r::ratio>())
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Asynchronous sinks
//!
//! This module contains the `Sink` trait, along with a number of adapter types
//! for it. An overview is available in the documentaiton for the trait itself.
//!
//! You can find more information/tutorials about streams [online at
//! https://tokio.rs][online]
//!
//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

use {IntoFuture, Poll, StartSend};
use stream::Stream;

mod with;
// mod with_map;
// mod with_filter;
// mod with_filter_map;
mod flush;
mod send;
mod send_all;
mod map_err;

if_std! {
    mod buffer;

    pub use self::buffer::Buffer;

    // TODO: consider expanding this via e.g. FromIterator
    impl<T> Sink for ::std::vec::Vec<T> {
        type SinkItem = T;
        type SinkError = (); // Change this to ! once it stabilizes

        fn start_send(&mut self, item: Self::SinkItem)
                      -> StartSend<Self::SinkItem, Self::SinkError>
        {
            self.push(item);
            Ok(::AsyncSink::Ready)
        }

        fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
            Ok(::Async::Ready(()))
        }
    }

    /// A type alias for `Box<Stream + Send>`
    pub type BoxSink<T, E> = ::std::boxed::Box<Sink<SinkItem = T, SinkError = E> +
                                               ::core::marker::Send>;

    impl<S: ?Sized + Sink> Sink for ::std::boxed::Box<S> {
        type SinkItem = S::SinkItem;
        type SinkError = S::SinkError;

        fn start_send(&mut self, item: Self::SinkItem)
                      -> StartSend<Self::SinkItem, Self::SinkError> {
            (**self).start_send(item)
        }

        fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
            (**self).poll_complete()
        }
    }
}

pub use self::with::With;
pub use self::flush::Flush;
pub use self::send::Send;
pub use self::send_all::SendAll;
pub use self::map_err::SinkMapErr;

/// A `Sink` is a value into which other values can be sent, asynchronously.
///
/// Basic examples of sinks include the sending side of:
///
/// - Channels
/// - Sockets
/// - Pipes
///
/// In addition to such "primitive" sinks, it's typical to layer additional
/// functionality, such as buffering, on top of an existing sink.
///
/// Sending to a sink is "asynchronous" in the sense that the value may not be
/// sent in its entirety immediately. Instead, values are sent in a two-phase
/// way: first by initiating a send, and then by polling for completion. This
/// two-phase setup is analogous to buffered writing in synchronous code, where
/// writes often succeed immediately, but internally are buffered and are
/// *actually* written only upon flushing.
///
/// In addition, the `Sink` may be *full*, in which case it is not even possible
/// to start the sending process.
///
/// As with `Future` and `Stream`, the `Sink` trait is built from a few core
/// required methods, and a host of default methods for working in a
/// higher-level way. The `Sink::send_all` combinator is of particular
/// importance: you can use it to send an entire stream to a sink, which is
/// the simplest way to ultimately consume a sink.
///
/// You can find more information/tutorials about streams [online at
/// https://tokio.rs][online]
///
/// [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/
pub trait Sink {
    /// The type of value that the sink accepts.
    type SinkItem;

    /// The type of value produced by the sink when an error occurs.
    type SinkError;

    /// Begin the process of sending a value to the sink.
    ///
    /// As the name suggests, this method only *begins* the process of sending
    /// the item. If the sink employs buffering, the item isn't fully processed
    /// until the buffer is fully flushed. Since sinks are designed to work with
    /// asynchronous I/O, the process of actually writing out the data to an
    /// underlying object takes place asynchronously. **You *must* use
    /// `poll_complete` in order to drive completion of a send**. In particular,
    /// `start_send` does not begin the flushing process
    ///
    /// # Return value
    ///
    /// This method returns `AsyncSink::Ready` if the sink was able to start
    /// sending `item`. In that case, you *must* ensure that you call
    /// `poll_complete` to process the sent item to completion. Note, however,
    /// that several calls to `start_send` can be made prior to calling
    /// `poll_complete`, which will work on completing all pending items.
    ///
    /// The method returns `AsyncSink::NotReady` if the sink was unable to begin
    /// sending, usually due to being full. The sink must have attempted to
    /// complete processing any outstanding requests (equivalent to
    /// `poll_complete`) before yielding this result. The current task will be
    /// automatically scheduled for notification when the sink may be ready to
    /// receive new values.
    ///
    /// # Errors
    ///
    /// If the sink encounters an error other than being temporarily full, it
    /// uses the `Err` variant to signal that error. In most cases, such errors
    /// mean that the sink will permanently be unable to receive items.
    ///
    /// # Panics
    ///
    /// This method may panic in a few situations, depending on the specific
    /// sink:
    ///
    /// - It is called outside of the context of a task.
    /// - A previous call to `start_send` or `poll_complete` yielded an error.
    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, Self::SinkError>;

    /// Make progress on all pending requests, and determine whether they have
    /// completed.
    ///
    /// Since sinks are asynchronous, no single method completes all of their
    /// work in one shot. Instead, you use `poll_complete` to repeatedly drive
    /// the sink to make progress on requests (such as `start_send`). As with
    /// `Future::poll`, if the pending requests are not able to complete during
    /// this call, the current task is automatically scheduled to be woken up
    /// again once more progress is possible.
    ///
    /// # Return value
    ///
    /// Returns `Ok(Async::Ready(()))` when no unprocessed requests remain.
    ///
    /// Returns `Ok(Async::NotReady)` if there is more work left to do, in which
    /// case the current task is scheduled to wake up when more progress may be
    /// possible.
    ///
    /// # Errors
    ///
    /// Returns `Err` if the sink encounters an error while processing one of
    /// its pending requests. Due to the buffered nature of requests, it is not
    /// generally possible to correlate the error with a particular request. As
    /// with `start_send`, these errors are generally "fatal" for continued use
    /// of the sink.
    ///
    /// # Panics
    ///
    /// This method may panic in a few situations, depending on the specific sink:
    ///
    /// - It is called outside of the context of a task.
    /// - A previous call to `start_send` or `poll_complete` yielded an error.
    fn poll_complete(&mut self) -> Poll<(), Self::SinkError>;

    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *future*, which is then polled to
    /// completion before passing its result down to the underlying sink. If the
    /// future produces an error, that error is returned by the new sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    fn with<U, F, Fut>(self, f: F) -> With<Self, U, F, Fut>
        where F: FnMut(U) -> Fut,
              Fut: IntoFuture<Item = Self::SinkItem>,
              Fut::Error: From<Self::SinkError>,
              Self: Sized
    {
        with::new(self, f)
    }

    /*
    fn with_map<U, F>(self, f: F) -> WithMap<Self, U, F>
        where F: FnMut(U) -> Self::SinkItem,
              Self: Sized;

    fn with_filter<F>(self, f: F) -> WithFilter<Self, F>
        where F: FnMut(Self::SinkItem) -> bool,
              Self: Sized;

    fn with_filter_map<U, F>(self, f: F) -> WithFilterMap<Self, U, F>
        where F: FnMut(U) -> Option<Self::SinkItem>,
              Self: Sized;
     */

    /// Transforms the error returned by the sink.
    fn sink_map_err<F, E>(self, f: F) -> SinkMapErr<Self, F>
        where F: FnOnce(Self::SinkError) -> E,
              Self: Sized,
    {
        map_err::new(self, f)
    }

    /// Adds a fixed-size buffer to the current sink.
    ///
    /// The resulting sink will buffer up to `amt` items when the underlying
    /// sink is unwilling to accept additional items. Calling `poll_complete` on
    /// the buffered sink will attempt to both empty the buffer and complete
    /// processing on the underlying sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    ///
    /// This method is only available when the `use_std` feature of this
    /// library is activated, and it is activated by default.
    #[cfg(feature = "use_std")]
    fn buffer(self, amt: usize) -> Buffer<Self>
        where Self: Sized
    {
        buffer::new(self, amt)
    }

    /// A future that completes when the sink has finished processing all
    /// pending requests.
    ///
    /// The sink itself is returned after flushing is complete; this adapter is
    /// intended to be used when you want to stop sending to the sink until
    /// all current requests are processed.
    fn flush(self) -> Flush<Self>
        where Self: Sized
    {
        flush::new(self)
    }

    /// A future that completes after the given item has been fully processed
    /// into the sink, including flushing.
    ///
    /// Note that, **because of the flushing requirement, it is usually better
    /// to batch together items to send via `send_all`, rather than flushing
    /// between each item.**
    ///
    /// On completion, the sink is returned.
    fn send(self, item: Self::SinkItem) -> Send<Self>
        where Self: Sized
    {
        send::new(self, item)
    }

    /// A future that completes after the given stream has been fully processed
    /// into the sink, including flushing.
    ///
    /// This future will drive the stream to keep producing items until it is
    /// exhausted, sending each item to the sink. It will complete once both the
    /// stream is exhausted, and the sink has fully processed and flushed all of
    /// the items sent to it.
    ///
    /// Doing `sink.send_all(stream)` is roughly equivalent to
    /// `stream.forward(sink)`.
    ///
    /// On completion, the pair `(sink, source)` is returned.
    fn send_all<S>(self, stream: S) -> SendAll<Self, S>
        where S: Stream<Item = Self::SinkItem>,
              Self::SinkError: From<S::Error>,
              Self: Sized
    {
        send_all::new(self, stream)
    }
}

impl<'a, S: ?Sized + Sink> Sink for &'a mut S {
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, Self::SinkError> {
        (**self).start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        (**self).poll_complete()
    }
}
<commit_msg>Update Sink::poll_complete docs<commit_after>//! Asynchronous sinks
//!
//! This module contains the `Sink` trait, along with a number of adapter types
//! for it. An overview is available in the documentaiton for the trait itself.
//!
//! You can find more information/tutorials about streams [online at
//! https://tokio.rs][online]
//!
//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

use {IntoFuture, Poll, StartSend};
use stream::Stream;

mod with;
// mod with_map;
// mod with_filter;
// mod with_filter_map;
mod flush;
mod send;
mod send_all;
mod map_err;

if_std! {
    mod buffer;

    pub use self::buffer::Buffer;

    // TODO: consider expanding this via e.g. FromIterator
    impl<T> Sink for ::std::vec::Vec<T> {
        type SinkItem = T;
        type SinkError = (); // Change this to ! once it stabilizes

        fn start_send(&mut self, item: Self::SinkItem)
                      -> StartSend<Self::SinkItem, Self::SinkError>
        {
            self.push(item);
            Ok(::AsyncSink::Ready)
        }

        fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
            Ok(::Async::Ready(()))
        }
    }

    /// A type alias for `Box<Stream + Send>`
    pub type BoxSink<T, E> = ::std::boxed::Box<Sink<SinkItem = T, SinkError = E> +
                                               ::core::marker::Send>;

    impl<S: ?Sized + Sink> Sink for ::std::boxed::Box<S> {
        type SinkItem = S::SinkItem;
        type SinkError = S::SinkError;

        fn start_send(&mut self, item: Self::SinkItem)
                      -> StartSend<Self::SinkItem, Self::SinkError> {
            (**self).start_send(item)
        }

        fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
            (**self).poll_complete()
        }
    }
}

pub use self::with::With;
pub use self::flush::Flush;
pub use self::send::Send;
pub use self::send_all::SendAll;
pub use self::map_err::SinkMapErr;

/// A `Sink` is a value into which other values can be sent, asynchronously.
///
/// Basic examples of sinks include the sending side of:
///
/// - Channels
/// - Sockets
/// - Pipes
///
/// In addition to such "primitive" sinks, it's typical to layer additional
/// functionality, such as buffering, on top of an existing sink.
///
/// Sending to a sink is "asynchronous" in the sense that the value may not be
/// sent in its entirety immediately. Instead, values are sent in a two-phase
/// way: first by initiating a send, and then by polling for completion. This
/// two-phase setup is analogous to buffered writing in synchronous code, where
/// writes often succeed immediately, but internally are buffered and are
/// *actually* written only upon flushing.
///
/// In addition, the `Sink` may be *full*, in which case it is not even possible
/// to start the sending process.
///
/// As with `Future` and `Stream`, the `Sink` trait is built from a few core
/// required methods, and a host of default methods for working in a
/// higher-level way. The `Sink::send_all` combinator is of particular
/// importance: you can use it to send an entire stream to a sink, which is
/// the simplest way to ultimately consume a sink.
///
/// You can find more information/tutorials about streams [online at
/// https://tokio.rs][online]
///
/// [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/
pub trait Sink {
    /// The type of value that the sink accepts.
    type SinkItem;

    /// The type of value produced by the sink when an error occurs.
    type SinkError;

    /// Begin the process of sending a value to the sink.
    ///
    /// As the name suggests, this method only *begins* the process of sending
    /// the item. If the sink employs buffering, the item isn't fully processed
    /// until the buffer is fully flushed. Since sinks are designed to work with
    /// asynchronous I/O, the process of actually writing out the data to an
    /// underlying object takes place asynchronously. **You *must* use
    /// `poll_complete` in order to drive completion of a send**. In particular,
    /// `start_send` does not begin the flushing process
    ///
    /// # Return value
    ///
    /// This method returns `AsyncSink::Ready` if the sink was able to start
    /// sending `item`. In that case, you *must* ensure that you call
    /// `poll_complete` to process the sent item to completion. Note, however,
    /// that several calls to `start_send` can be made prior to calling
    /// `poll_complete`, which will work on completing all pending items.
    ///
    /// The method returns `AsyncSink::NotReady` if the sink was unable to begin
    /// sending, usually due to being full. The sink must have attempted to
    /// complete processing any outstanding requests (equivalent to
    /// `poll_complete`) before yielding this result. The current task will be
    /// automatically scheduled for notification when the sink may be ready to
    /// receive new values.
    ///
    /// # Errors
    ///
    /// If the sink encounters an error other than being temporarily full, it
    /// uses the `Err` variant to signal that error. In most cases, such errors
    /// mean that the sink will permanently be unable to receive items.
    ///
    /// # Panics
    ///
    /// This method may panic in a few situations, depending on the specific
    /// sink:
    ///
    /// - It is called outside of the context of a task.
    /// - A previous call to `start_send` or `poll_complete` yielded an error.
    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, Self::SinkError>;

    /// Flush all output from this sink, if necessary.
    ///
    /// Some sinks may buffer intermediate data as an optimization to improve
    /// throughput. In other words, if a sink has a corresponding receiver then
    /// a successful `start_send` above may not guarantee that the value is
    /// actually ready to be received by the receiver. This function is intended
    /// to be used to ensure that values do indeed make their way to the
    /// receiver.
    ///
    /// This function will attempt to process any pending requests on behalf of
    /// the sink and drive it to completion. When `Ready`
    ///
    /// # Return value
    ///
    /// Returns `Ok(Async::Ready(()))` when no buffered items remain. If this
    /// value is returned then it is guaranteed that all previous values sent
    /// via `start_send` will be guaranteed to available to a listening
    /// receiver.
    ///
    /// Returns `Ok(Async::NotReady)` if there is more work left to do, in which
    /// case the current task is scheduled to wake up when more progress may be
    /// possible.
    ///
    /// # Errors
    ///
    /// Returns `Err` if the sink encounters an error while processing one of
    /// its pending requests. Due to the buffered nature of requests, it is not
    /// generally possible to correlate the error with a particular request. As
    /// with `start_send`, these errors are generally "fatal" for continued use
    /// of the sink.
    ///
    /// # Panics
    ///
    /// This method may panic in a few situations, depending on the specific sink:
    ///
    /// - It is called outside of the context of a task.
    /// - A previous call to `start_send` or `poll_complete` yielded an error.
    ///
    /// # Compatibility nodes
    ///
    /// The name of this method may be slightly misleading as the original
    /// intention was to have this method be more general than just flushing
    /// requests. Over time though it was decided to trim back the ambitions of
    /// this method to what it's always done, just flushing.
    ///
    /// In the 0.2 release series of futures this method will be renamed to
    /// `poll_flush`. For 0.1, however, the breaking change is not happening
    /// yet.
    fn poll_complete(&mut self) -> Poll<(), Self::SinkError>;

    /// Composes a function *in front of* the sink.
    ///
    /// This adapter produces a new sink that passes each value through the
    /// given function `f` before sending it to `self`.
    ///
    /// To process each value, `f` produces a *future*, which is then polled to
    /// completion before passing its result down to the underlying sink. If the
    /// future produces an error, that error is returned by the new sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    fn with<U, F, Fut>(self, f: F) -> With<Self, U, F, Fut>
        where F: FnMut(U) -> Fut,
              Fut: IntoFuture<Item = Self::SinkItem>,
              Fut::Error: From<Self::SinkError>,
              Self: Sized
    {
        with::new(self, f)
    }

    /*
    fn with_map<U, F>(self, f: F) -> WithMap<Self, U, F>
        where F: FnMut(U) -> Self::SinkItem,
              Self: Sized;

    fn with_filter<F>(self, f: F) -> WithFilter<Self, F>
        where F: FnMut(Self::SinkItem) -> bool,
              Self: Sized;

    fn with_filter_map<U, F>(self, f: F) -> WithFilterMap<Self, U, F>
        where F: FnMut(U) -> Option<Self::SinkItem>,
              Self: Sized;
     */

    /// Transforms the error returned by the sink.
    fn sink_map_err<F, E>(self, f: F) -> SinkMapErr<Self, F>
        where F: FnOnce(Self::SinkError) -> E,
              Self: Sized,
    {
        map_err::new(self, f)
    }

    /// Adds a fixed-size buffer to the current sink.
    ///
    /// The resulting sink will buffer up to `amt` items when the underlying
    /// sink is unwilling to accept additional items. Calling `poll_complete` on
    /// the buffered sink will attempt to both empty the buffer and complete
    /// processing on the underlying sink.
    ///
    /// Note that this function consumes the given sink, returning a wrapped
    /// version, much like `Iterator::map`.
    ///
    /// This method is only available when the `use_std` feature of this
    /// library is activated, and it is activated by default.
    #[cfg(feature = "use_std")]
    fn buffer(self, amt: usize) -> Buffer<Self>
        where Self: Sized
    {
        buffer::new(self, amt)
    }

    /// A future that completes when the sink has finished processing all
    /// pending requests.
    ///
    /// The sink itself is returned after flushing is complete; this adapter is
    /// intended to be used when you want to stop sending to the sink until
    /// all current requests are processed.
    fn flush(self) -> Flush<Self>
        where Self: Sized
    {
        flush::new(self)
    }

    /// A future that completes after the given item has been fully processed
    /// into the sink, including flushing.
    ///
    /// Note that, **because of the flushing requirement, it is usually better
    /// to batch together items to send via `send_all`, rather than flushing
    /// between each item.**
    ///
    /// On completion, the sink is returned.
    fn send(self, item: Self::SinkItem) -> Send<Self>
        where Self: Sized
    {
        send::new(self, item)
    }

    /// A future that completes after the given stream has been fully processed
    /// into the sink, including flushing.
    ///
    /// This future will drive the stream to keep producing items until it is
    /// exhausted, sending each item to the sink. It will complete once both the
    /// stream is exhausted, and the sink has fully processed and flushed all of
    /// the items sent to it.
    ///
    /// Doing `sink.send_all(stream)` is roughly equivalent to
    /// `stream.forward(sink)`.
    ///
    /// On completion, the pair `(sink, source)` is returned.
    fn send_all<S>(self, stream: S) -> SendAll<Self, S>
        where S: Stream<Item = Self::SinkItem>,
              Self::SinkError: From<S::Error>,
              Self: Sized
    {
        send_all::new(self, stream)
    }
}

impl<'a, S: ?Sized + Sink> Sink for &'a mut S {
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, Self::SinkError> {
        (**self).start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        (**self).poll_complete()
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Sort_an_integer_array

#[cfg(not(test))]
fn main() {
    let mut a = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);

    // Merge sort in place, allocates ~2*n memory
    a.sort();
    println!("{}", a);
}
<commit_msg>add test for sort_int<commit_after>// Implements http://rosettacode.org/wiki/Sort_an_integer_array

#[cfg(not(test))]
fn main() {
    let mut a = vec!(9, 8, 7, 6, 5, 4, 3, 2, 1, 0);

    // Merge sort in place, allocates ~2*n memory
    a.sort();
    println!("{}", a);
}

#[test]
fn test_sort() {
    let mut a = vec![3, 1, 4, 1, 5, 9];
    a.sort();
    assert!(a == vec![1, 1, 3, 4, 5, 9]);
}
<|endoftext|>


<commit_before>extern crate serial;
extern crate json;

use self::json::JsonValue;
use self::serial::prelude::*;
use std::time::Duration;
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::error::Error;
use std::str::from_utf8;

const DEFAULTCONFIG: &str = "\
{
    \"port\": \"\"
}";

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

pub struct Input {
    port: Option<serial::windows::COMPort>,
    buf: Vec<u8>,
    pub output: [f32; 16],
}

impl Input {
    pub fn new() -> Input {
        Input {
            port: create_port(),
            buf: vec![0u8; 32],
            output: [0.; 16],
        }
    }

    // Synchronous Input Update
    pub fn update(&mut self) -> [f32; 16] {

        let mut ftoken: Vec<f32> = Vec::new();

        let mut new_line = String::new();

        let mut buf = vec![0u8; 256];

        {
            match self.port {
                Some(ref mut p) => {
                    loop {
                        match p.read(&mut buf) {
                            Ok(size) => {
                                if size == 0 {
                                    continue;
                                } else {
                                    let str_buf = match from_utf8(&mut buf) {
                                        Ok(v) => v,
                                        Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
                                    };

                                    new_line.push_str(str_buf);
                                }
                            }
                            Err(_) => break,
                    }

                    // Clear buffer
                    buf = vec![0u8; 256];

                    let tokens: Vec<&str> = new_line.split_whitespace().collect();

                    if tokens.len() >= 16 {
                        break;
                    }
            }

            // Traverse new_line till we find a \n, then split it there
            let mut token_index = match new_line.find('\n') {
                Some(nl) => nl,
                None => 0
            };

            let tokens = new_line.split_at(token_index).1.split_whitespace();

            for token in tokens {
                match token {
                    x => {
                        let f = x.parse::<f32>();
                        match f {
                            Ok(num) => ftoken.push(num),
                            Err(e) => ftoken.push(1.),
                        }
                    }
                }
            }

        for (i, t) in ftoken.iter().enumerate() {
            if i < self.output.len() {
                self.output[i] = *t;
            }
        }
        self.buf = vec![0u8; 32];
            },
            None => ()
                }
            }

        self.output

}
}

fn create_port() -> Option<serial::windows::COMPort> {

    use self::SETTINGS;

    let contents = {

        use std::io::Error;

        let open = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open("config.json");

        let mut contents = String::new();

        let mut file = match open {
            Err(why) => panic!("Couldn't open a handle to ./config.json, are you editing it?"),
            Ok(file) => file,
        };

        match file.read_to_string(&mut contents) {
            Err(why) => panic!("Couldn't read ./config.json, are you editing it?"),
            Ok(_) => println!("Opened config.json file."),
        }

        if contents.is_empty() {

            contents.insert_str(0, DEFAULTCONFIG);

            match file.write_all(contents.as_bytes()) {

                Err(why) => panic!("Couldn't write to ./config.json, are you editing it?"),
                Ok(_) => println!("Created default ./config.json file."),
            }
        }

        contents
    };

{
    let json_data = match json::parse(&contents) {
        Err(why) => panic!("JSON data couldn't be parsed, verify your JSON."),
        Ok(data) => data,
    };

    let portstr = json_data["port"].as_str();

    match portstr {

        Some(port_name) => {

            let mut port: Option<serial::windows::COMPort> = match serial::windows::COMPort::open(port_name) {
                Ok(mut p) => {
                         p.configure(&SETTINGS);

            p.set_timeout(Duration::from_millis(16));
                    Some(p)},
                Err(why) => None,
            };

            port
        },
        None => None
    }
}
}<commit_msg>*bangs head*<commit_after>extern crate serial;
extern crate json;

use self::json::JsonValue;
use self::serial::prelude::*;
use std::time::Duration;
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::error::Error;
use std::str::from_utf8;
use std::str::FromStr;

const DEFAULTCONFIG: &str = "\
{
    \"port\": \"\"
}";

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

pub struct Input {
    port: Option<serial::windows::COMPort>,
    buf: Vec<u8>,
    pub output: [f32; 16],
}

impl Input {
    pub fn new() -> Input {
        Input {
            port: create_port(),
            buf: vec![0u8; 32],
            output: [0.; 16],
        }
    }

    // Synchronous Input Update
    pub fn update(&mut self) -> [f32; 16] {

        let mut ftoken: Vec<f32> = Vec::new();

        let mut new_line = String::new();

        let mut buf = vec![0u8; 32];

        {
            match self.port {
                Some(ref mut p) => {
                    loop {
                        match p.read(&mut buf) {
                            Ok(size) => {
                                if size == 0 {
                                    continue;
                                } else {
                                    let str_buf = match from_utf8(&mut buf) {
                                        Ok(v) => v,
                                        Err(e) => continue,
                                    };

                                    new_line.push_str(str_buf);
                                }
                            }
                            Err(_) => break,
                        }

                        // Clear buffer
                        buf = vec![0u8; 32];

                        let mut token_index = match new_line.find('\n') {
                            Some(nl) => {
                                new_line = String::from_str(new_line.split_at(nl).1).unwrap();
                            }
                            None => (),
                        };

                        let tokens: Vec<&str> = new_line.split_whitespace().collect();

                        if tokens.len() >= 16 {
                            break;
                        }
                    }

                    // Traverse new_line till we find a \n, then split it there
                    let mut token_index = match new_line.find('\n') {
                        Some(nl) => nl,
                        None => 0,
                    };

                    let tokens = new_line.split_at(token_index).1.split_whitespace();

                    // Make sure that this is at least 16

                    for token in tokens {
                        match token {
                            x => {
                                let f = x.parse::<f32>();
                                match f {
                                    Ok(num) => ftoken.push(1. - num),
                                    Err(e) => ftoken.push(0.),
                                }
                            }
                        }
                    }

                    for i in 0..self.output.len() {
                        if i < ftoken.len() {
                            self.output[i] = ftoken[i];
                        } else {
                            self.output[i] = 0.;
                        }
                    }
                    self.buf = vec![0u8; 32];
                }
                None => (),
            }
        }

        self.output

    }
}

fn create_port() -> Option<serial::windows::COMPort> {

    use self::SETTINGS;

    let contents = {

        use std::io::Error;

        let open = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open("config.json");

        let mut contents = String::new();

        let mut file = match open {
            Err(why) => panic!("Couldn't open a handle to ./config.json, are you editing it?"),
            Ok(file) => file,
        };

        match file.read_to_string(&mut contents) {
            Err(why) => panic!("Couldn't read ./config.json, are you editing it?"),
            Ok(_) => println!("Opened config.json file."),
        }

        if contents.is_empty() {

            contents.insert_str(0, DEFAULTCONFIG);

            match file.write_all(contents.as_bytes()) {

                Err(why) => panic!("Couldn't write to ./config.json, are you editing it?"),
                Ok(_) => println!("Created default ./config.json file."),
            }
        }

        contents
    };

    {
        let json_data = match json::parse(&contents) {
            Err(why) => panic!("JSON data couldn't be parsed, verify your JSON."),
            Ok(data) => data,
        };

        let portstr = json_data["port"].as_str();

        match portstr {

            Some(port_name) => {

                let mut port: Option<serial::windows::COMPort> =
                    match serial::windows::COMPort::open(port_name) {
                        Ok(mut p) => {

                            p.configure(&SETTINGS);

                            p.set_timeout(Duration::from_millis(16));

                            Some(p)
                        }
                        Err(why) => None,
                    };

                port
            }
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>/*!
factorizes a matrix of times and observed values
into ...

use it by repeatedly calling `update` with data
and inspecting `hidden` and `weights`.
*/

extern crate num;
use self::num::traits::{Zero, One, FromPrimitive, ToPrimitive, Float};

extern crate nalgebra;
use self::nalgebra::{DMat, DVec, Norm, BaseFloat};

pub struct OnlineNMF<FloatT> {
    /// maps hidden variables (= rows) to observed variables (= cols).
    /// changes on every `update`.
    /// stays constant in size.
    pub hidden: DMat<FloatT>,
    /// maps times (= rows) to hidden variables (= cols).
    /// changes on every `update`.
    /// inspect this.
    /// will grow in size.
    pub weights: DMat<FloatT>,
}

impl<FloatT: Zero + Clone + Copy> OnlineNMF<FloatT> {
    /// returns an online nonnegative matrix factorization
    /// that is supposed to find `nhidden` hidden variables
    /// when repeatedly being `update`d with columns of `nobserved` variables
    pub fn new(nobserved: usize, nhidden: usize) -> OnlineNMF<FloatT> {
        OnlineNMF {
            hidden: DMat::new_zeros(nhidden, nobserved),
            weights: DMat::new_zeros(0, nhidden)
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.ncols()
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.nrows()
    }

    pub fn update(&mut self, new_observed_columns: &DMat<FloatT>) {
        assert_eq!(self.nobserved(), new_observed_columns.nrows());

        // do nothing for now
    }
}
<commit_msg>remove unnecessary imports<commit_after>/*!
factorizes a matrix of times and observed values
into ...

use it by repeatedly calling `update` with data
and inspecting `hidden` and `weights`.
*/

extern crate num;
use self::num::{Zero};

extern crate nalgebra;
use self::nalgebra::{DMat};

pub struct OnlineNMF<FloatT> {
    /// maps hidden variables (= rows) to observed variables (= cols).
    /// changes on every `update`.
    /// stays constant in size.
    pub hidden: DMat<FloatT>,
    /// maps times (= rows) to hidden variables (= cols).
    /// changes on every `update`.
    /// inspect this.
    /// will grow in size.
    pub weights: DMat<FloatT>,
}

impl<FloatT: Zero + Clone + Copy> OnlineNMF<FloatT> {
    /// returns an online nonnegative matrix factorization
    /// that is supposed to find `nhidden` hidden variables
    /// when repeatedly being `update`d with columns of `nobserved` variables
    pub fn new(nobserved: usize, nhidden: usize) -> OnlineNMF<FloatT> {
        OnlineNMF {
            hidden: DMat::new_zeros(nhidden, nobserved),
            weights: DMat::new_zeros(0, nhidden)
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.ncols()
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.nrows()
    }

    pub fn update(&mut self, new_observed_columns: &DMat<FloatT>) {
        assert_eq!(self.nobserved(), new_observed_columns.nrows());

        // do nothing for now
    }
}
<|endoftext|>