<commit_before>use errors::OscError;
use types::{OscBundle, OscMessage, OscPacket, OscType, Result};

use byteorder::{BigEndian, ByteOrder};

/// Takes a reference to an OSC packet and returns
/// a byte vector on success. If the packet was invalid
/// an `OscError` is returned.
///
/// # Example
///
/// ```
/// use rosc::{OscPacket,OscMessage,OscType};
/// use rosc::encoder;
///
/// let packet = OscPacket::Message(OscMessage{
///         addr: "/greet/me".to_string(),
///         args: Some(vec![OscType::String("hi!".to_string())])
///     }
/// );
/// assert!(encoder::encode(&packet).is_ok())
/// ```
pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(msg.addr.clone()));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if let Some(ref args) = msg.args {
        for arg in args {
            let (bytes, tags): (Option<Vec<u8>>, String) = encode_arg(arg)?;

            type_tags.extend(tags.chars());
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(type_tags.into_iter().collect::<String>()));
    if !arg_bytes.is_empty() {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string("#bundle".to_string()).into_iter());

    match encode_arg(&bundle.timetag)? {
        (Some(x), _) => {
            bundle_bytes.extend(x.into_iter());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.is_empty() {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = encode_message(m)?;
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.into_iter().chain(msg.into_iter()));
            }
            OscPacket::Bundle(ref b) => {
                let bdl = encode_bundle(b)?;
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.into_iter().chain(bdl.into_iter()));
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, String)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), "i".into()))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), "h".into()))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), "f".into()))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), "d".into()))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), "c".into()))
        }
        OscType::String(ref x) => Ok((Some(encode_string(x.clone())), "s".into())),
        OscType::Blob(ref x) => {
            let padded_blob_length: usize = pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), "b".into()))
        }
        OscType::Time(ref x, ref y) => Ok((Some(encode_time_tag(*x, *y)), "t".into())),
        OscType::Midi(ref x) => Ok((Some(vec![x.port, x.status, x.data1, x.data2]), "m".into())),
        OscType::Color(ref x) => Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), "r".into())),
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, "T".into()))
            } else {
                Ok((None, "F".into()))
            }
        }
        OscType::Nil => Ok((None, "N".into())),
        OscType::Inf => Ok((None, "I".into())),
        OscType::Array(ref x) => {
            let mut bytes = vec![0u8; 0];
            let mut type_tags = String::from("[");
            for v in x.content.iter() {
                match encode_arg(v) {
                    Ok((Some(other_bytes), other_type_tags)) => {
                        bytes.extend(other_bytes);
                        type_tags.push_str(&other_type_tags);
                    }
                    Ok((None, other_type_tags)) => {
                        type_tags.push_str(&other_type_tags);
                    }
                    Err(err) => return Err(err),
                }
            }
            type_tags.push_str("]");
            Ok((Some(bytes), type_tags))
        }
    }
}

/// Null terminates the byte representation of string `s` and
/// adds null bytes until the length of the result is a
/// multiple of 4.
pub fn encode_string<S: Into<String>>(s: S) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.into().as_bytes().into();
    bytes.push(0u8);
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

/// Returns the position padded to 4 bytes.
///
/// # Example
///
/// ```
/// use rosc::encoder;
///
/// let pos: u64 = 10;
/// assert_eq!(12u64, encoder::pad(pos))
/// ```
pub fn pad(pos: u64) -> u64 {
    match pos % 4 {
        0 => pos,
        d => pos + (4 - d),
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}

#[test]
fn test_pad() {
    assert_eq!(4, pad(4));
    assert_eq!(8, pad(5));
    assert_eq!(8, pad(6));
    assert_eq!(8, pad(7));
}
<commit_msg>Replace unwrap with if let<commit_after>use errors::OscError;
use types::{OscBundle, OscMessage, OscPacket, OscType, Result};

use byteorder::{BigEndian, ByteOrder};

/// Takes a reference to an OSC packet and returns
/// a byte vector on success. If the packet was invalid
/// an `OscError` is returned.
///
/// # Example
///
/// ```
/// use rosc::{OscPacket,OscMessage,OscType};
/// use rosc::encoder;
///
/// let packet = OscPacket::Message(OscMessage{
///         addr: "/greet/me".to_string(),
///         args: Some(vec![OscType::String("hi!".to_string())])
///     }
/// );
/// assert!(encoder::encode(&packet).is_ok())
/// ```
pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(msg.addr.clone()));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if let Some(ref args) = msg.args {
        for arg in args {
            let (bytes, tags): (Option<Vec<u8>>, String) = encode_arg(arg)?;

            type_tags.extend(tags.chars());
            if let Some(data) = bytes {
                arg_bytes.extend(data);
            }
        }
    }

    msg_bytes.extend(encode_string(type_tags.into_iter().collect::<String>()));
    if !arg_bytes.is_empty() {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string("#bundle".to_string()).into_iter());

    match encode_arg(&bundle.timetag)? {
        (Some(x), _) => {
            bundle_bytes.extend(x.into_iter());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.is_empty() {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = encode_message(m)?;
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.into_iter().chain(msg.into_iter()));
            }
            OscPacket::Bundle(ref b) => {
                let bdl = encode_bundle(b)?;
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.into_iter().chain(bdl.into_iter()));
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, String)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), "i".into()))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), "h".into()))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), "f".into()))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), "d".into()))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), "c".into()))
        }
        OscType::String(ref x) => Ok((Some(encode_string(x.clone())), "s".into())),
        OscType::Blob(ref x) => {
            let padded_blob_length: usize = pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), "b".into()))
        }
        OscType::Time(ref x, ref y) => Ok((Some(encode_time_tag(*x, *y)), "t".into())),
        OscType::Midi(ref x) => Ok((Some(vec![x.port, x.status, x.data1, x.data2]), "m".into())),
        OscType::Color(ref x) => Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), "r".into())),
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, "T".into()))
            } else {
                Ok((None, "F".into()))
            }
        }
        OscType::Nil => Ok((None, "N".into())),
        OscType::Inf => Ok((None, "I".into())),
        OscType::Array(ref x) => {
            let mut bytes = vec![0u8; 0];
            let mut type_tags = String::from("[");
            for v in x.content.iter() {
                match encode_arg(v) {
                    Ok((Some(other_bytes), other_type_tags)) => {
                        bytes.extend(other_bytes);
                        type_tags.push_str(&other_type_tags);
                    }
                    Ok((None, other_type_tags)) => {
                        type_tags.push_str(&other_type_tags);
                    }
                    Err(err) => return Err(err),
                }
            }
            type_tags.push_str("]");
            Ok((Some(bytes), type_tags))
        }
    }
}

/// Null terminates the byte representation of string `s` and
/// adds null bytes until the length of the result is a
/// multiple of 4.
pub fn encode_string<S: Into<String>>(s: S) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.into().as_bytes().into();
    bytes.push(0u8);
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

