<commit_before>use std::collections::{BTreeSet, HashMap};
use std::fmt::{Debug, Display, Formatter, Result};
use std::iter::{Extend, FromIterator};

use serde::{Deserialize, Serialize};

#[cfg(feature = "with-constraint")]
use constraints;

#[cfg(test)]
mod tests;

pub trait BindingsValue
    : Clone + Debug + Default + Deserialize + Display + Eq + PartialEq + PartialOrd + Serialize
    {
    /// Construct a BindingsValue variable using the specified string as it's name
    fn variable(_s: &String) -> Option<Self> {
        None
    }
    /// Extract the name of this BindingsValue variable (if it is a variable)
    fn to_variable(&self) -> Option<String> {
        None
    }
}

#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct Bindings<T: BindingsValue> {
    #[serde(default)]
    data: HashMap<String, T>,
    #[serde(default)]
    equivalences: HashMap<String, BTreeSet<String>>,
}

impl<T: BindingsValue> PartialEq for Bindings<T> {
    fn eq(&self, other: &Bindings<T>) -> bool {
        self.data.eq(&other.data) && self.equivalences.eq(&other.equivalences)
    }
}
impl<T: BindingsValue> Eq for Bindings<T> {}

impl<T: BindingsValue> Default for Bindings<T> {
    fn default() -> Self {
        Bindings {
            data: HashMap::new(),
            equivalences: HashMap::new(),
        }
    }
}

impl<T: BindingsValue> Bindings<T> {
    pub fn new() -> Bindings<T> {
        Bindings::default()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn new_from_vec(data: Vec<(String, T)>) -> Bindings<T> {
        data.into_iter().collect()
    }

    pub fn has_binding(&self, variable: &String) -> bool {
        self.data.contains_key(variable)
    }

    pub fn set_binding(&self, variable: &String, val: T) -> Bindings<T> {
        let mut bindings_copy = self.clone();

        bindings_copy.set_binding_mut(variable, val);

        bindings_copy
    }

    pub fn set_binding_mut(&mut self, variable: &String, val: T) {
        self.ensure_equivalence_exists_mut(variable);

        if let Some(variable2) = val.to_variable() {
            self.add_equivalence(variable, &variable2);
        } else {
            for equivalent_variable in self.equivalences.get(variable).unwrap().iter() {
                self.data.insert(equivalent_variable.clone(), val.clone());
            }
        }
    }

    fn add_equivalence(&mut self, variable: &String, variable2: &String) {
        self.ensure_equivalence_exists_mut(&variable2);
        self.merge_equivalences_mut(variable, &variable2);
    }

    fn ensure_equivalence_exists_mut(&mut self, variable: &String) {
        if !self.equivalences.contains_key(variable) {
            self.equivalences.insert(variable.clone(),
                                     vec![variable.clone()].into_iter().collect());
        }
    }

    fn merge_equivalences_mut(&mut self, variable: &String, variable2: &String) {
        let mut merge = self.equivalences.get(variable).cloned().unwrap();
        merge.extend(self.equivalences.get(variable2).cloned().unwrap());

        self.equivalences.insert(variable.clone(), merge.clone());
        self.equivalences.insert(variable2.clone(), merge);
    }

    pub fn get_binding(&self, variable: &String) -> Option<T> {
        match self.data.get(variable) {
            Some(val) => Some(val.clone()),
            None => None,
        }
    }

    pub fn update_bindings(&self, variable: &String, value: &T) -> Option<Self> {
        // If we are setting a variable to itself, then do nothing
        if Some(variable.clone()) == value.to_variable() {
            return Some(self.clone());
        }
        match self.get_binding(&variable) {
            Some(ref val) if val == value => Some(self.clone()),
            Some(_) => None,
            None => Some(self.set_binding(variable, value.clone())),
        }
    }

    pub fn merge(&self, other: &Self) -> Self {
        let mut bindings = self.clone();

        // Merge in equivalences
        for (ref key, ref equivalences) in other.equivalences.iter() {
            for equivalent_key in equivalences.iter() {
                bindings.ensure_equivalence_exists_mut(key);
                bindings.add_equivalence(key, equivalent_key);
            }
        }

        // Merge in values
        for (key, value) in other.data.iter() {
            bindings.set_binding_mut(&key, value.clone())
        }

        bindings
    }

    pub fn equivalences_string(&self) -> String {
        let equivalent_v: Vec<String> = self.equivalences.iter().map(|(key, value)| format!("{} => {:?}", key, value)).collect();
        equivalent_v.join(",")
    }
}

impl<T: BindingsValue> FromIterator<(String, T)> for Bindings<T> {
    fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Bindings<T> {
        let mut bindings: Bindings<T> = Bindings::new();
        for (key, value) in iter {
            bindings.set_binding_mut(&key, value);
        }
        bindings
    }
}

impl<T: BindingsValue> Extend<(String, T)> for Bindings<T> {
    fn extend<It>(&mut self, iter: It)
        where It: IntoIterator<Item = (String, T)>
    {
        for (key, value) in iter {
            self.set_binding_mut(&key, value);
        }
    }
}

impl<T: BindingsValue> Display for Bindings<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(write!(f, "("));
        let mut sorted_keys: Vec<String> = self.data.keys().cloned().collect();
        sorted_keys.sort();
        for key in sorted_keys.into_iter() {
            let ref val = self.data[&key];
            try!(write!(f, "{} => {}, ", key, val));
        }
        try!(write!(f, "Equivalences: {}", self.equivalences_string()));
        write!(f, ")")
    }
}

pub trait Unify<T: BindingsValue>
    : Clone + Debug + Display + Eq + Serialize + Deserialize + PartialEq {
    fn unify(&self, &Self, &Bindings<T>) -> Option<Bindings<T>>;
    fn apply_bindings(&self, &Bindings<T>) -> Option<Self>;
    fn variables(&self) -> Vec<String>;
    fn get_variable(&self, &String) -> Option<&T>;
    fn rename_variables(&self, &HashMap<String, String>) -> Self;
    fn nil() -> Self;
    fn equiv(&self, other: &Self) -> bool {
        self.unify(other, &Bindings::new()).is_some()
    }
}

pub trait Apply<T: BindingsValue, U: Unify<T>>
    : Clone + Debug + Display + Eq + PartialEq + Deserialize + Serialize {
    fn arg_count(&self) -> usize;
    fn apply(&self, &Vec<&U>, &Bindings<T>) -> Option<(U, Bindings<T>)>;
    // NOTE: replace constraints with validate_bindings
    #[cfg(feature = "with-constraint")]
    fn constraints<'a>(&'a self) -> Vec<&'a constraints::Constraint>;
    fn r_apply(&self, &U, &Bindings<T>) -> Option<(Vec<U>, Bindings<T>)>;
    fn snowflake(&self, String) -> Self;
}
<commit_msg>Updated comment<commit_after>use std::collections::{BTreeSet, HashMap};
use std::fmt::{Debug, Display, Formatter, Result};
use std::iter::{Extend, FromIterator};

use serde::{Deserialize, Serialize};

#[cfg(feature = "with-constraint")]
use constraints;

#[cfg(test)]
mod tests;

pub trait BindingsValue
    : Clone + Debug + Default + Deserialize + Display + Eq + PartialEq + PartialOrd + Serialize
    {
    /// Construct a BindingsValue variable using the specified string as it's name
    fn variable(_s: &String) -> Option<Self> {
        None
    }
    /// Extract the name of this BindingsValue variable (if it is a variable)
    fn to_variable(&self) -> Option<String> {
        None
    }
}

#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct Bindings<T: BindingsValue> {
    #[serde(default)]
    data: HashMap<String, T>,
    #[serde(default)]
    equivalences: HashMap<String, BTreeSet<String>>,
}

impl<T: BindingsValue> PartialEq for Bindings<T> {
    fn eq(&self, other: &Bindings<T>) -> bool {
        self.data.eq(&other.data) && self.equivalences.eq(&other.equivalences)
    }
}
impl<T: BindingsValue> Eq for Bindings<T> {}

impl<T: BindingsValue> Default for Bindings<T> {
    fn default() -> Self {
        Bindings {
            data: HashMap::new(),
            equivalences: HashMap::new(),
        }
    }
}