/// Returns the position padded to 4 bytes.
///
/// # Example
///
/// ```
/// use rosc::encoder;
///
/// let pos: u64 = 10;
/// assert_eq!(12u64, encoder::pad(pos))
/// ```
pub fn pad(pos: u64) -> u64 {
    match pos % 4 {
        0 => pos,
        d => pos + (4 - d),
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}

#[test]
fn test_pad() {
    assert_eq!(4, pad(4));
    assert_eq!(8, pad(5));
    assert_eq!(8, pad(6));
    assert_eq!(8, pad(7));
}
<|endoftext|>


<commit_before>use std::io::Cursor;
use std::io::prelude::*;
use super::parser::{Parser, ParseEvent, ParseError};
use super::lexer::Lexer;
use super::position::Position;

use super::types::*;

pub struct Figtree<T: Read> {
    parser: Parser<T>,
}

impl<T: Read> Figtree<T> {
    pub fn new(input: T) -> Self {
        Figtree {
            parser: Parser::parse(Lexer::lex(input))
        }
    }

    pub fn from_string(input: &str) -> Figtree<Cursor<&[u8]>> {
        Figtree::new(Cursor::new(input.as_bytes()))
    }

    pub fn parse(&mut self) -> Result<Document, (ParseError, Position)> {
        let mut doc = Document::new();
        match self.parser.next() {
            Some(Ok((ParseEvent::FileStart, _))) =>
                self.parse_file(&mut doc),
            Some(Ok(_)) | None =>
                panic!("ParseEvent occurred that cannot happen at this time."),
            Some(Err(error)) =>
                return Err(error),
        }
        Ok(doc)
    }

    fn parse_file(&mut self, doc: &mut Document) {
        // TODO: implement!
    }
}
<commit_msg>Allow document object to be created<commit_after>use std::io::Cursor;
use std::io::prelude::*;
use super::parser::{Parser, ParseEvent, ParseError};
use super::lexer::Lexer;
use super::position::Position;

use super::types::*;

pub struct Figtree<T: Read> {
    parser: Parser<T>,
}

impl<T: Read> Figtree<T> {
    pub fn new(input: T) -> Self {
        Figtree {
            parser: Parser::parse(Lexer::lex(input))
        }
    }

    pub fn from_string(input: &str) -> Figtree<Cursor<&[u8]>> {
        Figtree::new(Cursor::new(input.as_bytes()))
    }

    pub fn parse(&mut self) -> Result<Document, (ParseError, Position)> {
        let mut doc = Document::new();
        match self.parser.next() {
            Some(Ok((ParseEvent::FileStart, _))) => {
                if let Some(err) = self.parse_file(&mut doc) {
                    return Err(err);
                }
            }
            Some(Ok(_)) | None =>
                unreachable!("ParseEvent occurred that cannot happen at this time."),
            Some(Err(error)) =>
                return Err(error),
        }
        Ok(doc)
    }

    fn parse_file(&mut self, doc: &mut Document) -> Option<(ParseError, Position)> {
        loop {
            match self.parser.next() {
                Some(Ok((ParseEvent::NodeStart(name), _))) => {
                    if let Some(err) = self.parse_node(doc.new_node(name)) {
                        return Some(err);
                    }
                },
                Some(Ok((ParseEvent::FileEnd, _))) => {
                    return None;
                },
                Some(Ok(ev)) =>
                    unreachable!("ParseEvent {:?} occured that cannot happen at this time.", ev),
                Some(Err(error)) => { return Some(error) },
                None =>
                    unreachable!("EOF occured that cannot happen at this time."),
            }
        }
    }

    fn parse_node(&mut self, doc: &mut Node) -> Option<(ParseError, Position)> {
        None
    }
}

#[cfg(test)]
mod tests {
    use super::Figtree;
    use std::io::Cursor;

    #[test]
    fn construct_empty_file() {
        let mut figgy = Figtree::<Cursor<&[u8]>>::from_string("");
        let config = figgy.parse().unwrap();
        assert_eq!(config.nodes.len(), 0);
    }
}
<|endoftext|>


<commit_before>use lalafell::commands::MentionOrId;

use serenity::model::guild::{Member, Role};

pub enum Filter {
  Include(FilterKind),
  Exclude(FilterKind)
}

impl Filter {
  fn find_all_filters(input: &str) -> Option<Vec<String>> {
    let mut roles = Vec::new();
    let mut last_index = 0;
    loop {
      let index = input[last_index..].find("role:").or_else(|| input[last_index..].find("user:"));
      let mut i = match index {
        Some(i) => i,
        None => break
      };
      if i + last_index != 0 && &input[i + last_index - 1..i + last_index] == "!" {
        i -= 1;
      }
      if !input[last_index..last_index + i].trim().is_empty() {
        return None;
      }
      if let Some(role) = Filter::lexical_parse(&input[last_index + i..]) {
        last_index += role.len();
        roles.push(role);
      }
      last_index += i;
    }
    if input.len() - last_index != 0 {
      None
    } else {
      Some(roles)
    }
  }

  fn lexical_parse(input: &str) -> Option<String> {
    let mut acc = String::new();
    let mut escaped = false;
    let mut take_whitespace = false;
    for c in input.chars() {
      if c == '`' {
        if take_whitespace {
          break;
        } else {
          take_whitespace = true;
          continue;
        }
      }
      if c == '\\' && !escaped {
        escaped = true;
        continue;
      }
      if escaped {
        acc.push(c);
        escaped = false;
        continue;
      }
      if !take_whitespace && c == ' ' {
        break;
      }
      acc.push(c);
    }
    if acc.is_empty() {
      None
    } else {
      Some(acc)
    }
  }

  pub fn all_filters(s: &str) -> Option<Vec<Filter>> {
    some_or!(Filter::find_all_filters(s), return None)
      .into_iter()
      .map(|x| Filter::parse(&x))
      .collect()
  }

  pub fn parse(s: &str) -> Option<Filter> {
    if s.starts_with('!') {
      let fk = match FilterKind::parse(&s[1..]) {
        Some(f) => f,
        None => return None
      };
      Some(Filter::Exclude(fk))
    } else {
      let fk = match FilterKind::parse(s) {
        Some(f) => f,
        None => return None
      };
      Some(Filter::Include(fk))
    }
  }

  pub fn matches(&self, member: &Member, roles: &[Role]) -> bool {
    let (include, fk) = match *self {
      Filter::Include(ref fk) => (true, fk),
      Filter::Exclude(ref fk) => (false, fk)
    };
    match *fk {
      FilterKind::Role(ref role_name) => {
        let role_name = role_name.to_lowercase();
        let role = match roles.iter().find(|r| r.name.to_lowercase() == role_name) {
          Some(r) => r,
          None => return !include
        };
        member.roles.iter().any(|r| *r == role.id) == include
      }
      FilterKind::User(id) => (member.user.read().id.0 == id) == include
    }
  }
}

impl ToString for Filter {
  fn to_string(&self) -> String {
    match *self {
      Filter::Include(ref fk) => fk.to_string(),
      Filter::Exclude(ref fk) => format!("!{}", fk.to_string())
    }
  }
}

pub enum FilterKind {
  Role(String),
  User(u64)
}

impl FilterKind {
  pub fn parse(s: &str) -> Option<FilterKind> {
    let parts: Vec<&str> = s.splitn(2, ':').collect();
    if parts.len() != 2 {
      return None;
    }
    let (kind, value) = (&parts[0], &parts[1]);
    match kind.to_lowercase().as_str() {
      "role" => Some(FilterKind::Role(value.to_string())),
      "user" | "member" => {
        let id = match MentionOrId::parse(value) {
          Ok(i) => i,
          Err(_) => return None
        };
        Some(FilterKind::User(id.0))
      }
      _ => None
    }
  }
}

impl ToString for FilterKind {
  fn to_string(&self) -> String {
    match *self {
      FilterKind::Role(ref role) => format!("role:{}", role),
      FilterKind::User(id) => format!("user:{}", id)
    }
  }
}
<commit_msg>fix: record consumed bytes<commit_after>use lalafell::commands::MentionOrId;

use serenity::model::guild::{Member, Role};

pub enum Filter {
  Include(FilterKind),
  Exclude(FilterKind)
}

impl Filter {
  fn find_all_filters(input: &str) -> Option<Vec<String>> {
    let mut roles = Vec::new();
    let mut last_index = 0;
    loop {
      let index = input[last_index..].find("role:").or_else(|| input[last_index..].find("user:"));
      let mut i = match index {
        Some(i) => i,
        None => break
      };
      if i + last_index != 0 && &input[i + last_index - 1..i + last_index] == "!" {
        i -= 1;
      }
      if !input[last_index..last_index + i].trim().is_empty() {
        return None;
      }
      if let Some((bytes, role)) = Filter::lexical_parse(&input[last_index + i..]) {
        last_index += bytes;
        roles.push(role);
      }
      last_index += i;
    }
    if input.len() - last_index != 0 {
      None
    } else {
      Some(roles)
    }
  }

  fn lexical_parse(input: &str) -> Option<(usize, String)> {
    let mut consumed_bytes = 0;
    let mut acc = String::new();
    let mut escaped = false;
    let mut take_whitespace = false;
    for c in input.chars() {
      if c == '`' {
        consumed_bytes += c.len_utf8();
        if take_whitespace {
          break;
        } else {
          take_whitespace = true;
          continue;
        }
      }
      if c == '\\' && !escaped {
        consumed_bytes += c.len_utf8();
        escaped = true;
        continue;
      }
      if escaped {
        acc.push(c);
        consumed_bytes += c.len_utf8();
        escaped = false;
        continue;
      }
      if !take_whitespace && c == ' ' {
        break;
      }
      acc.push(c);
      consumed_bytes += c.len_utf8();
    }
    if acc.is_empty() {
      None
    } else {
      Some((consumed_bytes, acc))
    }
  }

  pub fn all_filters(s: &str) -> Option<Vec<Filter>> {
    some_or!(Filter::find_all_filters(s), return None)
      .into_iter()
      .map(|x| Filter::parse(&x))
      .collect()
  }

  pub fn parse(s: &str) -> Option<Filter> {
    if s.starts_with('!') {
      let fk = match FilterKind::parse(&s[1..]) {
        Some(f) => f,
        None => return None
      };
      Some(Filter::Exclude(fk))
    } else {
      let fk = match FilterKind::parse(s) {
        Some(f) => f,
        None => return None
      };
      Some(Filter::Include(fk))
    }
  }

  pub fn matches(&self, member: &Member, roles: &[Role]) -> bool {
    let (include, fk) = match *self {
      Filter::Include(ref fk) => (true, fk),
      Filter::Exclude(ref fk) => (false, fk)
    };
    match *fk {
      FilterKind::Role(ref role_name) => {
        let role_name = role_name.to_lowercase();
        let role = match roles.iter().find(|r| r.name.to_lowercase() == role_name) {
          Some(r) => r,
          None => return !include
        };
        member.roles.iter().any(|r| *r == role.id) == include
      }
      FilterKind::User(id) => (member.user.read().id.0 == id) == include
    }
  }
}

impl ToString for Filter {
  fn to_string(&self) -> String {
    match *self {
      Filter::Include(ref fk) => fk.to_string(),
      Filter::Exclude(ref fk) => format!("!{}", fk.to_string())
    }
  }
}

pub enum FilterKind {
  Role(String),
  User(u64)
}

impl FilterKind {
  pub fn parse(s: &str) -> Option<FilterKind> {
    let parts: Vec<&str> = s.splitn(2, ':').collect();
    if parts.len() != 2 {
      return None;
    }
    let (kind, value) = (&parts[0], &parts[1]);
    match kind.to_lowercase().as_str() {
      "role" => Some(FilterKind::Role(value.to_string())),
      "user" | "member" => {
        let id = match MentionOrId::parse(value) {
          Ok(i) => i,
          Err(_) => return None
        };
        Some(FilterKind::User(id.0))
      }
      _ => None
    }
  }
}

impl ToString for FilterKind {
  fn to_string(&self) -> String {
    match *self {
      FilterKind::Role(ref role) => format!("role:{}", role),
      FilterKind::User(id) => format!("user:{}", id)
    }
  }
}
<|endoftext|>


<commit_before>use super::Dimension;

/// An iterator over the indexes of an array shape.
///
/// Iterator element type is `D`.
#[derive(Clone)]
pub struct Indexes<D> {
    dim: D,
    index: Option<D>,
}

impl<D: Dimension> Indexes<D>
{
    /// Create an iterator over the array shape `dim`.
    pub fn new(dim: D) -> Indexes<D>
    {
        Indexes {
            index: dim.first_index(),
            dim: dim,
        }
    }
}

impl<D: Dimension> Iterator for Indexes<D>
{
    type Item = D;
    #[inline]
    fn next(&mut self) -> Option<D>
    {
        let index = match self.index {
            None => return None,
            Some(ref ix) => ix.clone(),
        };
        self.index = self.dim.next_for(index.clone());
        Some(index)
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        let l = match self.index {
            None => 0,
            Some(ref ix) => {
                let gone = self.dim.default_strides().slice().iter()
                            .zip(ix.slice().iter())
                                 .fold(0, |s, (&a, &b)| s + a as usize * b as usize);
                self.dim.size() - gone
            }
        };
        (l, Some(l))
    }
}

<commit_msg>impl ESI for Indexes<commit_after>use super::Dimension;

/// An iterator over the indexes of an array shape.
///
/// Iterator element type is `D`.
#[derive(Clone)]
pub struct Indexes<D> {
    dim: D,
    index: Option<D>,
}

impl<D: Dimension> Indexes<D>
{
    /// Create an iterator over the array shape `dim`.
    pub fn new(dim: D) -> Indexes<D>
    {
        Indexes {
            index: dim.first_index(),
            dim: dim,
        }
    }
}

impl<D> Iterator for Indexes<D>
    where D: Dimension,
{
    type Item = D;
    #[inline]
    fn next(&mut self) -> Option<D> {
        let index = match self.index {
            None => return None,
            Some(ref ix) => ix.clone(),
        };
        self.index = self.dim.next_for(index.clone());
        Some(index)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let l = match self.index {
            None => 0,
            Some(ref ix) => {
                let gone = self.dim.default_strides().slice().iter()
                            .zip(ix.slice().iter())
                                 .fold(0, |s, (&a, &b)| s + a as usize * b as usize);
                self.dim.size() - gone
            }
        };
        (l, Some(l))
    }
}

impl<D> ExactSizeIterator for Indexes<D> where D: Dimension { }
<|endoftext|>


<commit_before>use std::cell::Cell;

// I think I can think of Cell as getter/setter pair
// You can not get the ref value from Cell. It gives you copy of value
// you mutate this value somewhere in your program and set it back with setter.
pub struct SpiderRobot {
    species: String,
    web_enabled: bool,
    leg_devices: [fd::FileDesc, 8],
    hardware_error_count: Cell<u32>,
}

impl SpiderRobot {
    // Increase the error count by 1
    pub fn add_hardware_error(&self) {
        let n = self.hardware_error_count.get();
        self.hardware_error_count.set(n+1);
    }

    pub fn has_hardware_errors(&self) {
        self.hardware_error_count.get() > 0
    }
}

fn main() {
    SpiderRobot { species, web_enabled, leg_devices, hardware_error_count }
}
<commit_msg>wrap log in refcell<commit_after>use std::cell::Cell;

// I think I can think of Cell as getter/setter pair
// You can not get the ref value from Cell. It gives you copy of value
// you mutate this value somewhere in your program and set it back with setter.

// BTW File is not Copyable, so Cell, want help us. (we need mut File to do something with it)
pub struct SpiderRobot {
    species: String,
    web_enabled: bool,
    leg_devices: [fd::FileDesc, 8],
    hardware_error_count: Cell<u32>,
    log: RefCell<File>// with refcell everything is better
}

impl SpiderRobot {
    // Increase the error count by 1
    pub fn add_hardware_error(&self) {
        let n = self.hardware_error_count.get();
        self.hardware_error_count.set(n+1);
    }

    pub fn has_hardware_errors(&self) {
        self.hardware_error_count.get() > 0
    }

    pub fn log(&self, message: &str) {
        let mut file = self.log_file.borrow_mut();
        writeln!(file, "{}", message).unwrap();
    }
}

fn main() {
    SpiderRobot { species, web_enabled, leg_devices, hardware_error_count }
}
<|endoftext|>


<commit_before>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and modify the value which will be returned next
    /// if let Some(mut p) = iter.peek_mut() {
    ///     if *p == &2 {
    ///         *p = &5;
    ///     }
    /// }
    ///
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<commit_msg>Rollup merge of #79478 - lukaslueg:peek_mut_docs, r=m-ou-se<commit_after>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// // Like with `peek()`, we can see into the future without advancing the iterator.
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and set the value behind the mutable reference.
    /// if let Some(p) = iter.peek_mut() {
    ///     assert_eq!(*p, &2);
    ///     *p = &5;
    /// }
    ///
    /// // The value we put in reappears as the iterator continues.
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// #![feature(peekable_next_if)]
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[unstable(feature = "peekable_next_if", issue = "72480")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<|endoftext|>


<commit_before>//! Module for handling content types

use std::collections::BTreeMap;
use std::str::FromStr;

use itertools::Itertools;
use lazy_static::*;
use log::*;
use mime::Mime;
use serde::{Deserialize, Serialize};

/// Content type of a body
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
pub struct ContentType {
  /// Main content type
  pub main_type: String,
  /// Sub content type
  pub sub_type: String,
  /// Content type attributes
  pub attributes: BTreeMap<String, String>,
  /// Suffix
  pub suffix: Option<String>
}

lazy_static! {
  /// XML Content Type
  pub static ref XML: ContentType = ContentType {
    main_type: "application".into(),
    sub_type: "xml".into(),
    .. ContentType::default()
  };

  /// HTML Content Type
  pub static ref HTML: ContentType = ContentType {
    main_type: "text".into(),
    sub_type: "html".into(),
    .. ContentType::default()
  };

  /// JSON Content Type
  pub static ref JSON: ContentType = ContentType {
    main_type: "application".into(),
    sub_type: "json".into(),
    .. ContentType::default()
  };

  /// TEXT Content Type
  pub static ref TEXT: ContentType = ContentType {
    main_type: "text".into(),
    sub_type: "plain".into(),
    .. ContentType::default()
  };
}

impl ContentType {
  /// Parses a string into a ContentType
  pub fn parse<'a, S: Into<&'a str>>(content_type: S) -> Result<ContentType, String> {
    let content_type = content_type.into();
    match Mime::from_str(content_type) {
      Ok(mime) => {
        Ok(ContentType {
          main_type: mime.type_().to_string(),
          sub_type: mime.subtype().to_string(),
          attributes: mime.params().map(|(key, value)| (key.to_string(), value.to_string())).collect(),
          suffix: mime.suffix().map(|name| name.to_string())
        })
      },
      Err(err) => {
        let message = format!("Failed to parse '{}' as a content type: {}",
                              content_type, err);
        warn!("{}", message);
        Err(message)
      }
    }
  }

  /// If it is a JSON type
  pub fn is_json(&self) -> bool {
    self.main_type == "application" && (self.sub_type.starts_with("json") ||
      self.suffix.as_ref().unwrap_or(&String::default()) == "json")
  }

  /// If it is a XML type
  pub fn is_xml(&self) -> bool {
    (self.main_type == "application" || self.main_type == "text") && (self.sub_type == "xml" ||
      self.suffix.as_ref().unwrap_or(&String::default()) == "xml")
  }

  /// If it is a text type
  pub fn is_text(&self) -> bool {
    self.main_type == "text" || self.is_xml() || self.is_json()
  }

  /// If it is a known binary type
  pub fn is_binary(&self) -> bool {
    match self.main_type.as_str() {
      "audio" | "font" | "image" | "video" => true,
      "text" => false,
      _ => false
    }
  }

  /// Returns the base type with no attributes or suffix
  pub fn base_type(&self) -> ContentType {
    match self.suffix.as_ref() {
      Some(suffix) => ContentType {
        main_type: self.main_type.clone(),
        sub_type: suffix.clone(),
        .. ContentType::default()
      },
      None => ContentType {
        main_type: self.main_type.clone(),
        sub_type: self.sub_type.clone(),
        .. ContentType::default()
      }
    }
  }

  /// If the content type is the default type
  pub fn is_unknown(&self) -> bool {
    self.main_type == "*" || self.sub_type == "*"
  }

  /// Equals, ignoring attributes if not present on self
  pub fn is_equivalent_to(&self, other: &ContentType) -> bool {
    if self.attributes.is_empty() {
      self.main_type == other.main_type && self.sub_type == other.sub_type
    } else {
      self == other
    }
  }
}

impl Default for ContentType {
  fn default() -> Self {
    ContentType {
      main_type: "*".into(),
      sub_type: "*".into(),
      attributes: BTreeMap::new(),
      suffix: None
    }
  }
}

impl std::fmt::Display for ContentType {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let base = if let Some(suffix) = &self.suffix {
      format!("{}/{}+{}", self.main_type, self.sub_type, suffix)
    } else {
      format!("{}/{}", self.main_type, self.sub_type)
    };
    if self.attributes.is_empty() {
      write!(f, "{}", base)
    } else {
      write!(f, "{};{}", base, self.attributes.iter()
        .map(|(key, value)| format!("{}={}", key, value)).join(";"))
    }
  }
}

impl From<String> for ContentType {
  fn from(s: String) -> Self {
    ContentType::parse(s.as_str()).unwrap_or_default()
  }
}

impl From<&String> for ContentType {
  fn from(s: &String) -> Self {
    ContentType::parse(s.as_str()).unwrap_or_default()
  }
}

impl From<&str> for ContentType {
  fn from(s: &str) -> Self {
    ContentType::parse(s).unwrap_or_default()
  }
}

impl FromStr for ContentType {
  type Err = String;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    ContentType::parse(s)
  }
}

impl PartialEq<str> for ContentType {
  fn eq(&self, other: &str) -> bool {
    match ContentType::parse(other) {
      Ok(other) => *self == other,
      Err(_) => false
    }
  }
}

impl PartialEq<&str> for ContentType {
  fn eq(&self, other: &&str) -> bool {
    match ContentType::parse(*other) {
      Ok(other) => *self == other,
      Err(_) => false
    }
  }
}

#[cfg(test)]
mod tests {
  use expectest::prelude::*;
  use maplit::btreemap;

  use super::ContentType;

  #[test]
  fn parse_test() {
    let content_type = &ContentType::parse("application/json").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"json".to_string()));
    expect!(content_type.attributes.iter()).to(be_empty());
    expect!(content_type.clone().suffix).to(be_none());

    let content_type = &ContentType::parse("application/json;charset=UTF-16").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"json".to_string()));
    expect!(content_type.clone().attributes).to(be_equal_to(btreemap! {
    "charset".to_string() => "utf-16".to_string()
  }));
    expect!(content_type.clone().suffix).to(be_none());

    let content_type = &ContentType::parse("application/hal+json; charset=UTF-8").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"hal".to_string()));
    expect!(content_type.clone().attributes).to(be_equal_to(btreemap! {
    "charset".to_string() => "utf-8".to_string()
  }));
    expect!(content_type.clone().suffix).to(be_some().value("json".to_string()));
  }

  #[test]
  fn to_string_test() {
    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal+json".into(),
      ..ContentType::default()
    };
    expect!(content_type.to_string()).to(be_equal_to("application/hal+json".to_string()));

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal+json".into(),
      attributes: btreemap! {
      "charset".to_string() => "UTF-32".to_string(),
      "b".to_string() => "c".to_string()
    },
      suffix: None
    };
    expect!(content_type.to_string()).to(be_equal_to("application/hal+json;b=c;charset=UTF-32".to_string()));
  }

  #[test]
  fn is_json_test() {
    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal".into(),
      suffix: Some("json".to_string()),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_false());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "json".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "json-rpc".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());
  }

  #[test]
  fn is_xml_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.is_xml()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_false());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_true());
  }

  #[test]
  fn base_type_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    }));

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    }));

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      attributes: btreemap! { "charset".to_string() => "UTF-8".to_string() },
      ..ContentType::default()
    };
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    }));
  }

  #[test]
  fn is_binary_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.is_binary()).to(be_false());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_binary()).to(be_false());

    let content_type = ContentType {
      main_type: "image".into(),
      sub_type: "jpeg".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_binary()).to(be_true());
  }
}
<commit_msg>fix: make application/xml equivalent to text/xml<commit_after>//! Module for handling content types