impl<T: BindingsValue> Bindings<T> {
    pub fn new() -> Bindings<T> {
        Bindings::default()
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn new_from_vec(data: Vec<(String, T)>) -> Bindings<T> {
        data.into_iter().collect()
    }

    pub fn has_binding(&self, variable: &String) -> bool {
        self.data.contains_key(variable)
    }

    pub fn set_binding(&self, variable: &String, val: T) -> Bindings<T> {
        let mut bindings_copy = self.clone();

        bindings_copy.set_binding_mut(variable, val);

        bindings_copy
    }

    pub fn set_binding_mut(&mut self, variable: &String, val: T) {
        self.ensure_equivalence_exists_mut(variable);

        if let Some(variable2) = val.to_variable() {
            self.add_equivalence(variable, &variable2);
        } else {
            for equivalent_variable in self.equivalences.get(variable).unwrap().iter() {
                self.data.insert(equivalent_variable.clone(), val.clone());
            }
        }
    }

    fn add_equivalence(&mut self, variable: &String, variable2: &String) {
        self.ensure_equivalence_exists_mut(&variable2);
        self.merge_equivalences_mut(variable, &variable2);
    }

    fn ensure_equivalence_exists_mut(&mut self, variable: &String) {
        if !self.equivalences.contains_key(variable) {
            self.equivalences.insert(variable.clone(),
                                     vec![variable.clone()].into_iter().collect());
        }
    }

    fn merge_equivalences_mut(&mut self, variable: &String, variable2: &String) {
        let mut merge = self.equivalences.get(variable).cloned().unwrap();
        merge.extend(self.equivalences.get(variable2).cloned().unwrap());

        self.equivalences.insert(variable.clone(), merge.clone());
        self.equivalences.insert(variable2.clone(), merge);
    }

    pub fn get_binding(&self, variable: &String) -> Option<T> {
        match self.data.get(variable) {
            Some(val) => Some(val.clone()),
            None => None,
        }
    }

    pub fn update_bindings(&self, variable: &String, value: &T) -> Option<Self> {
        // If we are setting a variable to itself, then do nothing
        if Some(variable.clone()) == value.to_variable() {
            return Some(self.clone());
        }
        match self.get_binding(&variable) {
            Some(ref val) if val == value => Some(self.clone()),
            Some(_) => None,
            None => Some(self.set_binding(variable, value.clone())),
        }
    }

    pub fn merge(&self, other: &Self) -> Self {
        let mut bindings = self.clone();

        // Merge in equivalences
        for (ref key, ref equivalences) in other.equivalences.iter() {
            for equivalent_key in equivalences.iter() {
                bindings.ensure_equivalence_exists_mut(key);
                bindings.add_equivalence(key, equivalent_key);
            }
        }

        // Merge in values
        for (key, value) in other.data.iter() {
            bindings.set_binding_mut(&key, value.clone())
        }

        bindings
    }

    pub fn equivalences_string(&self) -> String {
        let equivalent_v: Vec<String> = self.equivalences.iter().map(|(key, value)| format!("{} => {:?}", key, value)).collect();
        equivalent_v.join(",")
    }
}

impl<T: BindingsValue> FromIterator<(String, T)> for Bindings<T> {
    fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Bindings<T> {
        let mut bindings: Bindings<T> = Bindings::new();
        for (key, value) in iter {
            bindings.set_binding_mut(&key, value);
        }
        bindings
    }
}

impl<T: BindingsValue> Extend<(String, T)> for Bindings<T> {
    fn extend<It>(&mut self, iter: It)
        where It: IntoIterator<Item = (String, T)>
    {
        for (key, value) in iter {
            self.set_binding_mut(&key, value);
        }
    }
}

impl<T: BindingsValue> Display for Bindings<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        try!(write!(f, "("));
        let mut sorted_keys: Vec<String> = self.data.keys().cloned().collect();
        sorted_keys.sort();
        for key in sorted_keys.into_iter() {
            let ref val = self.data[&key];
            try!(write!(f, "{} => {}, ", key, val));
        }
        try!(write!(f, "Equivalences: {}", self.equivalences_string()));
        write!(f, ")")
    }
}

pub trait Unify<T: BindingsValue>
    : Clone + Debug + Display + Eq + Serialize + Deserialize + PartialEq {
    fn unify(&self, &Self, &Bindings<T>) -> Option<Bindings<T>>;
    fn apply_bindings(&self, &Bindings<T>) -> Option<Self>;
    fn variables(&self) -> Vec<String>;
    fn get_variable(&self, &String) -> Option<&T>;
    fn rename_variables(&self, &HashMap<String, String>) -> Self;
    fn nil() -> Self;
    fn equiv(&self, other: &Self) -> bool {
        self.unify(other, &Bindings::new()).is_some()
    }
}

pub trait Apply<T: BindingsValue, U: Unify<T>>
    : Clone + Debug + Display + Eq + PartialEq + Deserialize + Serialize {
    fn arg_count(&self) -> usize;
    fn apply(&self, &Vec<&U>, &Bindings<T>) -> Option<(U, Bindings<T>)>;
    // NOTE: replace constraints with validate_bindings?
    #[cfg(feature = "with-constraint")]
    fn constraints<'a>(&'a self) -> Vec<&'a constraints::Constraint>;
    fn r_apply(&self, &U, &Bindings<T>) -> Option<(Vec<U>, Bindings<T>)>;
    fn snowflake(&self, String) -> Self;
}
<|endoftext|>


<commit_before>
use cpp_ffi_type::{CppFfiType, IndirectionChange};
use caption_strategy::TypeCaptionStrategy;
pub use serializable::{CppBuiltInNumericType, CppSpecificNumericTypeKind, CppTypeBase, CppType,
                       CppTypeIndirection};
extern crate regex;

impl CppBuiltInNumericType {
  pub fn to_cpp_code(&self) -> &'static str {
    match *self {
      CppBuiltInNumericType::Bool => "bool",
      CppBuiltInNumericType::CharS => "char",
      CppBuiltInNumericType::CharU => "char",
      CppBuiltInNumericType::SChar => "signed char",
      CppBuiltInNumericType::UChar => "unsigned char",
      CppBuiltInNumericType::WChar => "wchar_t",
      CppBuiltInNumericType::Char16 => "char16_t",
      CppBuiltInNumericType::Char32 => "char32_t",
      CppBuiltInNumericType::Short => "short",
      CppBuiltInNumericType::UShort => "unsigned short",
      CppBuiltInNumericType::Int => "int",
      CppBuiltInNumericType::UInt => "unsigned int",
      CppBuiltInNumericType::Long => "long",
      CppBuiltInNumericType::ULong => "unsigned long",
      CppBuiltInNumericType::LongLong => "long long",
      CppBuiltInNumericType::ULongLong => "unsigned long long",
      CppBuiltInNumericType::Int128 => "__int128_t",
      CppBuiltInNumericType::UInt128 => "__uint128_t",
      CppBuiltInNumericType::Float => "float",
      CppBuiltInNumericType::Double => "double",
      CppBuiltInNumericType::LongDouble => "long double",
    }
  }

  pub fn all() -> [CppBuiltInNumericType; 21] {
    [CppBuiltInNumericType::Bool,
     CppBuiltInNumericType::CharS,
     CppBuiltInNumericType::CharU,
     CppBuiltInNumericType::SChar,
     CppBuiltInNumericType::UChar,
     CppBuiltInNumericType::WChar,
     CppBuiltInNumericType::Char16,
     CppBuiltInNumericType::Char32,
     CppBuiltInNumericType::Short,
     CppBuiltInNumericType::UShort,
     CppBuiltInNumericType::Int,
     CppBuiltInNumericType::UInt,
     CppBuiltInNumericType::Long,
     CppBuiltInNumericType::ULong,
     CppBuiltInNumericType::LongLong,
     CppBuiltInNumericType::ULongLong,
     CppBuiltInNumericType::Int128,
     CppBuiltInNumericType::UInt128,
     CppBuiltInNumericType::Float,
     CppBuiltInNumericType::Double,
     CppBuiltInNumericType::LongDouble]
  }
}