use std::collections::BTreeMap;
use std::str::FromStr;

use itertools::Itertools;
use lazy_static::*;
use log::*;
use mime::Mime;
use serde::{Deserialize, Serialize};

/// Content type of a body
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
pub struct ContentType {
  /// Main content type
  pub main_type: String,
  /// Sub content type
  pub sub_type: String,
  /// Content type attributes
  pub attributes: BTreeMap<String, String>,
  /// Suffix
  pub suffix: Option<String>
}

lazy_static! {
  /// XML Content Type
  pub static ref XML: ContentType = ContentType {
    main_type: "application".into(),
    sub_type: "xml".into(),
    .. ContentType::default()
  };

  /// HTML Content Type
  pub static ref HTML: ContentType = ContentType {
    main_type: "text".into(),
    sub_type: "html".into(),
    .. ContentType::default()
  };

  /// JSON Content Type
  pub static ref JSON: ContentType = ContentType {
    main_type: "application".into(),
    sub_type: "json".into(),
    .. ContentType::default()
  };

  /// TEXT Content Type
  pub static ref TEXT: ContentType = ContentType {
    main_type: "text".into(),
    sub_type: "plain".into(),
    .. ContentType::default()
  };
}

impl ContentType {
  /// Parses a string into a ContentType
  pub fn parse<'a, S: Into<&'a str>>(content_type: S) -> Result<ContentType, String> {
    let content_type = content_type.into();
    match Mime::from_str(content_type) {
      Ok(mime) => {
        Ok(ContentType {
          main_type: mime.type_().to_string(),
          sub_type: mime.subtype().to_string(),
          attributes: mime.params().map(|(key, value)| (key.to_string(), value.to_string())).collect(),
          suffix: mime.suffix().map(|name| name.to_string())
        })
      },
      Err(err) => {
        let message = format!("Failed to parse '{}' as a content type: {}",
                              content_type, err);
        warn!("{}", message);
        Err(message)
      }
    }
  }

  /// If it is a JSON type
  pub fn is_json(&self) -> bool {
    self.main_type == "application" && (self.sub_type.starts_with("json") ||
      self.suffix.as_ref().unwrap_or(&String::default()) == "json")
  }

  /// If it is a XML type
  pub fn is_xml(&self) -> bool {
    (self.main_type == "application" || self.main_type == "text") && (self.sub_type == "xml" ||
      self.suffix.as_ref().unwrap_or(&String::default()) == "xml")
  }

  /// If it is a XML type (not including ones with suffixes like atom+xml)
  pub fn is_strict_xml(&self) -> bool {
    (self.main_type == "application" || self.main_type == "text") && self.sub_type == "xml"
  }

  /// If it is a text type
  pub fn is_text(&self) -> bool {
    self.main_type == "text" || self.is_xml() || self.is_json()
  }

  /// If it is a known binary type
  pub fn is_binary(&self) -> bool {
    match self.main_type.as_str() {
      "audio" | "font" | "image" | "video" => true,
      "text" => false,
      _ => false
    }
  }

  /// Returns the base type with no attributes or suffix
  pub fn base_type(&self) -> ContentType {
    match self.suffix.as_ref() {
      Some(suffix) => ContentType {
        main_type: self.main_type.clone(),
        sub_type: suffix.clone(),
        .. ContentType::default()
      },
      None => ContentType {
        main_type: self.main_type.clone(),
        sub_type: self.sub_type.clone(),
        .. ContentType::default()
      }
    }
  }

  /// If the content type is the default type
  pub fn is_unknown(&self) -> bool {
    self.main_type == "*" || self.sub_type == "*"
  }

  /// Equals, ignoring attributes if not present on self
  pub fn is_equivalent_to(&self, other: &ContentType) -> bool {
    if self.is_strict_xml() && other.is_strict_xml() {
      self.attributes.is_empty() || self.attributes == other.attributes
    }
    else if self.attributes.is_empty() {
      self.main_type == other.main_type && self.sub_type == other.sub_type
    } else {
      self == other
    }
  }
}