impl CppTypeBase {
  #[allow(dead_code)]
  pub fn is_void(&self) -> bool {
    match self {
      &CppTypeBase::Void => true,
      _ => false,
    }
  }
  pub fn is_class(&self) -> bool {
    match self {
      &CppTypeBase::Class { .. } => true,
      _ => false,
    }
  }
  pub fn is_template_parameter(&self) -> bool {
    match self {
      &CppTypeBase::TemplateParameter { .. } => true,
      _ => false,
    }
  }
  pub fn to_cpp_code(&self) -> Result<String, String> {
    match *self {
      CppTypeBase::Void => Ok("void".to_string()),
      CppTypeBase::BuiltInNumeric(ref t) => Ok(t.to_cpp_code().to_string()),
      CppTypeBase::Enum { ref name } => Ok(name.clone()),
      CppTypeBase::SpecificNumeric { ref name, .. } => Ok(name.clone()),
      CppTypeBase::PointerSizedInteger { ref name, .. } => Ok(name.clone()),
      CppTypeBase::Class { ref name, ref template_arguments } => {
        match *template_arguments {
          Some(ref args) => {
            let mut arg_texts = Vec::new();
            for arg in args {
              arg_texts.push(try!(arg.to_cpp_code()));
            }
            Ok(format!("{}< {} >", name, arg_texts.join(", ")))
          }
          None => Ok(name.clone()),
        }
      }
      CppTypeBase::TemplateParameter { .. } => {
        return Err(format!("template parameters are not supported here yet"));
      }
      CppTypeBase::FunctionPointer { ref return_type,
                                     ref arguments,
                                     ref allows_variable_arguments } => {
        if *allows_variable_arguments {
          return Err(format!("Function pointers with variadic arguments are not supported"));
        }
        let mut arg_texts = Vec::new();
        for arg in arguments {
          arg_texts.push(try!(arg.to_cpp_code()));
        }
        Ok(format!("{} (*FN_PTR)({})",
                   try!(return_type.as_ref().to_cpp_code()),
                   arg_texts.join(", ")))
      }
    }
  }
  pub fn caption(&self) -> String {
    match *self {
      CppTypeBase::Void => "void".to_string(),
      CppTypeBase::BuiltInNumeric(ref t) => t.to_cpp_code().to_string().replace(" ", "_"),
      CppTypeBase::SpecificNumeric { ref name, .. } => name.clone(),
      CppTypeBase::PointerSizedInteger { ref name, .. } => name.clone(),
      CppTypeBase::Enum { ref name } => name.replace("::", "_"),
      CppTypeBase::Class { ref name, ref template_arguments } => {
        let name_caption = name.replace("::", "_");
        match *template_arguments {
          Some(ref args) => {
            let mut arg_texts = Vec::new();
            for arg in args {
              arg_texts.push(arg.caption(TypeCaptionStrategy::Full));
            }
            format!("{}_{}", name_caption, arg_texts.join("_"))
          }
          None => name_caption,
        }
      }
      CppTypeBase::TemplateParameter { .. } => {
        panic!("template parameters are not supported here yet");
      }
      CppTypeBase::FunctionPointer { .. } => {
        panic!("function pointers are not supported here yet");
      }
    }
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CppTypeRole {
  ReturnType,
  NotReturnType,
}

impl CppType {
  pub fn void() -> Self {
    CppType {
      is_const: false,
      indirection: CppTypeIndirection::None,
      base: CppTypeBase::Void,
    }
  }

  pub fn is_void(&self) -> bool {
    !self.is_const && self.indirection == CppTypeIndirection::None && self.base == CppTypeBase::Void
  }

  pub fn to_cpp_code(&self) -> Result<String, String> {
    let name = try!(self.base.to_cpp_code());
    Ok(format!("{}{}{}",
               if self.is_const {
                 "const "
               } else {
                 ""
               },
               name,
               match self.indirection {
                 CppTypeIndirection::None => "",
                 CppTypeIndirection::Ptr => "*",
                 CppTypeIndirection::Ref => "&",
                 CppTypeIndirection::PtrRef => "*&",
                 CppTypeIndirection::PtrPtr => "**",
                 CppTypeIndirection::RValueRef => "&&",
               }))
  }

  pub fn to_cpp_ffi_type(&self, role: CppTypeRole) -> Result<CppFfiType, String> {
    match self.base {
      CppTypeBase::TemplateParameter { .. } => {
        return Err(format!("Unsupported type"));
      }
      CppTypeBase::FunctionPointer { ref return_type,
                                     ref arguments,
                                     ref allows_variable_arguments } => {
        if *allows_variable_arguments {
          return Err(format!("Function pointers with variadic arguments are not supported"));
        }
        let mut all_types: Vec<&CppType> = arguments.iter().collect();
        all_types.push(return_type.as_ref());
        for arg in all_types {
          match arg.base {
            CppTypeBase::TemplateParameter { .. } => {
              return Err(format!("Function pointers containing template parameters are not \
                                  supported"));
            }
            CppTypeBase::FunctionPointer { .. } => {
              return Err(format!("Function pointers containing nested function pointers are not \
                                  supported"));
            }
            _ => {}
          }
          match arg.indirection {
            CppTypeIndirection::Ref |
            CppTypeIndirection::PtrRef |
            CppTypeIndirection::RValueRef => {
              return Err(format!("Function pointers containing references are not supported"));
            }
            CppTypeIndirection::Ptr | CppTypeIndirection::PtrPtr => {}
            CppTypeIndirection::None => {
              match arg.base {
                CppTypeBase::Class { .. } => {
                  return Err(format!("Function pointers containing classes by value are not \
                                      supported"));
                }
                _ => {}
              }
            }
          }
        }
        return Ok(CppFfiType {
          ffi_type: self.clone(),
          conversion: IndirectionChange::NoChange,
          original_type: self.clone(),
        });
      }
      _ => {}
    }
    let mut result = self.clone();
    let mut conversion = IndirectionChange::NoChange;
    match self.indirection {
      CppTypeIndirection::None |
      CppTypeIndirection::Ptr |
      CppTypeIndirection::PtrPtr => {
        // no change needed
      }
      CppTypeIndirection::Ref => {
        result.indirection = CppTypeIndirection::Ptr;
        conversion = IndirectionChange::ReferenceToPointer;
      }
      _ => return Err("Unsupported level of indirection".to_string()),
    }
    if let CppTypeBase::Class { ref name, .. } = self.base {
      if name == "QFlags" {
        assert!(self.indirection == CppTypeIndirection::None);
        conversion = IndirectionChange::QFlagsToUInt;
        result.base = CppTypeBase::BuiltInNumeric(CppBuiltInNumericType::UInt);
      } else {
        // structs can't be passed by value
        if self.indirection == CppTypeIndirection::None {
          result.indirection = CppTypeIndirection::Ptr;
          conversion = IndirectionChange::ValueToPointer;

          // "const Rect" return type should not be translated to const pointer
          result.is_const = role != CppTypeRole::ReturnType;
        }
      }
    }
    Ok(CppFfiType {
      ffi_type: result,
      conversion: conversion,
      original_type: self.clone(),
    })
  }

  pub fn caption(&self, strategy: TypeCaptionStrategy) -> String {
    match strategy {
      TypeCaptionStrategy::Short => self.base.caption(),
      TypeCaptionStrategy::Full => {
        let mut r = self.base.caption();
        match self.indirection {
          CppTypeIndirection::None => {}
          CppTypeIndirection::Ptr => r = format!("{}_ptr", r),
          CppTypeIndirection::Ref => r = format!("{}_ref", r),
          CppTypeIndirection::PtrRef => r = format!("{}_ptr_ref", r),
          CppTypeIndirection::PtrPtr => r = format!("{}_ptr_ptr", r),
          CppTypeIndirection::RValueRef => r = format!("{}_rvalue_ref", r),
        }
        if self.is_const {
          r = format!("const_{}", r);
        }
        r
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use cpp_type::{CppType, CppTypeRole};
  use caption_strategy::TypeCaptionStrategy;
  use cpp_ffi_type::IndirectionChange;

  #[test]
  fn test1() {
    let type1 = CppType::void();
    assert_eq!(type1.is_void(), true);
    assert_eq!(type1.base.is_void(), true);
    assert_eq!(type1.base.is_class(), false);
    assert_eq!(type1.base.is_template_parameter(), false);
    assert_eq!(type1.to_cpp_code().unwrap(), "void");
    assert_eq!(type1.base.to_cpp_code().unwrap(), "void");
    assert_eq!(type1.base.caption(), "void");

    let ffi1 = type1.to_cpp_ffi_type(CppTypeRole::NotReturnType).unwrap();
    assert_eq!(ffi1.original_type, type1);
    assert_eq!(ffi1.ffi_type, type1);
    assert_eq!(ffi1.conversion, IndirectionChange::NoChange);

    let ffi2 = type1.to_cpp_ffi_type(CppTypeRole::ReturnType).unwrap();
    assert_eq!(ffi2.original_type, type1);
    assert_eq!(ffi2.ffi_type, type1);
    assert_eq!(ffi2.conversion, IndirectionChange::NoChange);

    assert_eq!(type1.caption(TypeCaptionStrategy::Short), "void");
    assert_eq!(type1.caption(TypeCaptionStrategy::Full), "void");

  }

}

<commit_msg>more tests<commit_after>
use cpp_ffi_type::{CppFfiType, IndirectionChange};
use caption_strategy::TypeCaptionStrategy;
pub use serializable::{CppBuiltInNumericType, CppSpecificNumericTypeKind, CppTypeBase, CppType,
                       CppTypeIndirection};
extern crate regex;

impl CppBuiltInNumericType {
  pub fn to_cpp_code(&self) -> &'static str {
    match *self {
      CppBuiltInNumericType::Bool => "bool",
      CppBuiltInNumericType::CharS => "char",
      CppBuiltInNumericType::CharU => "char",
      CppBuiltInNumericType::SChar => "signed char",
      CppBuiltInNumericType::UChar => "unsigned char",
      CppBuiltInNumericType::WChar => "wchar_t",
      CppBuiltInNumericType::Char16 => "char16_t",
      CppBuiltInNumericType::Char32 => "char32_t",
      CppBuiltInNumericType::Short => "short",
      CppBuiltInNumericType::UShort => "unsigned short",
      CppBuiltInNumericType::Int => "int",
      CppBuiltInNumericType::UInt => "unsigned int",
      CppBuiltInNumericType::Long => "long",
      CppBuiltInNumericType::ULong => "unsigned long",
      CppBuiltInNumericType::LongLong => "long long",
      CppBuiltInNumericType::ULongLong => "unsigned long long",
      CppBuiltInNumericType::Int128 => "__int128_t",
      CppBuiltInNumericType::UInt128 => "__uint128_t",
      CppBuiltInNumericType::Float => "float",
      CppBuiltInNumericType::Double => "double",
      CppBuiltInNumericType::LongDouble => "long double",
    }
  }

  pub fn all() -> [CppBuiltInNumericType; 21] {
    [CppBuiltInNumericType::Bool,
     CppBuiltInNumericType::CharS,
     CppBuiltInNumericType::CharU,
     CppBuiltInNumericType::SChar,
     CppBuiltInNumericType::UChar,
     CppBuiltInNumericType::WChar,
     CppBuiltInNumericType::Char16,
     CppBuiltInNumericType::Char32,
     CppBuiltInNumericType::Short,
     CppBuiltInNumericType::UShort,
     CppBuiltInNumericType::Int,
     CppBuiltInNumericType::UInt,
     CppBuiltInNumericType::Long,
     CppBuiltInNumericType::ULong,
     CppBuiltInNumericType::LongLong,
     CppBuiltInNumericType::ULongLong,
     CppBuiltInNumericType::Int128,
     CppBuiltInNumericType::UInt128,
     CppBuiltInNumericType::Float,
     CppBuiltInNumericType::Double,
     CppBuiltInNumericType::LongDouble]
  }
}

impl CppTypeBase {
  #[allow(dead_code)]
  pub fn is_void(&self) -> bool {
    match self {
      &CppTypeBase::Void => true,
      _ => false,
    }
  }
  pub fn is_class(&self) -> bool {
    match self {
      &CppTypeBase::Class { .. } => true,
      _ => false,
    }
  }
  pub fn is_template_parameter(&self) -> bool {
    match self {
      &CppTypeBase::TemplateParameter { .. } => true,
      _ => false,
    }
  }
  pub fn to_cpp_code(&self) -> Result<String, String> {
    match *self {
      CppTypeBase::Void => Ok("void".to_string()),
      CppTypeBase::BuiltInNumeric(ref t) => Ok(t.to_cpp_code().to_string()),
      CppTypeBase::Enum { ref name } => Ok(name.clone()),
      CppTypeBase::SpecificNumeric { ref name, .. } => Ok(name.clone()),
      CppTypeBase::PointerSizedInteger { ref name, .. } => Ok(name.clone()),
      CppTypeBase::Class { ref name, ref template_arguments } => {
        match *template_arguments {
          Some(ref args) => {
            let mut arg_texts = Vec::new();
            for arg in args {
              arg_texts.push(try!(arg.to_cpp_code()));
            }
            Ok(format!("{}< {} >", name, arg_texts.join(", ")))
          }
          None => Ok(name.clone()),
        }
      }
      CppTypeBase::TemplateParameter { .. } => {
        return Err(format!("template parameters are not supported here yet"));
      }
      CppTypeBase::FunctionPointer { ref return_type,
                                     ref arguments,
                                     ref allows_variable_arguments } => {
        if *allows_variable_arguments {
          return Err(format!("Function pointers with variadic arguments are not supported"));
        }
        let mut arg_texts = Vec::new();
        for arg in arguments {
          arg_texts.push(try!(arg.to_cpp_code()));
        }
        Ok(format!("{} (*FN_PTR)({})",
                   try!(return_type.as_ref().to_cpp_code()),
                   arg_texts.join(", ")))
      }
    }
  }
  pub fn caption(&self) -> String {
    match *self {
      CppTypeBase::Void => "void".to_string(),
      CppTypeBase::BuiltInNumeric(ref t) => t.to_cpp_code().to_string().replace(" ", "_"),
      CppTypeBase::SpecificNumeric { ref name, .. } => name.clone(),
      CppTypeBase::PointerSizedInteger { ref name, .. } => name.clone(),
      CppTypeBase::Enum { ref name } => name.replace("::", "_"),
      CppTypeBase::Class { ref name, ref template_arguments } => {
        let name_caption = name.replace("::", "_");
        match *template_arguments {
          Some(ref args) => {
            let mut arg_texts = Vec::new();
            for arg in args {
              arg_texts.push(arg.caption(TypeCaptionStrategy::Full));
            }
            format!("{}_{}", name_caption, arg_texts.join("_"))
          }
          None => name_caption,
        }
      }
      CppTypeBase::TemplateParameter { .. } => {
        panic!("template parameters are not supported here yet");
      }
      CppTypeBase::FunctionPointer { .. } => {
        panic!("function pointers are not supported here yet");
      }
    }
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CppTypeRole {
  ReturnType,
  NotReturnType,
}

impl CppType {
  pub fn void() -> Self {
    CppType {
      is_const: false,
      indirection: CppTypeIndirection::None,
      base: CppTypeBase::Void,
    }
  }

  pub fn is_void(&self) -> bool {
    !self.is_const && self.indirection == CppTypeIndirection::None && self.base == CppTypeBase::Void
  }

  pub fn to_cpp_code(&self) -> Result<String, String> {
    let name = try!(self.base.to_cpp_code());
    Ok(format!("{}{}{}",
               if self.is_const {
                 "const "
               } else {
                 ""
               },
               name,
               match self.indirection {
                 CppTypeIndirection::None => "",
                 CppTypeIndirection::Ptr => "*",
                 CppTypeIndirection::Ref => "&",
                 CppTypeIndirection::PtrRef => "*&",
                 CppTypeIndirection::PtrPtr => "**",
                 CppTypeIndirection::RValueRef => "&&",
               }))
  }

  pub fn to_cpp_ffi_type(&self, role: CppTypeRole) -> Result<CppFfiType, String> {
    match self.base {
      CppTypeBase::TemplateParameter { .. } => {
        return Err(format!("Unsupported type"));
      }
      CppTypeBase::FunctionPointer { ref return_type,
                                     ref arguments,
                                     ref allows_variable_arguments } => {
        if *allows_variable_arguments {
          return Err(format!("Function pointers with variadic arguments are not supported"));
        }
        let mut all_types: Vec<&CppType> = arguments.iter().collect();
        all_types.push(return_type.as_ref());
        for arg in all_types {
          match arg.base {
            CppTypeBase::TemplateParameter { .. } => {
              return Err(format!("Function pointers containing template parameters are not \
                                  supported"));
            }
            CppTypeBase::FunctionPointer { .. } => {
              return Err(format!("Function pointers containing nested function pointers are not \
                                  supported"));
            }
            _ => {}
          }
          match arg.indirection {
            CppTypeIndirection::Ref |
            CppTypeIndirection::PtrRef |
            CppTypeIndirection::RValueRef => {
              return Err(format!("Function pointers containing references are not supported"));
            }
            CppTypeIndirection::Ptr | CppTypeIndirection::PtrPtr => {}
            CppTypeIndirection::None => {
              match arg.base {
                CppTypeBase::Class { .. } => {
                  return Err(format!("Function pointers containing classes by value are not \
                                      supported"));
                }
                _ => {}
              }
            }
          }
        }
        return Ok(CppFfiType {
          ffi_type: self.clone(),
          conversion: IndirectionChange::NoChange,
          original_type: self.clone(),
        });
      }
      _ => {}
    }
    let mut result = self.clone();
    let mut conversion = IndirectionChange::NoChange;
    match self.indirection {
      CppTypeIndirection::None |
      CppTypeIndirection::Ptr |
      CppTypeIndirection::PtrPtr => {
        // no change needed
      }
      CppTypeIndirection::Ref => {
        result.indirection = CppTypeIndirection::Ptr;
        conversion = IndirectionChange::ReferenceToPointer;
      }
      _ => return Err("Unsupported level of indirection".to_string()),
    }
    if let CppTypeBase::Class { ref name, .. } = self.base {
      if name == "QFlags" {
        assert!(self.indirection == CppTypeIndirection::None);
        conversion = IndirectionChange::QFlagsToUInt;
        result.base = CppTypeBase::BuiltInNumeric(CppBuiltInNumericType::UInt);
      } else {
        // structs can't be passed by value
        if self.indirection == CppTypeIndirection::None {
          result.indirection = CppTypeIndirection::Ptr;
          conversion = IndirectionChange::ValueToPointer;

          // "const Rect" return type should not be translated to const pointer
          result.is_const = role != CppTypeRole::ReturnType;
        }
      }
    }
    Ok(CppFfiType {
      ffi_type: result,
      conversion: conversion,
      original_type: self.clone(),
    })
  }

  pub fn caption(&self, strategy: TypeCaptionStrategy) -> String {
    match strategy {
      TypeCaptionStrategy::Short => self.base.caption(),
      TypeCaptionStrategy::Full => {
        let mut r = self.base.caption();
        match self.indirection {
          CppTypeIndirection::None => {}
          CppTypeIndirection::Ptr => r = format!("{}_ptr", r),
          CppTypeIndirection::Ref => r = format!("{}_ref", r),
          CppTypeIndirection::PtrRef => r = format!("{}_ptr_ref", r),
          CppTypeIndirection::PtrPtr => r = format!("{}_ptr_ptr", r),
          CppTypeIndirection::RValueRef => r = format!("{}_rvalue_ref", r),
        }
        if self.is_const {
          r = format!("const_{}", r);
        }
        r
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use cpp_type::{CppType, CppTypeRole, CppTypeIndirection, CppTypeBase, CppBuiltInNumericType,
                 CppSpecificNumericTypeKind};
  use caption_strategy::TypeCaptionStrategy;
  use cpp_ffi_type::IndirectionChange;

  fn assert_type_to_ffi_unchanged(t: &CppType) {
    for role in &[CppTypeRole::NotReturnType, CppTypeRole::ReturnType] {
      let ffi1 = t.to_cpp_ffi_type(role.clone()).unwrap();
      assert_eq!(&ffi1.original_type, t);
      assert_eq!(&ffi1.ffi_type, t);
      assert_eq!(ffi1.conversion, IndirectionChange::NoChange);
    }
  }

  #[test]
  fn void() {
    let type1 = CppType::void();
    assert_eq!(type1.is_void(), true);
    assert_eq!(type1.base.is_void(), true);
    assert_eq!(type1.base.is_class(), false);
    assert_eq!(type1.base.is_template_parameter(), false);
    assert_eq!(type1.to_cpp_code().unwrap(), "void");
    assert_eq!(type1.base.to_cpp_code().unwrap(), "void");
    assert_eq!(type1.base.caption(), "void");
    assert_eq!(type1.caption(TypeCaptionStrategy::Short), "void");
    assert_eq!(type1.caption(TypeCaptionStrategy::Full), "void");
    assert_type_to_ffi_unchanged(&type1);
  }

  #[test]
  fn void_ptr() {
    let type1 = CppType {
      indirection: CppTypeIndirection::Ptr,
      is_const: false,
      base: CppTypeBase::Void,
    };
    assert_eq!(type1.is_void(), false);
    assert_eq!(type1.base.is_void(), true);
    assert_eq!(type1.base.is_class(), false);
    assert_eq!(type1.base.is_template_parameter(), false);
    assert_eq!(type1.to_cpp_code().unwrap(), "void*");
    assert_eq!(type1.base.to_cpp_code().unwrap(), "void");
    assert_eq!(type1.base.caption(), "void");
    assert_eq!(type1.caption(TypeCaptionStrategy::Short), "void");
    assert_eq!(type1.caption(TypeCaptionStrategy::Full), "void_ptr");
    assert_type_to_ffi_unchanged(&type1);
  }

  #[test]
  fn int() {
    let type1 = CppType {
      indirection: CppTypeIndirection::None,
      is_const: false,
      base: CppTypeBase::BuiltInNumeric(CppBuiltInNumericType::Int),
    };
    assert_eq!(type1.is_void(), false);
    assert_eq!(type1.base.is_void(), false);
    assert_eq!(type1.base.is_class(), false);
    assert_eq!(type1.base.is_template_parameter(), false);
    assert_eq!(type1.to_cpp_code().unwrap(), "int");
    assert_eq!(type1.base.to_cpp_code().unwrap(), "int");
    assert_eq!(type1.base.caption(), "int");
    assert_eq!(type1.caption(TypeCaptionStrategy::Short), "int");
    assert_eq!(type1.caption(TypeCaptionStrategy::Full), "int");
    assert_type_to_ffi_unchanged(&type1);
  }

  #[test]
  fn qint64() {
    let type1 = CppType {
      indirection: CppTypeIndirection::None,
      is_const: false,
      base: CppTypeBase::SpecificNumeric {
        name: "qint64".to_string(),
        bits: 64,
        kind: CppSpecificNumericTypeKind::Integer { is_signed: true },
      },
    };
    assert_eq!(type1.is_void(), false);
    assert_eq!(type1.base.is_void(), false);
    assert_eq!(type1.base.is_class(), false);
    assert_eq!(type1.base.is_template_parameter(), false);
    assert_eq!(type1.to_cpp_code().unwrap(), "qint64");
    assert_eq!(type1.base.to_cpp_code().unwrap(), "qint64");
    assert_eq!(type1.base.caption(), "qint64");
    assert_eq!(type1.caption(TypeCaptionStrategy::Short), "qint64");
    assert_eq!(type1.caption(TypeCaptionStrategy::Full), "qint64");
    assert_type_to_ffi_unchanged(&type1);
  }

}
<|endoftext|>


<commit_before>use std::io::Write;
use std::default::Default;

use termion;
use termion::clear;
use termion::cursor;

use errors::*;

fn _return_true() -> bool {
    true
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Line {
    pub text: Option<String>,
    #[serde(rename="cursor")]
    pub cursors: Option<Vec<u64>>,
    pub styles: Vec<i64>,
    #[serde(default="_return_true")]
    #[serde(skip_deserializing)]
    pub is_valid: bool,
}

impl Default for Line {
    fn default() -> Line {
        Line {
            text: None,
            cursors: None,
            styles: vec![],
            is_valid: true,
        }
    }
}

impl Line {
    pub fn invalid() -> Line {
        Line {
            is_valid: false,
            ..Default::default()
        }
    }

    pub fn render<W: Write>(&self, w: &mut W, lineno: u16) -> Result<()> {
        let mut line = self.text.as_ref().cloned().unwrap_or_default();
        self.trim_new_line(&mut line);
        self.add_styles(&mut line)?;
        write!(w, "{}{}{}", cursor::Goto(1, lineno), clear::CurrentLine, line)
            .chain_err(|| ErrorKind::DisplayError)?;
        w.flush().chain_err(|| ErrorKind::DisplayError)?;
        Ok(())
    }

    fn trim_new_line(&self, text: &mut String) {
        if let Some('\n') = text.chars().last() {
            text.pop();
        }
    }

    fn add_styles(&self, text: &mut String) -> Result<()> {
        if self.styles.is_empty() {
            return Ok(());
        }
        if self.styles.len() % 3 != 0 {
            // FIXME: find a more descriptive error for this. Hopefully, this should not happen
            // though.
            error!("Invalid style");
            bail!(ErrorKind::DisplayError);
        }
        let mut style_idx = 0;
        loop {
            let start = self.styles[style_idx] as usize;
            let mut end = start + self.styles[style_idx + 1] as usize;

            if end > text.len() {
                // XXX: when dragging to a line below, xi-core sends a style that ends 1 index
                // after the end of the string. I think it considers the \n as a character, but we
                // remove it when rendering the line. Not sure if this is a bug. Should talk about
                // that on IRC.
                error!("style ends after the end of the line ({} > {})", end, text.len());
                end = text.len();
            }

            if end == text.len() {
                text.push_str(&format!("{}", termion::style::Reset));
            } else {
                text.insert_str(end, &format!("{}", termion::style::Reset));
            }
            text.insert_str(start, &format!("{}", termion::style::Invert));

            style_idx += 3;
            if style_idx >= self.styles.len() {
                break;
            }
        }
        Ok(())
    }
}
<commit_msg>remove FIXME/XXX comments that do not apply<commit_after>use std::io::Write;
use std::default::Default;

use termion;
use termion::clear;
use termion::cursor;

use errors::*;

fn _return_true() -> bool {
    true
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Line {
    pub text: Option<String>,
    #[serde(rename="cursor")]
    pub cursors: Option<Vec<u64>>,
    pub styles: Vec<i64>,
    #[serde(default="_return_true")]
    #[serde(skip_deserializing)]
    pub is_valid: bool,
}

impl Default for Line {
    fn default() -> Line {
        Line {
            text: None,
            cursors: None,
            styles: vec![],
            is_valid: true,
        }
    }
}

impl Line {
    pub fn invalid() -> Line {
        Line {
            is_valid: false,
            ..Default::default()
        }
    }

    pub fn render<W: Write>(&self, w: &mut W, lineno: u16) -> Result<()> {
        let mut line = self.text.as_ref().cloned().unwrap_or_default();
        self.trim_new_line(&mut line);
        self.add_styles(&mut line)?;
        write!(w, "{}{}{}", cursor::Goto(1, lineno), clear::CurrentLine, line)
            .chain_err(|| ErrorKind::DisplayError)?;
        w.flush().chain_err(|| ErrorKind::DisplayError)?;
        Ok(())
    }

    fn trim_new_line(&self, text: &mut String) {
        if let Some('\n') = text.chars().last() {
            text.pop();
        }
    }

    fn add_styles(&self, text: &mut String) -> Result<()> {
        if self.styles.is_empty() {
            return Ok(());
        }
        if self.styles.len() % 3 != 0 {
            error!("Invalid style array (should be a multiple of 3)");
            bail!(ErrorKind::DisplayError);
        }
        let mut style_idx = 0;
        loop {
            let start = self.styles[style_idx] as usize;
            let mut end = start + self.styles[style_idx + 1] as usize;

            if end >= text.len() {
                text.push_str(&format!("{}", termion::style::Reset));
            } else {
                text.insert_str(end, &format!("{}", termion::style::Reset));
            }
            text.insert_str(start, &format!("{}", termion::style::Invert));

            style_idx += 3;
            if style_idx >= self.styles.len() {
                break;
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::path::PathBuf;
use std::rc::Rc;
use std::slice::Iter;
use std::string::String;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;
use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn list_pools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    Ok(vec![m.method_return()])
}

fn create_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let blockdevs = devs.into_iter()
        .map(|x| PathBuf::from(x.inner::<&str>().unwrap()))
        .collect::<Vec<_>>();

    let result = engine.borrow().create_pool(&name, &blockdevs, raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroy_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let result = engine.borrow().destroy_pool(&name);

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_pool_object_path(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_volume_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn get_dev_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn get_cache_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn get_list_items<T: HasCodes + Display>(m: &Message, items: &Iter<T>) -> MethodResult {

    let msg_vec = items.as_slice()
        .into_iter()
        .map(|item| {
            MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                     MessageItem::UInt16(item.get_error_int()),
                                     MessageItem::Str(format!("{}", item.get_error_string()))])
        })
        .collect::<Vec<MessageItem>>();

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn get_error_codes(m: &Message) -> MethodResult {
    get_list_items(m, &StratisErrorEnum::iterator())
}

fn get_raid_levels(m: &Message) -> MethodResult {
    get_list_items(m, &StratisRaidType::iterator())
}

fn get_dev_types(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| create_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroy_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| list_pools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| get_pool_object_path(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| get_volume_object_path(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method =
        f.method(GET_DEV_OBJECT_PATH, move |m, _, _| get_dev_object_path(m))
            .in_arg(("dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getcacheobjectpath_method = f.method(GET_CACHE_OBJECT_PATH,
                move |m, _, _| get_cache_object_path(m))
        .in_arg(("cache_dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| get_error_codes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| get_raid_levels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| get_dev_types(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<commit_msg>Simplify get_list_items a little<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::path::PathBuf;
use std::rc::Rc;
use std::slice::Iter;
use std::string::String;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;
use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn list_pools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    Ok(vec![m.method_return()])
}

fn create_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let blockdevs = devs.into_iter()
        .map(|x| PathBuf::from(x.inner::<&str>().unwrap()))
        .collect::<Vec<_>>();

    let result = engine.borrow().create_pool(&name, &blockdevs, raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroy_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let result = engine.borrow().destroy_pool(&name);

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_pool_object_path(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_volume_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn get_dev_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn get_cache_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn get_list_items<T: HasCodes + Display>(m: &Message, items: Iter<T>) -> MethodResult {

    let msg_vec = items
        .map(|item| {
            MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                     MessageItem::UInt16(item.get_error_int()),
                                     MessageItem::Str(format!("{}", item.get_error_string()))])
        })
        .collect::<Vec<MessageItem>>();

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn get_error_codes(m: &Message) -> MethodResult {
    get_list_items(m, StratisErrorEnum::iterator())
}

fn get_raid_levels(m: &Message) -> MethodResult {
    get_list_items(m, StratisRaidType::iterator())
}

fn get_dev_types(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| create_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroy_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| list_pools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| get_pool_object_path(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| get_volume_object_path(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method =
        f.method(GET_DEV_OBJECT_PATH, move |m, _, _| get_dev_object_path(m))
            .in_arg(("dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getcacheobjectpath_method = f.method(GET_CACHE_OBJECT_PATH,
                move |m, _, _| get_cache_object_path(m))
        .in_arg(("cache_dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| get_error_codes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| get_raid_levels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| get_dev_types(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<|endoftext|>


<commit_before>use std::collections::{
    HashMap,
    BinaryHeap,
};
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};

use std::hash::Hash;

use scored::MinScored;
use super::visit::{
    Visitable,
    VisitMap,
    IntoEdges,
    EdgeRef,
};
use algo::Measure;

/// [Generic] Dijkstra's shortest path algorithm.
///
/// Compute the length of the shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
pub fn dijkstra<G, F, K>(graph: G, start: G::NodeId, goal: Option<G::NodeId>,
                         mut edge_cost: F)
    -> HashMap<G::NodeId, K>
    where G: IntoEdges + Visitable,
          G::NodeId: Eq + Hash,
          K: Measure + Copy,
          F: FnMut(G::EdgeRef) -> K,
{
    let mut visited = graph.visit_map();
    let mut scores = HashMap::new();
    //let mut predecessor = HashMap::new();
    let mut visit_next = BinaryHeap::new();
    let zero_score = K::default();
    scores.insert(start.clone(), zero_score);
    visit_next.push(MinScored(zero_score, start));
    while let Some(MinScored(node_score, node)) = visit_next.pop() {
        if visited.is_visited(&node) {
            continue
        }
        if goal.as_ref() == Some(&node) {
            break
        }
        for edge in graph.edges(node.clone()) {
            let next = edge.target();
            if visited.is_visited(&next) {
                continue
            }
            let mut next_score = node_score + edge_cost(edge);
            match scores.entry(next.clone()) {
                Occupied(ent) => if next_score < *ent.get() {
                    *ent.into_mut() = next_score;
                    //predecessor.insert(next.clone(), node.clone());
                } else {
                    next_score = ent.get().clone();
                },
                Vacant(ent) => {
                    ent.insert(next_score);
                    //predecessor.insert(next.clone(), node.clone());
                }
            }
            visit_next.push(MinScored(next_score, next));
        }
        visited.visit(node);
    }
    scores
}
<commit_msg>Reorder typarms<commit_after>use std::collections::{
    HashMap,
    BinaryHeap,
};
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};

use std::hash::Hash;

use scored::MinScored;
use super::visit::{
    Visitable,
    VisitMap,
    IntoEdges,
    EdgeRef,
};
use algo::Measure;

/// [Generic] Dijkstra's shortest path algorithm.
///
/// Compute the length of the shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
pub fn dijkstra<G, F, K>(graph: G, start: G::NodeId, goal: Option<G::NodeId>,
                         mut edge_cost: F)
    -> HashMap<G::NodeId, K>
    where G: IntoEdges + Visitable,
          G::NodeId: Eq + Hash,
          F: FnMut(G::EdgeRef) -> K,
          K: Measure + Copy,
{
    let mut visited = graph.visit_map();
    let mut scores = HashMap::new();
    //let mut predecessor = HashMap::new();
    let mut visit_next = BinaryHeap::new();
    let zero_score = K::default();
    scores.insert(start.clone(), zero_score);
    visit_next.push(MinScored(zero_score, start));
    while let Some(MinScored(node_score, node)) = visit_next.pop() {
        if visited.is_visited(&node) {
            continue
        }
        if goal.as_ref() == Some(&node) {
            break
        }
        for edge in graph.edges(node.clone()) {
            let next = edge.target();
            if visited.is_visited(&next) {
                continue
            }
            let mut next_score = node_score + edge_cost(edge);
            match scores.entry(next.clone()) {
                Occupied(ent) => if next_score < *ent.get() {
                    *ent.into_mut() = next_score;
                    //predecessor.insert(next.clone(), node.clone());
                } else {
                    next_score = ent.get().clone();
                },
                Vacant(ent) => {
                    ent.insert(next_score);
                    //predecessor.insert(next.clone(), node.clone());
                }
            }
            visit_next.push(MinScored(next_score, next));
        }
        visited.visit(node);
    }
    scores
}
<|endoftext|>


<commit_before>use reqwest::{ self, header };
use std::fs::File;
use std::io::{ BufWriter, Read, Write };
use std::path::Path;

use config::Config;
use error::PackageError;

fn download_file<F>(url: &str, to_path: &Path, callback: F) -> Result<u64, PackageError>
    where F: Fn(u64, u64)
{
    // GET the URL, returning an error if necessary.
    let response = reqwest::get(url)?;

    // Try to retrieve the content length.
    let content_length =
        response
        .headers()
        .get::<header::ContentLength>()
        // If the Response contains no content-length, default to 0.
        .map_or(0u64, |x| {
            let header::ContentLength(len) = *x;
            len
        });

    // For every `buffer_size` bytes, call the callback once.
    let Config { buffer_size: buffer_size, .. } = Config::default();

    // `buffer_size` decides how frequent the function calls the callback by
    // checking whether (downloaded bytes) % `buffer_size` is 0.
    let buffer_size = buffer_size.unwrap_or(65536);

    // Obviously, the target file to be written to by the BufWriter.
    let mut target = BufWriter::new(File::create(to_path)?);

    for (index, byte) in response.bytes().enumerate() {
        // Write to the target, returns an error if necessary.
        target.write(&[byte?])?;

        // Checks whether it's time to call the callback, and call it if it is.
        // Plus one to `index` as `index` itself is zero-indexed.
        if index as u64 % buffer_size == 0 {
            callback((index + 1) as u64, content_length);
        };
    }

    // In case the callback never got a chance to be called due to the package
    // itself being too small.
    callback(content_length, content_length);

    Ok(content_length)
}<commit_msg>Make download_file public<commit_after>use reqwest::{ self, header };
use std::fs::File;
use std::io::{ BufWriter, Read, Write };
use std::path::Path;

use config::Config;
use error::PackageError;

pub fn download_file<F>(url: &str, to_path: &Path, callback: F) -> Result<u64, PackageError>
    where F: Fn(u64, u64)
{
    // GET the URL, returning an error if necessary.
    let response = reqwest::get(url)?;

    // Try to retrieve the content length.
    let content_length =
        response
        .headers()
        .get::<header::ContentLength>()
        // If the Response contains no content-length, default to 0.
        .map_or(0u64, |x| {
            let header::ContentLength(len) = *x;
            len
        });

    // For every `buffer_size` bytes, call the callback once.
    let Config { buffer_size: buffer_size, .. } = Config::default();

    // `buffer_size` decides how frequent the function calls the callback by
    // checking whether (downloaded bytes) % `buffer_size` is 0.
    let buffer_size = buffer_size.unwrap_or(65536);

    // Obviously, the target file to be written to by the BufWriter.
    let mut target = BufWriter::new(File::create(to_path)?);

    for (index, byte) in response.bytes().enumerate() {
        // Write to the target, returns an error if necessary.
        target.write(&[byte?])?;

        // Checks whether it's time to call the callback, and call it if it is.
        // Plus one to `index` as `index` itself is zero-indexed.
        if index as u64 % buffer_size == 0 {
            callback((index + 1) as u64, content_length);
        };
    }

    // In case the callback never got a chance to be called due to the package
    // itself being too small.
    callback(content_length, content_length);

    Ok(content_length)
}<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules)];

#[link(name = "ears",
       vers = "0.1",
       package_id = "github.com/JeremyLetang/ears",
       author = "letang.jeremy@gmail.com",
       uuid = "D0271EC6-5F27-4C72-BBEA-1341DC665F34",
       url = "https://github.com/JeremyLetang/ears")];

#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];

extern mod extra;

// Reexport public API
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<commit_msg>reexport ears<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules)];

#[link(name = "ears",
       vers = "0.1",
       package_id = "github.com/JeremyLetang/ears",
       author = "letang.jeremy@gmail.com",
       uuid = "D0271EC6-5F27-4C72-BBEA-1341DC665F34",
       url = "https://github.com/JeremyLetang/ears")];

#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];

extern mod extra;

// Reexport public API
pub use init::ears_init;
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<|endoftext|>


<commit_before>/*
* Kinds are types of type.
*
* Every type has a kind. Every type parameter has a set of kind-capabilities
* saying which kind of type may be passed as the parameter.
*
* The kinds are based on two capabilities: copy and send. These may each be
* present or absent, though only three of the four combinations can actually
* occur:
*
*
*
*    MOVE +   SEND  =  "Unique": no shared substructures or pins, only
*                                interiors and ~ boxes.
*
*    MOVE + NOSEND  =  "Shared": structures containing @, fixed to the local
*                                task heap/pool; or ~ structures pointing to
*                                pinned values.
*
*  NOMOVE + NOSEND  =  "Pinned": structures directly containing resources, or
*                                by-alias closures as interior or
*                                uniquely-boxed members.
*
*  NOMOVE +   SEND  =  --      : no types are like this.
*
*
* Since this forms a lattice, we denote the capabilites in terms of a
* worst-case requirement.  That is, if your function needs to move-and-send
* (or copy) your T, you write fn<~T>(...). If you need to copy but not send,
* you write fn<@T>(...). And if you need neither -- can work with any sort of
* pinned data at all -- then you write fn<T>(...).
*
*
* Most types are unique or shared. Other possible name combinations for these
* two: (tree, graph; pruned, pooled; message, local; owned, common) are
* plausible but nothing stands out as completely pithy-and-obvious.
*
* Resources cannot be copied or sent; they're pinned. They can't be copied
* because it would interfere with destruction (multiple destruction?) They
* cannot be sent because we don't want to oblige the communication system to
* run destructors in some weird limbo context of messages-in-transit. It
* should always be ok to just free messages it's dropping.
*
* Note that obj~ and fn~ -- those that capture a unique environment -- can be
* sent, so satisfy ~T. So can plain obj and fn.
*
*
* Further notes on copying and moving; sending is accomplished by calling a
* move-in operator on something constrained to a unique type ~T.
*
*
* COPYING:
* --------
*
*   A copy is made any time you pass-by-value or execute the = operator in a
*   non-init expression.
*
*   @ copies shallow, is always legal
*   ~ copies deep, is only legal if pointee is unique.
*     pinned values (pinned resources, alias-closures) can't be copied
*     all other unique (eg. interior) values copy shallow
*
*   Note this means that only type parameters constrained to ~T can be copied.
*
* MOVING:
* -------
*
*  A move is made any time you pass-by-move (that is, with 'move' mode) or
*  execute the <- operator.
*
*/

import syntax::ast;
import syntax::visit;

import ast::kind;
import ast::kind_unique;
import ast::kind_shared;
import ast::kind_pinned;

fn kind_lteq(a: kind, b: kind) -> bool {
    alt a {
      kind_pinned. { true }
      kind_shared. { b != kind_pinned }
      kind_unique. { b == kind_unique }
    }
}

fn lower_kind(a: kind, b: kind) -> kind {
    if kind_lteq(a, b) { a } else { b }
}

fn kind_to_str(k: kind) -> str {
    alt k {
      ast::kind_pinned. { "pinned" }
      ast::kind_unique. { "unique" }
      ast::kind_shared. { "shared" }
    }
}

fn type_and_kind(tcx: &ty::ctxt, e: &@ast::expr)
    -> {ty: ty::t, kind: ast::kind} {
    let t = ty::expr_ty(tcx, e);
    let k = ty::type_kind(tcx, t);
    {ty: t, kind: k}
}

fn need_expr_kind(tcx: &ty::ctxt, e: &@ast::expr,
                  k_need: ast::kind, descr: &str) {
    let tk = type_and_kind(tcx, e);
    log #fmt("for %s: want %s type, got %s type %s",
             descr,
             kind_to_str(k_need),
             kind_to_str(tk.kind),
             util::ppaux::ty_to_str(tcx, tk.ty));

    if ! kind_lteq(k_need, tk.kind) {
        let s =
            #fmt("mismatched kinds for %s: needed %s type, got %s type %s",
                 descr,
                 kind_to_str(k_need),
                 kind_to_str(tk.kind),
                 util::ppaux::ty_to_str(tcx, tk.ty));
        tcx.sess.span_err(e.span, s);
    }
}

fn need_shared_lhs_rhs(tcx: &ty::ctxt,
                       a: &@ast::expr, b: &@ast::expr,
                       op: &str) {
    need_expr_kind(tcx, a, ast::kind_shared, op + " lhs");
    need_expr_kind(tcx, b, ast::kind_shared, op + " rhs");
}

fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) {
    alt e.node {
      ast::expr_move(a, b) { need_shared_lhs_rhs(tcx, a, b, "<-"); }
      ast::expr_assign(a, b) { need_shared_lhs_rhs(tcx, a, b, "="); }
      ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); }
      _ { }
    }
}

fn check_crate(tcx: &ty::ctxt, crate: &@ast::crate) {
    let visit = visit::mk_simple_visitor
        (@{visit_expr: bind check_expr(tcx, _)
           with *visit::default_simple_visitor()});
    visit::visit_crate(*crate, (), visit);
    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Fix stale 'copy' occurrences to 'move' in comments.<commit_after>/*
* Kinds are types of type.
*
* Every type has a kind. Every type parameter has a set of kind-capabilities
* saying which kind of type may be passed as the parameter.
*
* The kinds are based on two capabilities: move and send. These may each be
* present or absent, though only three of the four combinations can actually
* occur:
*
*
*
*    MOVE +   SEND  =  "Unique": no shared substructures or pins, only
*                                interiors and ~ boxes.
*
*    MOVE + NOSEND  =  "Shared": structures containing @, fixed to the local
*                                task heap/pool; or ~ structures pointing to
*                                pinned values.
*
*  NOMOVE + NOSEND  =  "Pinned": structures directly containing resources, or
*                                by-alias closures as interior or
*                                uniquely-boxed members.
*
*  NOMOVE +   SEND  =  --      : no types are like this.
*
*
* Since this forms a lattice, we denote the capabilites in terms of a
* worst-case requirement.  That is, if your function needs to move-and-send
* (or copy) your T, you write fn<~T>(...). If you need to move but not send,
* you write fn<@T>(...). And if you need neither -- can work with any sort of
* pinned data at all -- then you write fn<T>(...).
*
*
* Most types are unique or shared. Other possible name combinations for these
* two: (tree, graph; pruned, pooled; message, local; owned, common) are
* plausible but nothing stands out as completely pithy-and-obvious.
*
* Resources cannot be copied or sent; they're pinned. They can't be copied
* because it would interfere with destruction (multiple destruction?) They
* cannot be sent because we don't want to oblige the communication system to
* run destructors in some weird limbo context of messages-in-transit. It
* should always be ok to just free messages it's dropping.
*
* Note that obj~ and fn~ -- those that capture a unique environment -- can be
* sent, so satisfy ~T. So can plain obj and fn.
*
*
* Further notes on copying and moving; sending is accomplished by calling a
* move-in operator on something constrained to a unique type ~T.
*
*
* COPYING:
* --------
*
*   A copy is made any time you pass-by-value or execute the = operator in a
*   non-init expression.
*
*   @ copies shallow, is always legal
*   ~ copies deep, is only legal if pointee is unique.
*     pinned values (pinned resources, alias-closures) can't be copied
*     all other unique (eg. interior) values copy shallow
*
*   Note this means that only type parameters constrained to ~T can be copied.
*
* MOVING:
* -------
*
*  A move is made any time you pass-by-move (that is, with 'move' mode) or
*  execute the <- operator.
*
*/

import syntax::ast;
import syntax::visit;

import ast::kind;
import ast::kind_unique;
import ast::kind_shared;
import ast::kind_pinned;

fn kind_lteq(a: kind, b: kind) -> bool {
    alt a {
      kind_pinned. { true }
      kind_shared. { b != kind_pinned }
      kind_unique. { b == kind_unique }
    }
}

fn lower_kind(a: kind, b: kind) -> kind {
    if kind_lteq(a, b) { a } else { b }
}

fn kind_to_str(k: kind) -> str {
    alt k {
      ast::kind_pinned. { "pinned" }
      ast::kind_unique. { "unique" }
      ast::kind_shared. { "shared" }
    }
}

fn type_and_kind(tcx: &ty::ctxt, e: &@ast::expr)
    -> {ty: ty::t, kind: ast::kind} {
    let t = ty::expr_ty(tcx, e);
    let k = ty::type_kind(tcx, t);
    {ty: t, kind: k}
}

fn need_expr_kind(tcx: &ty::ctxt, e: &@ast::expr,
                  k_need: ast::kind, descr: &str) {
    let tk = type_and_kind(tcx, e);
    log #fmt("for %s: want %s type, got %s type %s",
             descr,
             kind_to_str(k_need),
             kind_to_str(tk.kind),
             util::ppaux::ty_to_str(tcx, tk.ty));

    if ! kind_lteq(k_need, tk.kind) {
        let s =
            #fmt("mismatched kinds for %s: needed %s type, got %s type %s",
                 descr,
                 kind_to_str(k_need),
                 kind_to_str(tk.kind),
                 util::ppaux::ty_to_str(tcx, tk.ty));
        tcx.sess.span_err(e.span, s);
    }
}

fn need_shared_lhs_rhs(tcx: &ty::ctxt,
                       a: &@ast::expr, b: &@ast::expr,
                       op: &str) {
    need_expr_kind(tcx, a, ast::kind_shared, op + " lhs");
    need_expr_kind(tcx, b, ast::kind_shared, op + " rhs");
}

fn check_expr(tcx: &ty::ctxt, e: &@ast::expr) {
    alt e.node {
      ast::expr_move(a, b) { need_shared_lhs_rhs(tcx, a, b, "<-"); }
      ast::expr_assign(a, b) { need_shared_lhs_rhs(tcx, a, b, "="); }
      ast::expr_swap(a, b) { need_shared_lhs_rhs(tcx, a, b, "<->"); }
      _ { }
    }
}

fn check_crate(tcx: &ty::ctxt, crate: &@ast::crate) {
    let visit = visit::mk_simple_visitor
        (@{visit_expr: bind check_expr(tcx, _)
           with *visit::default_simple_visitor()});
    visit::visit_crate(*crate, (), visit);
    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::path::Path;

pub fn flags<P>(path: P) -> std::io::Result<u32> where
    P: AsRef<Path>
{
    let file = std::fs::File::open(path)?;

    let mut flags = 0;
    let code = unsafe {
        use std::os::unix::io::AsRawFd as _;
        ioctls::fs_ioc_getflags(file.as_raw_fd(), &mut flags)
    };

    if code == 0 {
        Ok(flags as u32)
    } else {
        Err(std::io::Error::from_raw_os_error(code))
    }
}
<commit_msg>Write tests for the flag collection utility.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::path::Path;

pub fn flags<P>(path: P) -> std::io::Result<u32> where
    P: AsRef<Path>
{
    let file = std::fs::File::open(path)?;

    let mut flags = 0;
    let code = unsafe {
        use std::os::unix::io::AsRawFd as _;
        ioctls::fs_ioc_getflags(file.as_raw_fd(), &mut flags)
    };

    if code == 0 {
        Ok(flags as u32)
    } else {
        Err(std::io::Error::from_raw_os_error(code))
    }
}

#[cfg(test)]
mod tests {

    use std::fs::File;

    use super::*;

    #[test]
    fn test_flags_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(flags(tempdir.path().join("foo")).is_err());
    }

    #[test]
    fn test_flags_noatime() {
        // https://elixir.bootlin.com/linux/v5.8.14/source/include/uapi/linux/fs.h#L245
        const FS_NOATIME_FL: std::os::raw::c_long = 0x00000080;

        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = File::create(tempdir.path().join("foo")).unwrap();

        unsafe {
            use std::os::unix::io::AsRawFd as _;
            let fd = tempfile.as_raw_fd();

            assert_eq!(ioctls::fs_ioc_setflags(fd, &FS_NOATIME_FL), 0);
        }

        let flags = flags(tempdir.path().join("foo")).unwrap();
        assert_eq!(flags & FS_NOATIME_FL as u32, FS_NOATIME_FL as u32);
    }
}
<|endoftext|>