impl Default for ContentType {
  fn default() -> Self {
    ContentType {
      main_type: "*".into(),
      sub_type: "*".into(),
      attributes: BTreeMap::new(),
      suffix: None
    }
  }
}

impl std::fmt::Display for ContentType {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let base = if let Some(suffix) = &self.suffix {
      format!("{}/{}+{}", self.main_type, self.sub_type, suffix)
    } else {
      format!("{}/{}", self.main_type, self.sub_type)
    };
    if self.attributes.is_empty() {
      write!(f, "{}", base)
    } else {
      write!(f, "{};{}", base, self.attributes.iter()
        .map(|(key, value)| format!("{}={}", key, value)).join(";"))
    }
  }
}

impl From<String> for ContentType {
  fn from(s: String) -> Self {
    ContentType::parse(s.as_str()).unwrap_or_default()
  }
}

impl From<&String> for ContentType {
  fn from(s: &String) -> Self {
    ContentType::parse(s.as_str()).unwrap_or_default()
  }
}

impl From<&str> for ContentType {
  fn from(s: &str) -> Self {
    ContentType::parse(s).unwrap_or_default()
  }
}

impl FromStr for ContentType {
  type Err = String;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    ContentType::parse(s)
  }
}

impl PartialEq<str> for ContentType {
  fn eq(&self, other: &str) -> bool {
    match ContentType::parse(other) {
      Ok(other) => *self == other,
      Err(_) => false
    }
  }
}

impl PartialEq<&str> for ContentType {
  fn eq(&self, other: &&str) -> bool {
    match ContentType::parse(*other) {
      Ok(other) => *self == other,
      Err(_) => false
    }
  }
}

#[cfg(test)]
mod tests {
  use expectest::prelude::*;
  use maplit::btreemap;

  use super::ContentType;

  #[test]
  fn parse_test() {
    let content_type = &ContentType::parse("application/json").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"json".to_string()));
    expect!(content_type.attributes.iter()).to(be_empty());
    expect!(content_type.clone().suffix).to(be_none());

    let content_type = &ContentType::parse("application/json;charset=UTF-16").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"json".to_string()));
    expect!(content_type.clone().attributes).to(be_equal_to(btreemap! {
    "charset".to_string() => "utf-16".to_string()
  }));
    expect!(content_type.clone().suffix).to(be_none());

    let content_type = &ContentType::parse("application/hal+json; charset=UTF-8").unwrap();
    expect!(&content_type.main_type).to(be_equal_to(&"application".to_string()));
    expect!(&content_type.sub_type).to(be_equal_to(&"hal".to_string()));
    expect!(content_type.clone().attributes).to(be_equal_to(btreemap! {
    "charset".to_string() => "utf-8".to_string()
  }));
    expect!(content_type.clone().suffix).to(be_some().value("json".to_string()));
  }

  #[test]
  fn to_string_test() {
    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal+json".into(),
      ..ContentType::default()
    };
    expect!(content_type.to_string()).to(be_equal_to("application/hal+json".to_string()));

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal".into(),
      suffix: Some("json".into()),
      ..ContentType::default()
    };
    expect!(content_type.to_string()).to(be_equal_to("application/hal+json".to_string()));

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal+json".into(),
      attributes: btreemap! {
      "charset".to_string() => "UTF-32".to_string(),
      "b".to_string() => "c".to_string()
    },
      suffix: None
    };
    expect!(content_type.to_string()).to(be_equal_to("application/hal+json;b=c;charset=UTF-32".to_string()));
  }

  #[test]
  fn is_json_test() {
    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "hal".into(),
      suffix: Some("json".to_string()),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_false());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "json".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "json-rpc".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_json()).to(be_true());
  }

  #[test]
  fn is_xml_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.is_xml()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_false());

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_true());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_xml()).to(be_true());
  }

  #[test]
  fn base_type_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    }));

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    }));

    let content_type = ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      attributes: btreemap! { "charset".to_string() => "UTF-8".to_string() },
      ..ContentType::default()
    };
    expect!(content_type.base_type()).to(be_equal_to(ContentType {
      main_type: "application".into(),
      sub_type: "xml".into(),
      ..ContentType::default()
    }));
  }

  #[test]
  fn is_binary_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    expect!(content_type.is_binary()).to(be_false());

    let content_type = ContentType {
      main_type: "text".into(),
      sub_type: "javascript".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_binary()).to(be_false());

    let content_type = ContentType {
      main_type: "image".into(),
      sub_type: "jpeg".into(),
      ..ContentType::default()
    };
    expect!(content_type.is_binary()).to(be_true());
  }

  #[test]
  fn xml_equivalent_test() {
    let content_type = ContentType::parse("application/atom+xml").unwrap();
    let content_type2 = ContentType::parse("application/xml").unwrap();
    let content_type3 = ContentType::parse("text/xml").unwrap();
    let content_type4 = ContentType::parse("application/json").unwrap();

    expect!(content_type.is_equivalent_to(&content_type)).to(be_true());
    expect!(content_type.is_equivalent_to(&content_type2)).to(be_false());
    expect!(content_type2.is_equivalent_to(&content_type3)).to(be_true());
    expect!(content_type2.is_equivalent_to(&content_type4)).to(be_false());
  }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

extern crate mentat_core;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_sql;

use mentat_core::{
    Entid,
    TypedValue,
};

use mentat_query_algebrizer::{
    DatomsColumn,
    QualifiedAlias,
    SourceAlias,
};

use mentat_sql::{
    BuildQueryResult,
    QueryBuilder,
    QueryFragment,
    SQLiteQueryBuilder,
    SQLQuery,
};

//---------------------------------------------------------
// A Mentat-focused representation of a SQL query.

/// One of the things that can appear in a projection or a constraint. Note that we use
/// `TypedValue` here; it's not pure SQL, but it avoids us having to concern ourselves at this
/// point with the translation between a `TypedValue` and the storage-layer representation.
///
/// Eventually we might allow different translations by providing a different `QueryBuilder`
/// implementation for each storage backend. Passing `TypedValue`s here allows for that.
pub enum ColumnOrExpression {
    Column(QualifiedAlias),
    Entid(Entid),       // Because it's so common.
    Value(TypedValue),
}

pub type Name = String;

pub struct ProjectedColumn(pub ColumnOrExpression, pub Name);

pub enum Projection {
    Columns(Vec<ProjectedColumn>),
    Star,
    One,
}

#[derive(Copy, Clone)]
pub struct Op(&'static str);      // TODO: we can do better than this!

pub enum Constraint {
    Infix {
        op: Op,
        left: ColumnOrExpression,
        right: ColumnOrExpression
    }
}

impl Constraint {
    pub fn equal(left: ColumnOrExpression, right: ColumnOrExpression) -> Constraint {
        Constraint::Infix {
            op: Op("="),
            left: left,
            right: right,
        }
    }
}

#[allow(dead_code)]
enum JoinOp {
    Inner,
}

// Short-hand for a list of tables all inner-joined.
pub struct TableList(pub Vec<SourceAlias>);

pub struct Join {
    left: TableOrSubquery,
    op: JoinOp,
    right: TableOrSubquery,
    // TODO: constraints (ON, USING).
}

#[allow(dead_code)]
enum TableOrSubquery {
    Table(SourceAlias),
    // TODO: Subquery.
}

pub enum FromClause {
    TableList(TableList),      // Short-hand for a pile of inner joins.
    Join(Join),
}

pub struct SelectQuery {
    pub projection: Projection,
    pub from: FromClause,
    pub constraints: Vec<Constraint>,
    pub limit: Option<u64>,
}

// We know that DatomsColumns are safe to serialize.
fn push_column(qb: &mut QueryBuilder, col: &DatomsColumn) {
    qb.push_sql(col.as_str());
}

//---------------------------------------------------------
// Turn that representation into SQL.

impl QueryFragment for ColumnOrExpression {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::ColumnOrExpression::*;
        match self {
            &Column(QualifiedAlias(ref table, ref column)) => {
                out.push_identifier(table.as_str())?;
                out.push_sql(".");
                push_column(out, column);
                Ok(())
            },
            &Entid(entid) => {
                out.push_sql(entid.to_string().as_str());
                Ok(())
            },
            &Value(ref v) => {
                out.push_typed_value(v)
            },
        }
    }
}

impl QueryFragment for Projection {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::Projection::*;
        match self {
            &One => out.push_sql("1"),
            &Star => out.push_sql("*"),
            &Columns(ref cols) => {
                let &ProjectedColumn(ref col, ref alias) = &cols[0];
                col.push_sql(out)?;
                out.push_sql(" AS ");
                out.push_identifier(alias.as_str())?;

                for &ProjectedColumn(ref col, ref alias) in &cols[1..] {
                    out.push_sql(", ");
                    col.push_sql(out)?;
                    out.push_sql(" AS ");
                    out.push_identifier(alias.as_str())?;
                }
            },
        };
        Ok(())
    }
}

impl QueryFragment for Op {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        // No escaping needed.
        out.push_sql(self.0);
        Ok(())
    }
}

impl QueryFragment for Constraint {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::Constraint::*;
        match self {
            &Infix { ref op, ref left, ref right } => {
                left.push_sql(out)?;
                out.push_sql(" ");
                op.push_sql(out)?;
                out.push_sql(" ");
                right.push_sql(out)
            }
        }
    }
}

impl QueryFragment for JoinOp {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        out.push_sql(" JOIN ");
        Ok(())
    }
}

// We don't own SourceAlias or QueryFragment, so we can't implement the trait.
fn source_alias_push_sql(out: &mut QueryBuilder, sa: &SourceAlias) -> BuildQueryResult {
    let &SourceAlias(ref table, ref alias) = sa;
    out.push_identifier(table.name())?;
    out.push_sql(" AS ");
    out.push_identifier(alias.as_str())
}

impl QueryFragment for TableList {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        if self.0.is_empty() {
            return Ok(());
        }

        source_alias_push_sql(out, &self.0[0])?;

        for sa in self.0.iter().skip(1) {
            out.push_sql(", ");
            source_alias_push_sql(out, sa)?;
        }
        Ok(())
    }
}

impl QueryFragment for Join {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        self.left.push_sql(out)?;
        self.op.push_sql(out)?;
        self.right.push_sql(out)
    }
}

impl QueryFragment for TableOrSubquery {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::TableOrSubquery::*;
        match self {
            &Table(ref sa) => source_alias_push_sql(out, sa)
        }
    }
}

impl QueryFragment for FromClause {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::FromClause::*;
        match self {
            &TableList(ref table_list) => table_list.push_sql(out),
            &Join(ref join) => join.push_sql(out),
        }
    }
}

impl QueryFragment for SelectQuery {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        out.push_sql("SELECT ");
        self.projection.push_sql(out)?;

        out.push_sql(" FROM ");
        self.from.push_sql(out)?;

        if self.constraints.is_empty() {
            return Ok(());
        }

        out.push_sql(" WHERE ");
        self.constraints[0].push_sql(out)?;

        for constraint in self.constraints[1..].iter() {
            out.push_sql(" AND ");
            constraint.push_sql(out)?;
        }

        // Guaranteed to be positive: u64.
        if let Some(limit) = self.limit {
            out.push_sql(" LIMIT ");
            out.push_sql(limit.to_string().as_str());
        }

        Ok(())
    }
}

impl SelectQuery {
    pub fn to_sql_query(&self) -> mentat_sql::Result<SQLQuery> {
        let mut builder = SQLiteQueryBuilder::new();
        self.push_sql(&mut builder).map(|_| builder.finish())
    }
}

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

    #[test]
    fn test_end_to_end() {

        // [:find ?x :where [?x 65537 ?v] [?x 65536 ?v]]
        let datoms00 = "datoms00".to_string();
        let datoms01 = "datoms01".to_string();
        let eq = Op("=");
        let source_aliases = vec![
            SourceAlias(DatomsTable::Datoms, datoms00.clone()),
            SourceAlias(DatomsTable::Datoms, datoms01.clone()),
        ];
        let query = SelectQuery {
            projection: Projection::Columns(
                            vec![
                                ProjectedColumn(
                                    ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Entity)),
                                    "x".to_string()),
                            ]),
            from: FromClause::TableList(TableList(source_aliases)),
            constraints: vec![
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms01.clone(), DatomsColumn::Value)),
                    right: ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Value)),
                },
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Attribute)),
                    right: ColumnOrExpression::Entid(65537),
                },
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms01.clone(), DatomsColumn::Attribute)),
                    right: ColumnOrExpression::Entid(65536),
                },
            ],
            limit: None,
        };

        let SQLQuery { sql, args } = query.to_sql_query().unwrap();
        println!("{}", sql);
        assert_eq!("SELECT `datoms00`.e AS `x` FROM `datoms` AS `datoms00`, `datoms` AS `datoms01` WHERE `datoms01`.v = `datoms00`.v AND `datoms00`.a = 65537 AND `datoms01`.a = 65536", sql);
        assert!(args.is_empty());
    }
}
<commit_msg>Pre: add an interpose macro for SQL output.<commit_after>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

extern crate mentat_core;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_sql;

use mentat_core::{
    Entid,
    TypedValue,
};

use mentat_query_algebrizer::{
    DatomsColumn,
    QualifiedAlias,
    SourceAlias,
};

use mentat_sql::{
    BuildQueryResult,
    QueryBuilder,
    QueryFragment,
    SQLiteQueryBuilder,
    SQLQuery,
};

//---------------------------------------------------------
// A Mentat-focused representation of a SQL query.

/// One of the things that can appear in a projection or a constraint. Note that we use
/// `TypedValue` here; it's not pure SQL, but it avoids us having to concern ourselves at this
/// point with the translation between a `TypedValue` and the storage-layer representation.
///
/// Eventually we might allow different translations by providing a different `QueryBuilder`
/// implementation for each storage backend. Passing `TypedValue`s here allows for that.
pub enum ColumnOrExpression {
    Column(QualifiedAlias),
    Entid(Entid),       // Because it's so common.
    Value(TypedValue),
}

pub type Name = String;

pub struct ProjectedColumn(pub ColumnOrExpression, pub Name);

pub enum Projection {
    Columns(Vec<ProjectedColumn>),
    Star,
    One,
}

#[derive(Copy, Clone)]
pub struct Op(&'static str);      // TODO: we can do better than this!

pub enum Constraint {
    Infix {
        op: Op,
        left: ColumnOrExpression,
        right: ColumnOrExpression
    }
}

impl Constraint {
    pub fn equal(left: ColumnOrExpression, right: ColumnOrExpression) -> Constraint {
        Constraint::Infix {
            op: Op("="),
            left: left,
            right: right,
        }
    }
}

#[allow(dead_code)]
enum JoinOp {
    Inner,
}

// Short-hand for a list of tables all inner-joined.
pub struct TableList(pub Vec<SourceAlias>);

pub struct Join {
    left: TableOrSubquery,
    op: JoinOp,
    right: TableOrSubquery,
    // TODO: constraints (ON, USING).
}

#[allow(dead_code)]
enum TableOrSubquery {
    Table(SourceAlias),
    // TODO: Subquery.
}

pub enum FromClause {
    TableList(TableList),      // Short-hand for a pile of inner joins.
    Join(Join),
}

pub struct SelectQuery {
    pub projection: Projection,
    pub from: FromClause,
    pub constraints: Vec<Constraint>,
    pub limit: Option<u64>,
}

// We know that DatomsColumns are safe to serialize.
fn push_column(qb: &mut QueryBuilder, col: &DatomsColumn) {
    qb.push_sql(col.as_str());
}

//---------------------------------------------------------
// Turn that representation into SQL.

impl QueryFragment for ColumnOrExpression {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::ColumnOrExpression::*;
        match self {
            &Column(QualifiedAlias(ref table, ref column)) => {
                out.push_identifier(table.as_str())?;
                out.push_sql(".");
                push_column(out, column);
                Ok(())
            },
            &Entid(entid) => {
                out.push_sql(entid.to_string().as_str());
                Ok(())
            },
            &Value(ref v) => {
                out.push_typed_value(v)
            },
        }
    }
}

impl QueryFragment for Projection {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::Projection::*;
        match self {
            &One => out.push_sql("1"),
            &Star => out.push_sql("*"),
            &Columns(ref cols) => {
                let &ProjectedColumn(ref col, ref alias) = &cols[0];
                col.push_sql(out)?;
                out.push_sql(" AS ");
                out.push_identifier(alias.as_str())?;

                for &ProjectedColumn(ref col, ref alias) in &cols[1..] {
                    out.push_sql(", ");
                    col.push_sql(out)?;
                    out.push_sql(" AS ");
                    out.push_identifier(alias.as_str())?;
                }
            },
        };
        Ok(())
    }
}

impl QueryFragment for Op {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        // No escaping needed.
        out.push_sql(self.0);
        Ok(())
    }
}

macro_rules! interpose {
    ( $name: ident, $across: expr, $body: block, $inter: block ) => {
        let mut seq = $across.iter();
        if let Some($name) = seq.next() {
            $body;
            for $name in seq {
                $inter;
                $body;
            }
        }
    }
}

impl QueryFragment for Constraint {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::Constraint::*;
        match self {
            &Infix { ref op, ref left, ref right } => {
                left.push_sql(out)?;
                out.push_sql(" ");
                op.push_sql(out)?;
                out.push_sql(" ");
                right.push_sql(out)
            }
        }
    }
}

impl QueryFragment for JoinOp {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        out.push_sql(" JOIN ");
        Ok(())
    }
}

// We don't own SourceAlias or QueryFragment, so we can't implement the trait.
fn source_alias_push_sql(out: &mut QueryBuilder, sa: &SourceAlias) -> BuildQueryResult {
    let &SourceAlias(ref table, ref alias) = sa;
    out.push_identifier(table.name())?;
    out.push_sql(" AS ");
    out.push_identifier(alias.as_str())
}

impl QueryFragment for TableList {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        if self.0.is_empty() {
            return Ok(());
        }

        interpose!(sa, self.0,
                   { source_alias_push_sql(out, sa)? },
                   { out.push_sql(", ") });
        Ok(())
    }
}

impl QueryFragment for Join {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        self.left.push_sql(out)?;
        self.op.push_sql(out)?;
        self.right.push_sql(out)
    }
}

impl QueryFragment for TableOrSubquery {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::TableOrSubquery::*;
        match self {
            &Table(ref sa) => source_alias_push_sql(out, sa)
        }
    }
}

impl QueryFragment for FromClause {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        use self::FromClause::*;
        match self {
            &TableList(ref table_list) => table_list.push_sql(out),
            &Join(ref join) => join.push_sql(out),
        }
    }
}

impl QueryFragment for SelectQuery {
    fn push_sql(&self, out: &mut QueryBuilder) -> BuildQueryResult {
        out.push_sql("SELECT ");
        self.projection.push_sql(out)?;

        out.push_sql(" FROM ");
        self.from.push_sql(out)?;

        if self.constraints.is_empty() {
            return Ok(());
        }

        out.push_sql(" WHERE ");
        interpose!(constraint, self.constraints,
                   { constraint.push_sql(out)? },
                   { out.push_sql(" AND ") });

        // Guaranteed to be positive: u64.
        if let Some(limit) = self.limit {
            out.push_sql(" LIMIT ");
            out.push_sql(limit.to_string().as_str());
        }

        Ok(())
    }
}

impl SelectQuery {
    pub fn to_sql_query(&self) -> mentat_sql::Result<SQLQuery> {
        let mut builder = SQLiteQueryBuilder::new();
        self.push_sql(&mut builder).map(|_| builder.finish())
    }
}

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

    #[test]
    fn test_end_to_end() {

        // [:find ?x :where [?x 65537 ?v] [?x 65536 ?v]]
        let datoms00 = "datoms00".to_string();
        let datoms01 = "datoms01".to_string();
        let eq = Op("=");
        let source_aliases = vec![
            SourceAlias(DatomsTable::Datoms, datoms00.clone()),
            SourceAlias(DatomsTable::Datoms, datoms01.clone()),
        ];
        let query = SelectQuery {
            projection: Projection::Columns(
                            vec![
                                ProjectedColumn(
                                    ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Entity)),
                                    "x".to_string()),
                            ]),
            from: FromClause::TableList(TableList(source_aliases)),
            constraints: vec![
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms01.clone(), DatomsColumn::Value)),
                    right: ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Value)),
                },
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms00.clone(), DatomsColumn::Attribute)),
                    right: ColumnOrExpression::Entid(65537),
                },
                Constraint::Infix {
                    op: eq.clone(),
                    left: ColumnOrExpression::Column(QualifiedAlias(datoms01.clone(), DatomsColumn::Attribute)),
                    right: ColumnOrExpression::Entid(65536),
                },
            ],
            limit: None,
        };

        let SQLQuery { sql, args } = query.to_sql_query().unwrap();
        println!("{}", sql);
        assert_eq!("SELECT `datoms00`.e AS `x` FROM `datoms` AS `datoms00`, `datoms` AS `datoms01` WHERE `datoms01`.v = `datoms00`.v AND `datoms00`.a = 65537 AND `datoms01`.a = 65536", sql);
        assert!(args.is_empty());
    }
}
<|endoftext|>