<commit_before>
enum Order {
  Ascending,
  Descending,
  Ignore
}

enum Type<'a> {
  Null,
  Boolean,
  Int,
  Long,
  Float,
  Double,
  Bytes,
  String,
  Record(Record<'a>),
  Enum(Enum<'a>),
  Array(Array<'a>),
  Map(Map<'a>),
  Union(&'a[Box<Type<'a>>]),
  Fixed(Fixed<'a>)
}

struct Field<'a> {
  name: &'static str,
  doc: Option<String>,
  av_type: Type<'a>,
  default: &'static str,
  order: Option<Order>
}

struct Record<'a> {
    name: &'static str,
    namespace: Option<String>,
    doc: Option<String>,
    aliases: Option<&'a[String]>,
    fields: &'a[Field<'a>]
}

struct Enum<'a> {
    name: &'static str,
    namespace: Option<String>,
    doc: Option<String>,
    aliases: Option<&'a[String]>,
    symbols: &'a[String]
}

struct Array<'a> {
  items: Box<Type<'a>>
}

struct Map<'a> {
  values: &'a[String]
}

struct Fixed<'a> {
  name: &'static str,
  namespace: Option<String>,
  aliases: Option<&'a[String]>,
  size: i32
}

#[test]
#[should_panic]
fn it_works() {
  let arr: Array = Array {
    items: Box::new(Type::Null)
  };
  let field: Field = Field {
    name: "null_array",
    doc: None,
    av_type: Type::Array(arr),
    default: "null",
    order: Some(Order::Ascending)
  };
  let record: Record = Record {
    name: "record",
    namespace: None,
    doc: None,
    aliases: None,
    fields: &[field]
  };
  println!("hello world");
  assert!(false)
}
<commit_msg>basic trait<commit_after>
enum Order {
  Ascending,
  Descending,
  Ignore
}

enum Type<'a> {
  Null,
  Boolean,
  Int,
  Long,
  Float,
  Double,
  Bytes,
  String,
  Record(Record<'a>),
  Enum(Enum<'a>),
  Array(Array<'a>),
  Map(Map<'a>),
  Union(&'a[Box<Type<'a>>]),
  Fixed(Fixed<'a>)
}

struct Field<'a> {
  name: &'static str,
  doc: Option<String>,
  av_type: Type<'a>,
  default: &'static str,
  order: Option<Order>
}

struct Record<'a> {
    name: &'static str,
    namespace: Option<String>,
    doc: Option<String>,
    aliases: Option<&'a[String]>,
    fields: &'a[Field<'a>]
}

struct Enum<'a> {
    name: &'static str,
    namespace: Option<String>,
    doc: Option<String>,
    aliases: Option<&'a[String]>,
    symbols: &'a[String]
}

struct Array<'a> {
  items: Box<Type<'a>>
}

struct Map<'a> {
  values: &'a[String]
}

struct Fixed<'a> {
  name: &'static str,
  namespace: Option<String>,
  aliases: Option<&'a[String]>,
  size: i32
}

trait Valid {
  fn valid(&self) -> bool;
}

#[test]
#[should_panic]
fn it_works() {
  let arr: Array = Array {
    items: Box::new(Type::Null)
  };
  let field: Field = Field {
    name: "null_array",
    doc: None,
    av_type: Type::Array(arr),
    default: "null",
    order: Some(Order::Ascending)
  };
  let record: Record = Record {
    name: "record",
    namespace: None,
    doc: None,
    aliases: None,
    fields: &[field]
  };
  println!("hello world");
  assert!(false)
}
<|endoftext|>


<commit_before>extern crate flate2;
extern crate regex;
extern crate tar;
extern crate time;
#[macro_use]
extern crate try_opt;

mod macros;
mod time_utils;
pub mod backend;
pub mod collections;
pub mod signatures;
<commit_msg>Use clippy plugin only on nightly<commit_after>#![cfg_attr(unstable, feature(plugin))]
#![cfg_attr(unstable, plugin(clippy))]

extern crate flate2;
extern crate regex;
extern crate tar;
extern crate time;
#[macro_use]
extern crate try_opt;

mod macros;
mod time_utils;
pub mod backend;
pub mod collections;
pub mod signatures;
<|endoftext|>


<commit_before>//! A wrapper around the uchardet library. Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! ```
//! use uchardet::detect_encoding_name;
//!
//! assert_eq!("ISO-8859-1".to_string(),
//!            detect_encoding_name(&[0x46, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
//!                0x69, 0x73, 0xe9]).unwrap());
//! ```
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

// Increase the compiler's recursion limit for the `error_chain` crate.
#![recursion_limit = "1024"]
#![deny(missing_docs)]

#[macro_use]
extern crate error_chain;
extern crate libc;
extern crate uchardet_sys as ffi;

use libc::size_t;
use std::ffi::CStr;
use std::str::from_utf8;

use errors::*;

mod errors {
    error_chain! {
        errors {
            UnrecognizableCharset {
                description("unrecognizable charset")
                display("uchardet was unable to recognize a charset")
            }
            DataHandlingError {
                description("data handling error")
                display("uchardet failed to handle the supplied data (out of memory?)")
            }
        }
    }
}

/// Detects the encoding of text using the uchardet library.
///
/// EXPERIMENTAL: This may be replaced by a better API soon.
struct EncodingDetector {
    ptr: ffi::uchardet_t
}

/// Return the name of the charset used in `data` or an error if uchardet
/// was unable to detect a charset.
///
/// ```
/// use uchardet::detect_encoding_name;
///
/// assert_eq!("ASCII".to_string(),
///            detect_encoding_name("ascii".as_bytes()).unwrap());
/// assert_eq!("UTF-8".to_string(),
///            detect_encoding_name("©français".as_bytes()).unwrap());
/// assert_eq!("ISO-8859-1".to_string(),
///            detect_encoding_name(&[0x46, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
///                0x69, 0x73, 0xe9]).unwrap());
/// ```
pub fn detect_encoding_name(data: &[u8]) -> Result<String> {
    let mut detector = EncodingDetector::new();
    try!(detector.handle_data(data));
    detector.data_end();
    detector.charset()
}

impl EncodingDetector {
    /// Create a new EncodingDetector.
    fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(!ptr.is_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector. This is a no-op if a
    /// charset has been detected.
    fn handle_data(&mut self, data: &[u8]) -> Result<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                Err(ErrorKind::DataHandlingError.into())
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding. This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain. From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    // fn reset(&mut self) {
    //    unsafe { ffi::uchardet_reset(self.ptr); }
    // }

    /// Get the decoder's current best guess as to the encoding. May return
    /// an error if uchardet was unable to detect an encoding
    fn charset(&self) -> Result<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(!internal_str.is_null());
            let bytes = CStr::from_ptr(internal_str).to_bytes();
            let charset = from_utf8(bytes);
            match charset {
                Err(_) =>
                    panic!("uchardet_get_charset returned invalid value"),
                Ok("") => Err(ErrorKind::UnrecognizableCharset.into()),
                Ok(encoding) => Ok(encoding.to_string())
            }
        }
    }
}

impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<commit_msg>Address remarks<commit_after>//! A wrapper around the uchardet library. Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! ```
//! use uchardet::detect_encoding_name;
//!
//! assert_eq!("WINDOWS-1252",
//!            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
//!                0x69, 0x73, 0xe9, 0x94]).unwrap());
//! ```
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

// Increase the compiler's recursion limit for the `error_chain` crate.
#![recursion_limit = "1024"]
#![deny(missing_docs)]

#[macro_use]
extern crate error_chain;
extern crate libc;
extern crate uchardet_sys as ffi;

use libc::size_t;
use std::ffi::CStr;
use std::str::from_utf8;

pub use errors::*;

#[allow(missing_docs)]
mod errors {
    error_chain! {
        errors {
            UnrecognizableCharset {
                description("unrecognizable charset")
                display("uchardet was unable to recognize a charset")
            }
            DataHandlingError {
                description("data handling error")
                display("uchardet failed to handle the supplied data (out of memory?)")
            }
        }
    }
}

/// Detects the encoding of text using the uchardet library.
///
/// EXPERIMENTAL: This may be replaced by a better API soon.
struct EncodingDetector {
    ptr: ffi::uchardet_t
}

/// Return the name of the charset used in `data` or an error if uchardet
/// was unable to detect a charset.
///
/// ```
/// use uchardet::detect_encoding_name;
///
/// assert_eq!("ASCII",
///            detect_encoding_name("ascii".as_bytes()).unwrap());
/// assert_eq!("UTF-8",
///            detect_encoding_name("©français".as_bytes()).unwrap());
/// assert_eq!("WINDOWS-1252",
///            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
///                0x69, 0x73, 0xe9, 0x94]).unwrap());
/// ```
pub fn detect_encoding_name(data: &[u8]) -> Result<String> {
    let mut detector = EncodingDetector::new();
    try!(detector.handle_data(data));
    detector.data_end();
    detector.charset()
}

impl EncodingDetector {
    /// Create a new EncodingDetector.
    fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(!ptr.is_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector. This is a no-op if a
    /// charset has been detected.
    fn handle_data(&mut self, data: &[u8]) -> Result<()> {
        let result = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                Err(ErrorKind::DataHandlingError.into())
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding. This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain. From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    // fn reset(&mut self) {
    //    unsafe { ffi::uchardet_reset(self.ptr); }
    // }

    /// Get the decoder's current best guess as to the encoding. May return
    /// an error if uchardet was unable to detect an encoding.
    fn charset(&self) -> Result<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(!internal_str.is_null());
            let bytes = CStr::from_ptr(internal_str).to_bytes();
            let charset = from_utf8(bytes);
            match charset {
                Err(_) =>
                    panic!("uchardet_get_charset returned a charset name \
                            containing invalid characters"),
                Ok("") => Err(ErrorKind::UnrecognizableCharset.into()),
                Ok(encoding) => Ok(encoding.to_string())
            }
        }
    }
}

impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use std::collections::HashMap;
use std::str::FromStr;
pub use chrono::NaiveDate as Date;

#[derive(Debug, Eq, PartialEq)]
pub enum Recurrence {
    Daily(bool, u16),
    BDaily(bool, u16),
    Monthly(bool, u16),
    Weekly(bool, u16),
    Yearly(bool, u16),
}

impl FromStr for Recurrence {
    type Err = ();
    fn from_str(s: &str) -> Result<Recurrence, ()> {
        use self::Recurrence::*;

        let hard = s.starts_with("+");

        s[hard as usize..s.len() - 1].parse::<u16>().map_err(|_| ()).and_then(|num| {
            Ok(match &s[s.len() - 1..] {
                "d" => Daily(hard, num),
                "b" => BDaily(hard, num),
                "m" => Monthly(hard, num),
                "w" => Weekly(hard, num),
                "y" => Yearly(hard, num),
                _ => return Err(()),
            })
        })
    }
}

#[derive(Debug, Eq, PartialEq, Default)]
pub struct Task {
    pub line: String,
    pub subject: String,
    pub priority: u8,
    pub create_date: Option<Date>,
    pub finish_date: Option<Date>,
    pub finished: bool,
    pub threshold_date: Option<Date>,
    pub due_date: Option<Date>,
    pub recurrence: Option<Recurrence>,
    pub contexts: Vec<String>,
    pub projects: Vec<String>,
    pub hashtags: Vec<String>,
    pub tags: HashMap<String, String>,
}

impl FromStr for Task {
    type Err = ();
    fn from_str(mut s: &str) -> Result<Task, ()> {
        let line = s.to_owned();

        // parse finish state
        let (finished, mut finish_date) = if s.starts_with("x ") {
            s = &s[2..];
            (true, s[..10].parse::<Date>().ok())
        } else {
            (false, None)
        };

        if finish_date.is_some() {
            s = &s[11..];
        }

        // parse priority
        let priority = if s.starts_with("(") && &s[2..4] == ") " {
            match s.as_bytes()[1] {
                p @ b'A'...b'Z' => {
                    s = &s[4..];
                    p - b'A'
                }
                _ => 26,
            }
        } else {
            26
        };

        // parse creation date
        let mut create_date = match s[..10].parse::<Date>() {
            Ok(date) => {
                s = &s[11..];
                Some(date)
            }
            Err(_) => None,
        };

        // If creation date follows finished mark, it can be parsed as a finish date,
        // which is wrong. Note finish state part and creation date can be separated
        // by priority, so this confusion is possible only if no priority given.
        if priority == 26 && finish_date.is_some() && create_date.is_none() {
            create_date = finish_date;
            finish_date = None;
        }

        // Subject is the line with headers removed (priority, creation date and finish state).
        let subject = s.to_owned();

        // FSM to parse line for tags, contexts and projects.

        #[derive(Copy, Clone, Eq, PartialEq)]
        enum St {
            Init,
            Ctx(usize),
            Prj(usize),
            Hash(usize),
            Tag0(usize),
            Tag1(usize, usize),
        }
        let mut state = St::Init;
        let mut contexts = Vec::new();
        let mut projects = Vec::new();
        let mut hashtags = Vec::new();
        let mut tags = HashMap::new();

        // Some known tags: threshold date (`t:`), due date (`due:`) and recurrence (`rec:`).
        let mut threshold_date = None;
        let mut due_date = None;
        let mut recurrence = None;

        for (i, c) in s.bytes().enumerate() {
            state = match (c, state) {
                (b'@', St::Init) => St::Ctx(i),
                (b'+', St::Init) => St::Prj(i),
                (b'#', St::Init) => St::Hash(i),
                (b'a'...b'z', St::Init) => St::Tag0(i),
                (b':', St::Tag0(j)) => St::Tag1(j, i),
                (b' ', St::Ctx(j)) => {
                    contexts.push(s[j + 1..i].to_owned());
                    St::Init
                }
                (b' ', St::Prj(j)) => {
                    projects.push(s[j + 1..i].to_owned());
                    St::Init
                }
                (b' ', St::Hash(j)) => {
                    hashtags.push(s[j + 1..i].to_owned());
                    St::Init
                }
                (b' ', St::Tag1(j, k)) => {
                    match &s[j..k] {
                        "rec" => {
                            recurrence = s[k + 1..i].parse::<Recurrence>().ok();
                        }
                        "due" => {
                            due_date = s[k + 1..i].parse::<Date>().ok();
                        }
                        "t" => {
                            threshold_date = s[k + 1..i].parse::<Date>().ok();
                        }
                        tag => {
                            tags.insert(tag.to_owned(), s[k + 1..i].to_owned());
                        }
                    }
                    St::Init
                }
                _ => state,
            };
        }

        // Check final state, so tags at the end of line are also parsed.
        match state {
            St::Tag1(j, k) => {
                tags.insert(s[j..k].to_owned(), s[k + 1..].to_owned());
            }
            St::Prj(j) => {
                projects.push(s[j + 1..].to_owned());
            }
            St::Ctx(j) => {
                contexts.push(s[j + 1..].to_owned());
            }
            St::Hash(j) => {
                hashtags.push(s[j + 1..].to_owned());
            }
            _ => (),
        }

        Ok(Task {
            line: line,
            subject: subject,
            priority: priority,
            create_date: create_date,
            finish_date: finish_date,
            finished: finished,
            threshold_date: threshold_date,
            due_date: due_date,
            recurrence: recurrence,
            contexts: contexts,
            projects: projects,
            hashtags: hashtags,
            tags: tags,
        })
    }
}

#[cfg(test)]
mod test {
    use super::{Date, Recurrence, Task};

    #[test]
    fn it_works() {
        let todo_item = "(A) 2016-03-24 22:00 сходить на занятие в @microfon rec:+1w \
                         due:2016-04-05 t:2016-04-05 at:20:00";
        assert_eq!(todo_item.parse::<Task>(),
                   Ok(Task {
                       line: todo_item.to_owned(),
                       subject: todo_item[15..].to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 24)),
                       priority: 0,
                       recurrence: Some(Recurrence::Weekly(true, 1)),
                       due_date: Some(Date::from_ymd(2016, 4, 5)),
                       threshold_date: Some(Date::from_ymd(2016, 4, 5)),
                       contexts: vec!["microfon".to_owned()],
                       tags: vec![("at".to_owned(), "20:00".to_owned())].into_iter().collect(),
                       ..Task::default()
                   }));

        let todo_item = "2016-03-27 сменить загранпаспорт due:2020-08-14 t:2020-04-14 +документы";
        assert_eq!(todo_item.parse::<Task>(),
                   Ok(Task {
                       line: todo_item.to_owned(),
                       subject: todo_item[11..].to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 27)),
                       priority: 26,
                       due_date: Some(Date::from_ymd(2020, 8, 14)),
                       threshold_date: Some(Date::from_ymd(2020, 4, 14)),
                       projects: vec!["документы".to_owned()],
                       ..Task::default()
                   }));

        let todo_item = "x 2016-03-27 сменить загранпаспорт due:2020-08-14 t:2020-04-14 +документы";
        assert_eq!(todo_item.parse::<Task>(),
                   Ok(Task {
                       line: todo_item.to_owned(),
                       subject: todo_item[13..].to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 27)),
                       priority: 26,
                       due_date: Some(Date::from_ymd(2020, 8, 14)),
                       threshold_date: Some(Date::from_ymd(2020, 4, 14)),
                       projects: vec!["документы".to_owned()],
                       finished: true,
                       ..Task::default()
                   }));
    }
}
<commit_msg>cleaner subject, no empty tags<commit_after>extern crate chrono;

use std::collections::HashMap;
use std::str::FromStr;
pub use chrono::NaiveDate as Date;

#[derive(Debug, Eq, PartialEq)]
pub enum Recurrence {
    Daily(bool, u16),
    BDaily(bool, u16),
    Monthly(bool, u16),
    Weekly(bool, u16),
    Yearly(bool, u16),
}

impl FromStr for Recurrence {
    type Err = ();
    fn from_str(s: &str) -> Result<Recurrence, ()> {
        use self::Recurrence::*;

        let hard = s.starts_with("+");

        s[hard as usize..s.len() - 1].parse::<u16>().map_err(|_| ()).and_then(|num| {
            Ok(match &s[s.len() - 1..] {
                "d" => Daily(hard, num),
                "b" => BDaily(hard, num),
                "m" => Monthly(hard, num),
                "w" => Weekly(hard, num),
                "y" => Yearly(hard, num),
                _ => return Err(()),
            })
        })
    }
}

#[derive(Debug, Eq, PartialEq, Default)]
pub struct Task {
    pub line: String,
    pub subject: String,
    pub priority: u8,
    pub create_date: Option<Date>,
    pub finish_date: Option<Date>,
    pub finished: bool,
    pub threshold_date: Option<Date>,
    pub due_date: Option<Date>,
    pub recurrence: Option<Recurrence>,
    pub contexts: Vec<String>,
    pub projects: Vec<String>,
    pub hashtags: Vec<String>,
    pub tags: HashMap<String, String>,
}

impl FromStr for Task {
    type Err = ();
    fn from_str(mut s: &str) -> Result<Task, ()> {
        let line = s.to_owned();

        // parse finish state
        let (finished, mut finish_date) = if s.starts_with("x ") {
            s = &s[2..];
            (true, s[..10].parse::<Date>().ok())
        } else {
            (false, None)
        };

        if finish_date.is_some() {
            s = &s[11..];
        }

        // parse priority
        let priority = if s.starts_with("(") && &s[2..4] == ") " {
            match s.as_bytes()[1] {
                p @ b'A'...b'Z' => {
                    s = &s[4..];
                    p - b'A'
                }
                _ => 26,
            }
        } else {
            26
        };

        // parse creation date
        let mut create_date = match s[..10].parse::<Date>() {
            Ok(date) => {
                s = &s[11..];
                Some(date)
            }
            Err(_) => None,
        };

        // If creation date follows finished mark, it can be parsed as a finish date,
        // which is wrong. Note finish state part and creation date can be separated
        // by priority, so this confusion is possible only if no priority given.
        if priority == 26 && finish_date.is_some() && create_date.is_none() {
            create_date = finish_date;
            finish_date = None;
        }

        let buf = s;

        // Subject is the line with technical info removed (priority, creation date and finish state, tags).
        let mut subject = Vec::new();

        // FSM to parse line for tags, contexts and projects.

        #[derive(Copy, Clone, Eq, PartialEq)]
        enum St {
            Init,
            Ctx(usize),
            Prj(usize),
            Hash(usize),
            Tag0(usize),
            Tag1(usize, usize),
        }
        let mut state = St::Init;
        let mut contexts = Vec::new();
        let mut projects = Vec::new();
        let mut hashtags = Vec::new();
        let mut tags = HashMap::new();

        // Some known tags: threshold date (`t:`), due date (`due:`) and recurrence (`rec:`).
        let mut threshold_date = None;
        let mut due_date = None;
        let mut recurrence = None;

        for (i, c) in buf.bytes().enumerate() {
            let new_state = match (c, state) {
                (b'@', St::Init) => St::Ctx(i),
                (b'+', St::Init) => St::Prj(i),
                (b'#', St::Init) => St::Hash(i),
                (b'a'...b'z', St::Init) => St::Tag0(i),
                (b':', St::Tag0(j)) => St::Tag1(j, i),
                (b' ', St::Tag0(_)) => St::Init,
                (b' ', St::Ctx(j)) => {
                    if i - j > 1 {
                        contexts.push(buf[j + 1..i].to_owned());
                    }
                    St::Init
                }
                (b' ', St::Prj(j)) => {
                    if i - j > 1 {
                        projects.push(buf[j + 1..i].to_owned());
                    }
                    St::Init
                }
                (b' ', St::Hash(j)) => {
                    if i - j > 1 {
                        hashtags.push(buf[j + 1..i].to_owned());
                    }
                    St::Init
                }
                (b' ', St::Tag1(j, k)) => {
                    if i - k > 1 {
                        match &buf[j..k] {
                            "rec" => {
                                recurrence = buf[k + 1..i].parse::<Recurrence>().ok();
                            }
                            "due" => {
                                due_date = buf[k + 1..i].parse::<Date>().ok();
                            }
                            "t" => {
                                threshold_date = buf[k + 1..i].parse::<Date>().ok();
                            }
                            tag => {
                                tags.insert(tag.to_owned(), buf[k + 1..i].to_owned());
                            }
                        }
                    }
                    St::Init
                }
                _ => state,
            };

            if new_state == St::Init {
                match state {
                    St::Tag0(j) | St::Hash(j) | St::Prj(j) | St::Ctx(j) => {
                        subject.extend(&buf.as_bytes()[j..i]);
                    }
                    St::Init => subject.push(buf.as_bytes()[i]),
                    _ => {}
                }
            }

            state = new_state;
        }

        // Check final state, so tags at the end of line are also parsed.
        match state {
            St::Tag1(j, k) => {
                tags.insert(buf[j..k].to_owned(), buf[k + 1..].to_owned());
            }
            St::Prj(j) => {
                projects.push(buf[j + 1..].to_owned());
                subject.extend(&buf.as_bytes()[j..]);
            }
            St::Ctx(j) => {
                contexts.push(buf[j + 1..].to_owned());
                subject.extend(&buf.as_bytes()[j..]);
            }
            St::Hash(j) => {
                hashtags.push(buf[j + 1..].to_owned());
                subject.extend(&buf.as_bytes()[j..]);
            }
            St::Tag0(j) => {
                subject.extend(&buf.as_bytes()[j..]);
            }
            _ => {}
        }

        let subject = String::from_utf8(subject).unwrap_or_else(|_| s.to_owned());

        Ok(Task {
            line: line,
            subject: subject,
            priority: priority,
            create_date: create_date,
            finish_date: finish_date,
            finished: finished,
            threshold_date: threshold_date,
            due_date: due_date,
            recurrence: recurrence,
            contexts: contexts,
            projects: projects,
            hashtags: hashtags,
            tags: tags,
        })
    }
}

#[cfg(test)]
mod test {
    use super::{Date, Recurrence, Task};

    #[test]
    fn it_works() {
        let todo_item = "(A) 2016-03-24 22:00 сходить на занятие в @microfon rec:+1w \
                         due:2016-04-05 t:2016-04-05 at:20:00";
        let task = todo_item.parse::<Task>().unwrap();
        println!("subj: {}", task.subject);
        assert_eq!(task,
                   Task {
                       line: todo_item.to_owned(),
                       subject: "22:00 сходить на занятие в @microfon".to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 24)),
                       priority: 0,
                       recurrence: Some(Recurrence::Weekly(true, 1)),
                       due_date: Some(Date::from_ymd(2016, 4, 5)),
                       threshold_date: Some(Date::from_ymd(2016, 4, 5)),
                       contexts: vec!["microfon".to_owned()],
                       tags: vec![("at".to_owned(), "20:00".to_owned())].into_iter().collect(),
                       ..Task::default()
                   });

        let todo_item = "2016-03-27 сменить загранпаспорт due:2020-08-14 t:2020-04-14 +документы";
        let task = todo_item.parse::<Task>().unwrap();
        println!("subj: {}", task.subject);
        assert_eq!(task,
                   Task {
                       line: todo_item.to_owned(),
                       subject: "сменить загранпаспорт +документы".to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 27)),
                       priority: 26,
                       due_date: Some(Date::from_ymd(2020, 8, 14)),
                       threshold_date: Some(Date::from_ymd(2020, 4, 14)),
                       projects: vec!["документы".to_owned()],
                       ..Task::default()
                   });

        let todo_item = "x 2016-03-27 сменить загранпаспорт due:2020-08-14 t:2020-04-14 +документы";
        let task = todo_item.parse::<Task>().unwrap();
        println!("subj: {}", task.subject);
        assert_eq!(task,
                   Task {
                       line: todo_item.to_owned(),
                       subject: "сменить загранпаспорт +документы".to_owned(),
                       create_date: Some(Date::from_ymd(2016, 3, 27)),
                       priority: 26,
                       due_date: Some(Date::from_ymd(2020, 8, 14)),
                       threshold_date: Some(Date::from_ymd(2020, 4, 14)),
                       projects: vec!["документы".to_owned()],
                       finished: true,
                       ..Task::default()
                   });
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```rust
//! extern crate serde_yaml;
//!
//! use std::collections::BTreeMap;
//!
//! // You have some type.
//! let mut map = BTreeMap::new();
//! map.insert("x".to_string(), 1.0);
//! map.insert("y".to_string(), 2.0);
//!
//! // Serialize it to a YAML string.
//! let s = serde_yaml::to_string(&map).unwrap();
//! assert_eq!(s, "---\nx: 1.0\n\"y\": 2.0");
//!
//! // Deserialize it back to a Rust type.
//! let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s).unwrap();
//! assert_eq!(map, deserialized_map);
//! ```
//!
//! ## Using serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```rust
//! #[macro_use] extern crate serde_derive;
//! extern crate serde_yaml;
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point { x: f64, y: f64 }
//!
//! # fn main() {
//! let point = Point { x: 1.0, y: 2.0 };
//!
//! let s = serde_yaml::to_string(&point).unwrap();
//! assert_eq!(s, "---\nx: 1.0\n\"y\": 2.0");
//!
//! let deserialized_point: Point = serde_yaml::from_str(&s).unwrap();
//! assert_eq!(point, deserialized_point);
//! # }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.7.4")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// private Deserializer::next
    should_implement_trait,
// things are often more readable this way
    cast_lossless,
    single_match_else,
    stutter,
    use_self,
// not practical
    missing_docs_in_private_items,
// not stable
    empty_enum,
// meh, some things won't fail
    result_unwrap_used,
))]

extern crate dtoa;
extern crate linked_hash_map;
#[macro_use]
extern crate serde;
extern crate yaml_rust;

pub use self::de::{from_reader, from_slice, from_str};
pub use self::error::{Error, Location, Result};
pub use self::mapping::Mapping;
pub use self::ser::{to_string, to_vec, to_writer};
pub use self::value::{from_value, to_value, Number, Sequence, Value};

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;
<commit_msg>Ignore clippy casting lints<commit_after>// Copyright 2016 Serde YAML Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```rust
//! extern crate serde_yaml;
//!
//! use std::collections::BTreeMap;
//!
//! // You have some type.
//! let mut map = BTreeMap::new();
//! map.insert("x".to_string(), 1.0);
//! map.insert("y".to_string(), 2.0);
//!
//! // Serialize it to a YAML string.
//! let s = serde_yaml::to_string(&map).unwrap();
//! assert_eq!(s, "---\nx: 1.0\n\"y\": 2.0");
//!
//! // Deserialize it back to a Rust type.
//! let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s).unwrap();
//! assert_eq!(map, deserialized_map);
//! ```
//!
//! ## Using serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```rust
//! #[macro_use] extern crate serde_derive;
//! extern crate serde_yaml;
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point { x: f64, y: f64 }
//!
//! # fn main() {
//! let point = Point { x: 1.0, y: 2.0 };
//!
//! let s = serde_yaml::to_string(&point).unwrap();
//! assert_eq!(s, "---\nx: 1.0\n\"y\": 2.0");
//!
//! let deserialized_point: Point = serde_yaml::from_str(&s).unwrap();
//! assert_eq!(point, deserialized_point);
//! # }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.7.4")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// private Deserializer::next
    should_implement_trait,
// things are often more readable this way
    cast_lossless,
    single_match_else,
    stutter,
    use_self,
// code is acceptable
    cast_possible_wrap,
    cast_precision_loss,
    cast_sign_loss,
// not practical
    missing_docs_in_private_items,
// not stable
    empty_enum,
// meh, some things won't fail
    result_unwrap_used,
))]

extern crate dtoa;
extern crate linked_hash_map;
#[macro_use]
extern crate serde;
extern crate yaml_rust;

pub use self::de::{from_reader, from_slice, from_str};
pub use self::error::{Error, Location, Result};
pub use self::mapping::Mapping;
pub use self::ser::{to_string, to_vec, to_writer};
pub use self::value::{from_value, to_value, Number, Sequence, Value};

mod de;
mod error;
mod mapping;
mod number;
mod path;
mod ser;
mod value;
<|endoftext|>


<commit_before>#![recursion_limit="128"]
#[macro_use]

extern crate delegatemethod;

pub use hashmap::DefaultHashMap;

mod hashmap {
    use std::hash::Hash;
    use std::collections::HashMap;
    use std::collections::hash_map::*;
    use std::borrow::Borrow;
    use std::ops::{Index, IndexMut};

    #[derive(PartialEq, Eq, Debug, Default)]
    pub struct DefaultHashMap<K: Eq + Hash, V: Clone> {
        map: HashMap<K, V>,
        default: V,
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        pub fn new(default: V) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::new(),
                default: default,
            }
        }

        pub fn get_mut(&mut self, key: K) -> &mut V {
            self.map.entry(key).or_insert(self.default.clone())
        }
    }

    trait Getter<K, V> {
        fn get(&self, K) -> &V;
    }

    impl<'b, K, V: Clone> Getter<&'b K, V> for DefaultHashMap<K, V>
        where K: Eq + Hash
    {
        fn get(&self, key: &'b K) -> &V {
            self.map.get(key).unwrap_or(&self.default)
        }
    }

    impl<K, V: Clone> Getter<K, V> for DefaultHashMap<K, V>
        where K: Eq + Hash
    {
        fn get(&self, key: K) -> &V {
            self.map.get(&key).unwrap_or(&self.default)
        }
    }

    delegate_method!{
        impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
            map as HashMap:
                pub fn capacity(&self) -> usize;
                pub fn reserve(&mut self, additional: usize);
                pub fn shrink_to_fit(&mut self);
                pub fn keys(&self) -> Keys<K, V>;
                pub fn values(&self) -> Values<K, V>;
                pub fn values_mut(&mut self) -> ValuesMut<K, V>;
                pub fn iter(&self) -> Iter<K, V>;
                pub fn iter_mut(&mut self) -> IterMut<K, V>;
                pub fn entry(&mut self, key: K) -> Entry<K, V>;
                pub fn len(&self) -> usize;
                pub fn is_empty(&self) -> bool;
                pub fn drain(&mut self) -> Drain<K, V>;
                pub fn clear(&mut self);
                pub fn insert(&mut self, k: K, v: V) -> Option<V>;
        }
    }

    macro_rules! q_func {
        ($name:ident, $K:ident, $($returns:ty),*) => (
            pub fn $name<Q>(&self, k: &Q) -> ($($returns),*)
                where K: Borrow<Q>,
                      Q: Hash + Eq
            {

              self.map.$name(k)
            }
        )
    }

    macro_rules! q_func_mut {
        ($name:ident, $K:ident, $($returns:ty),*) => (
            pub fn $name<Q>(&mut self, k: &Q) -> ($($returns),*)
                where K: Borrow<Q>,
                      Q: Hash + Eq
            {

              self.map.$name(k)
            }
        )
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        q_func!(contains_key, K, bool);
        q_func_mut!(remove, K, Option<V>);
    }

    impl<'a, K: Eq + Hash, V: Clone> Index<&'a K> for DefaultHashMap<K, V> {
        type Output = V;

        fn index(&self, index: &K) -> &V {
            self.get(index)
        }
    }

    impl<K: Eq + Hash, V: Clone> Index<K> for DefaultHashMap<K, V> {
        type Output = V;

        fn index(&self, index: K) -> &V {
            self.get(&index)
        }
    }

    impl<K: Eq + Hash, V: Clone> IndexMut<K> for DefaultHashMap<K, V> {
        #[inline]
        fn index_mut(&mut self, index: K) -> &mut V {
            self.get_mut(index)
        }
    }

}

#[cfg(test)]
mod tests {
    use super::DefaultHashMap;

    #[test]
    fn add() {
        let mut map: DefaultHashMap<i32, i32> = DefaultHashMap::new(0);
        *map.get_mut(0) += 1;
        map[1] += 4;
        map[2] = map[0] + map.get(&1);
        assert_eq!(*map.get(0), 1);
        assert_eq!(*map.get(&0), 1);
        assert_eq!(map[0], 1);
        assert_eq!(map[&0], 1);
        assert_eq!(*map.get(&1), 4);
        assert_eq!(*map.get(&2), 5);
        assert_eq!(*map.get(999), 0);
        assert_eq!(*map.get(&999), 0);
        assert_eq!(map[999], 0);
        assert_eq!(map[&999], 0);
    }
}
<commit_msg>Simplify code by using Borrow trait<commit_after>#![recursion_limit="128"]
#[macro_use]

extern crate delegatemethod;

pub use hashmap::DefaultHashMap;

mod hashmap {
    use std::hash::Hash;
    use std::collections::HashMap;
    use std::collections::hash_map::*;
    use std::borrow::Borrow;
    use std::ops::{Index, IndexMut};

    #[derive(PartialEq, Eq, Debug, Default)]
    pub struct DefaultHashMap<K: Eq + Hash, V: Clone> {
        map: HashMap<K, V>,
        default: V,
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        pub fn new(default: V) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::new(),
                default: default,
            }
        }

        pub fn get_mut(&mut self, key: K) -> &mut V {
            self.map.entry(key).or_insert(self.default.clone())
        }

        pub fn get<Q, QB: Borrow<Q>>(&self, key: QB) -> &V
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.get(key.borrow()).unwrap_or(&self.default)
        }
    }

    delegate_method!{
        impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
            map as HashMap:
                pub fn capacity(&self) -> usize;
                pub fn reserve(&mut self, additional: usize);
                pub fn shrink_to_fit(&mut self);
                pub fn keys(&self) -> Keys<K, V>;
                pub fn values(&self) -> Values<K, V>;
                pub fn values_mut(&mut self) -> ValuesMut<K, V>;
                pub fn iter(&self) -> Iter<K, V>;
                pub fn iter_mut(&mut self) -> IterMut<K, V>;
                pub fn entry(&mut self, key: K) -> Entry<K, V>;
                pub fn len(&self) -> usize;
                pub fn is_empty(&self) -> bool;
                pub fn drain(&mut self) -> Drain<K, V>;
                pub fn clear(&mut self);
                pub fn insert(&mut self, k: K, v: V) -> Option<V>;
        }
    }

    macro_rules! q_func {
        ($name:ident, $K:ident, $($returns:ty),*) => (
            pub fn $name<Q>(&self, k: &Q) -> ($($returns),*)
                where K: Borrow<Q>,
                      Q: Hash + Eq
            {

              self.map.$name(k)
            }
        )
    }

    macro_rules! q_func_mut {
        ($name:ident, $K:ident, $($returns:ty),*) => (
            pub fn $name<Q>(&mut self, k: &Q) -> ($($returns),*)
                where K: Borrow<Q>,
                      Q: Hash + Eq
            {

              self.map.$name(k)
            }
        )
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        q_func!(contains_key, K, bool);
        q_func_mut!(remove, K, Option<V>);
    }

    impl<'a, K: Eq + Hash, KB: Borrow<K>, V: Clone> Index<KB> for DefaultHashMap<K, V> {
        type Output = V;

        fn index(&self, index: KB) -> &V {
            self.get(index)
        }
    }

    impl<K: Eq + Hash, V: Clone> IndexMut<K> for DefaultHashMap<K, V> {
        #[inline]
        fn index_mut(&mut self, index: K) -> &mut V {
            self.get_mut(index)
        }
    }

}

#[cfg(test)]
mod tests {
    use super::DefaultHashMap;

    #[test]
    fn add() {
        let mut map: DefaultHashMap<i32, i32> = DefaultHashMap::new(0);
        *map.get_mut(0) += 1;
        map[1] += 4;
        map[2] = map[0] + map.get(&1);
        assert_eq!(*map.get(0), 1);
        assert_eq!(*map.get(&0), 1);
        assert_eq!(map[0], 1);
        assert_eq!(map[&0], 1);
        assert_eq!(*map.get(&1), 4);
        assert_eq!(*map.get(&2), 5);
        assert_eq!(*map.get(999), 0);
        assert_eq!(*map.get(&999), 0);
        assert_eq!(map[999], 0);
        assert_eq!(map[&999], 0);
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # State machine
//!
//! The `StateMachine` trait is implemented by anything that represents a state machine (aka a finite state automaton). These
//! consist of one or more states that are transitioned between upon matching a symbol from the input.
//!
//! State machines in this library can optionally attach output symbols to states. A state with an output symbol is an 'accepting'
//! state: it matches a substring of the output.
//!

use std::rc::*;

///
/// Identifies a state in a state machine
///
pub type StateId = u32;

///
/// Trait implemented by objects that represent a state machine, whose transitions depend on a particular symbol type
///
/// These state machines can be nondeterministic - which is to say, have more than one transition per state. They always
/// start in state 0.
///
pub trait StateMachine<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId;

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)>;

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol>;
}

///
/// Trait implemented by state machines that can be altered
///
pub trait MutableStateMachine<InputSymbol, OutputSymbol> : StateMachine<InputSymbol, OutputSymbol> {
    ///
    /// Adds a transition from a particular state to another on seeing a symbol
    ///
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId);

    ///
    /// Ensures that a state with the specified ID exists in this state machine
    ///
    fn create_state(&mut self, state: StateId);

    ///
    /// Sets the output symbol to use for a particular state
    ///
    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol);

    ///
    /// Joins two states in this state machine
    ///
    /// This means that `first_state` will follow the transitions for `second_state` - that is, any transition that appears
    /// in `second_state` will also appear in `first_state` - including transitions that are added after this call.
    ///
    /// The reverse is not true: `second_state` does not acquire the transitions from `first_state`.
    ///
    /// This could be considered as creating an empty or 'epsilon' transition between the first state and the second state,
    /// which is useful for building NDFAs from regular languages.
    ///
    /// These semantics mean that callers don't have to treat empty transitions as special cases, and also ensure that state
    /// 0 is always the sole start state for the automaton.
    ///
    fn join_states(&mut self, first_state: StateId, second_state: StateId);
}

///
/// Trait implemented by things that can be converted into a non-deterministic state machine with a specific symbol for
/// the output state.
///
pub trait ToNdfa<InputSymbol> {
    fn to_ndfa<OutputSymbol>(&self, output: OutputSymbol) -> Box<StateMachine<InputSymbol, OutputSymbol>>;
}

///
/// Any reference to a state machine is also a state machine
///
impl<InputSymbol, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Rc<StateMachine<InputSymbol, OutputSymbol>> {
    #[inline]
    fn count_states(&self) -> StateId {
        (**self).count_states()
    }

    #[inline]
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        (**self).get_transitions_for_state(state)
    }

    #[inline]
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        (**self).output_symbol_for_state(state)
    }
}
<commit_msg>Make a boxed state machine the same as a state machine<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # State machine
//!
//! The `StateMachine` trait is implemented by anything that represents a state machine (aka a finite state automaton). These
//! consist of one or more states that are transitioned between upon matching a symbol from the input.
//!
//! State machines in this library can optionally attach output symbols to states. A state with an output symbol is an 'accepting'
//! state: it matches a substring of the output.
//!

use std::rc::*;

///
/// Identifies a state in a state machine
///
pub type StateId = u32;

///
/// Trait implemented by objects that represent a state machine, whose transitions depend on a particular symbol type
///
/// These state machines can be nondeterministic - which is to say, have more than one transition per state. They always
/// start in state 0.
///
pub trait StateMachine<InputSymbol, OutputSymbol> {
    ///
    /// Returns the number of states in this state machine
    ///
    /// Note that if state x exists then state x-1 is also expected to exist provided x > 0. This means that this returns the
    /// first unused state in this state machine.
    ///
    fn count_states(&self) -> StateId;

    ///
    /// Returns the transitions for a particular symbol
    ///
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)>;

    ///
    /// If a state is an accepting state, then this returns the output symbol that should be produced if this is the longest match
    ///
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol>;
}

///
/// Trait implemented by state machines that can be altered
///
pub trait MutableStateMachine<InputSymbol, OutputSymbol> : StateMachine<InputSymbol, OutputSymbol> {
    ///
    /// Adds a transition from a particular state to another on seeing a symbol
    ///
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId);

    ///
    /// Ensures that a state with the specified ID exists in this state machine
    ///
    fn create_state(&mut self, state: StateId);

    ///
    /// Sets the output symbol to use for a particular state
    ///
    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol);

    ///
    /// Joins two states in this state machine
    ///
    /// This means that `first_state` will follow the transitions for `second_state` - that is, any transition that appears
    /// in `second_state` will also appear in `first_state` - including transitions that are added after this call.
    ///
    /// The reverse is not true: `second_state` does not acquire the transitions from `first_state`.
    ///
    /// This could be considered as creating an empty or 'epsilon' transition between the first state and the second state,
    /// which is useful for building NDFAs from regular languages.
    ///
    /// These semantics mean that callers don't have to treat empty transitions as special cases, and also ensure that state
    /// 0 is always the sole start state for the automaton.
    ///
    fn join_states(&mut self, first_state: StateId, second_state: StateId);
}

///
/// Trait implemented by things that can be converted into a non-deterministic state machine with a specific symbol for
/// the output state.
///
pub trait ToNdfa<InputSymbol> {
    fn to_ndfa<OutputSymbol>(&self, output: OutputSymbol) -> Box<StateMachine<InputSymbol, OutputSymbol>>;
}

///
/// Any reference to a state machine is also a state machine
///
impl<InputSymbol, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Rc<StateMachine<InputSymbol, OutputSymbol>> {
    #[inline]
    fn count_states(&self) -> StateId {
        (**self).count_states()
    }

    #[inline]
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        (**self).get_transitions_for_state(state)
    }

    #[inline]
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        (**self).output_symbol_for_state(state)
    }
}

///
/// Any reference to a state machine is also a state machine
///
impl<InputSymbol, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Box<StateMachine<InputSymbol, OutputSymbol>> {
    #[inline]
    fn count_states(&self) -> StateId {
        (**self).count_states()
    }

    #[inline]
    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        (**self).get_transitions_for_state(state)
    }

    #[inline]
    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        (**self).output_symbol_for_state(state)
    }
}
<|endoftext|>


<commit_before>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
use std::ptr;
use std::mem;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRRenderModels,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TextureID,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    EVRRenderModelError as RenderModelError,
    EVRControllerAxisType as ControllerAxisType,
    VRControllerState as ControllerState,
    EVRButtonId as ButtonId,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

impl ButtonId {
    pub fn mask(self) -> u64 {
        1 << self as usize
    }
}

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct RenderModel {
    ptr: *mut ffi::RenderModel
}

pub struct RenderModelTexture {
    ptr: *mut ffi::RenderModel_TextureMap
}

pub struct VRRenderModels {
    i: *mut IVRRenderModels
}

impl VRRenderModels {
    pub fn load_render_model_async(
        &mut self,
        render_model_name: *const c_char
    ) -> Result<RenderModel, RenderModelError> {
        unsafe {
            let render_model: *mut *mut ffi::RenderModel = mem::zeroed();
            let error = ((*self.i).LoadRenderModel_Async)(render_model_name, render_model);
            if error == RenderModelError::None {
                Ok(RenderModel {
                    ptr:    *render_model
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_render_model(&mut self, render_model: RenderModel) {
        unsafe {
            ((*self.i).FreeRenderModel)(render_model.ptr)
        }
    }

    pub fn load_texture_async(
        &mut self,
        texture_id: TextureID
    ) -> Result<RenderModelTexture, RenderModelError> {
        unsafe {
            let texture: *mut *mut ffi::RenderModel_TextureMap = mem::zeroed();
            let error = ((*self.i).LoadTexture_Async)(texture_id, texture);
            if error == RenderModelError::None {
                Ok(RenderModelTexture {
                    ptr: *texture
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_texture(&mut self, texture: RenderModelTexture) {
        unsafe {
            ((*self.i).FreeTexture)(texture.ptr)
        }
    }
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_state(&self, device_index: usize) -> ControllerState {
        unsafe {
            let mut state = ControllerState::default();
            ((*self.i).GetControllerState)(device_index as ffi::TrackedDeviceIndex, &mut state);
            state
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:     VRSystem,
    pub compositor: VRCompositor,

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // render_models:      IVRRenderModels,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        Ok(VRContext {
            system:     system,
            compositor: compositor
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

#[cfg(test)]
mod prerequisites {
    use super::*;

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<commit_msg>get render model<commit_after>extern crate libloading;
#[macro_use]
extern crate lazy_static;

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ffi;

use std::os::raw::{c_char};
use std::ffi::{CString, CStr};
use std::ptr;
use std::mem;
use std::slice;
use libloading::Library;

use ffi::{
    IVRCompositor,
    IVRSystem,
    IVRChaperone,
    IVRRenderModels,
    IVRCompositor_FnTable,
    IVRSystem_FnTable,
    IVRRenderModels_FnTable,
    // IVRChaperone_FnTable,
};

pub use ffi::{
    Texture,
    TextureID,
    TrackedDevicePose,
    HmdMatrix34,
    HmdMatrix44,
    EVREye as Eye,
    EVRInitError as InitError,
    EVRApplicationType as ApplicationType,
    EGraphicsAPIConvention as GraphicsAPIConvention,
    EVRSubmitFlags as SubmitFlags,
    EVRCompositorError as CompositorError,
    ETrackingUniverseOrigin as TrackingUniverseOrigin,
    EColorSpace as ColorSpace,
    VRTextureBounds as TextureBounds,
    ETrackedDeviceClass as TrackedDeviceClass,
    ETrackedControllerRole as TrackedControllerRole,
    ETrackedDeviceProperty as TrackedDeviceProperty,
    ETrackedPropertyError as TrackedPropertyError,
    EVRRenderModelError as RenderModelError,
    EVRControllerAxisType as ControllerAxisType,
    VRControllerState as ControllerState,
    EVRButtonId as ButtonId,
    k_unMaxTrackedDeviceCount as MAX_TRACKED_DEVICE_COUNT
};

impl ButtonId {
    pub fn mask(self) -> u64 {
        1 << self as usize
    }
}

#[allow(non_snake_case)]
#[allow(dead_code)]
struct ApiFunctions {
    VR_InitInternal:            extern fn (peError: *mut InitError, eType: ApplicationType) -> usize,
    VR_ShutdownInternal:        extern fn (),
    VR_IsHmdPresent:            extern fn () -> ::std::os::raw::c_char,
    VR_GetStringForHmdError:    extern fn (error: InitError) -> *mut ::std::os::raw::c_char,
    VR_GetGenericInterface:     extern fn (pchInterfaceVersion: *const ::std::os::raw::c_char, peError: *mut InitError) -> usize,
    VR_IsRuntimeInstalled:      extern fn () -> ::std::os::raw::c_char,
    VR_GetVRInitErrorAsSymbol:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    VR_GetVRInitErrorAsEnglishDescription:  extern fn (error: InitError) -> *const ::std::os::raw::c_char,
    lib: Library,
}

unsafe impl Sync for ApiFunctions {}

lazy_static! {
    static ref API: ApiFunctions = {
        let lib = Library::new("openvr_api.dll").unwrap();

        unsafe {
            ApiFunctions {
                VR_InitInternal:            *lib.get(b"VR_InitInternal\0").unwrap(),
                VR_ShutdownInternal:        *lib.get(b"VR_ShutdownInternal\0").unwrap(),
                VR_IsHmdPresent:            *lib.get(b"VR_IsHmdPresent\0").unwrap(),
                VR_GetStringForHmdError:    *lib.get(b"VR_GetStringForHmdError\0").unwrap(),
                VR_GetGenericInterface:     *lib.get(b"VR_GetGenericInterface\0").unwrap(),
                VR_IsRuntimeInstalled:      *lib.get(b"VR_IsRuntimeInstalled\0").unwrap(),
                VR_GetVRInitErrorAsSymbol:  *lib.get(b"VR_GetVRInitErrorAsSymbol\0").unwrap(),
                VR_GetVRInitErrorAsEnglishDescription: *lib.get(b"VR_GetVRInitErrorAsEnglishDescription\0").unwrap(),
                lib: lib,
            }
        }
    };
}

pub struct VRCompositor {
    i: *mut IVRCompositor
}

impl VRCompositor {
    fn new(vr_compositor: *mut IVRCompositor) -> Self {
        assert!(vr_compositor as *const _ != ptr::null());
        VRCompositor {
            i:  vr_compositor
        }
    }

    /// Updated scene texture to display. If bounds is NULL the entire texture will be used.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::Submit
    pub fn submit(
        &mut self,
        eye:            Eye,
        texture:        *mut Texture,
        bounds:         *mut TextureBounds,
        submit_flags:   SubmitFlags
    ) -> CompositorError {
        unsafe {
            ((*self.i).Submit)(eye, texture, bounds, submit_flags)
        }
    }

    /// Returns pose(s) to use to render scene.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRCompositor::WaitGetPoses
    pub fn wait_get_poses(
        &mut self,
    ) -> [TrackedDevicePose; ffi::k_unMaxTrackedDeviceCount as usize] {
        unsafe {
            let mut render_poses = [TrackedDevicePose::default(); ffi::k_unMaxTrackedDeviceCount as usize];
            ((*self.i).WaitGetPoses)(
                (&mut render_poses[..]).as_mut_ptr(),
                render_poses.len() as u32,
                std::ptr::null_mut(),
                0
            );

            render_poses
        }
    }
}

pub struct VRChaperone {
    _i: *mut IVRChaperone
}

pub struct RenderModel {
    ptr: *mut ffi::RenderModel
}

impl RenderModel {
    pub fn vertices(&self) -> &[ffi::RenderModel_Vertex] {
        unsafe {
            slice::from_raw_parts((*self.ptr).rVertexData, (*self.ptr).unVertexCount as usize)
        }
    }

    pub fn indices(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.ptr).rIndexData, (*self.ptr).unTriangleCount as usize * 3)
        }
    }

    pub fn triangle_count(&self) -> usize {
        unsafe {
            (*self.ptr).unTriangleCount as usize
        }
    }

    pub fn texture_id(&self) -> TextureID {
        unsafe {
            (*self.ptr).diffuseTextureId
        }
    }
}

pub struct RenderModelTexture {
    ptr: *mut ffi::RenderModel_TextureMap
}

pub struct VRRenderModels {
    i: *mut IVRRenderModels
}

impl VRRenderModels {
    fn new(render_models: *mut IVRRenderModels) -> Self {
        assert!(render_models as *const _ != ptr::null());
        VRRenderModels {
            i:  render_models
        }
    }

    pub fn load_render_model_async(
        &mut self,
        render_model_name: String
    ) -> Result<RenderModel, RenderModelError> {
        unsafe {
            let render_model_name = CString::from_vec_unchecked(render_model_name.into());
            let mut render_model: *mut ffi::RenderModel = mem::zeroed();
            let error = ((*self.i).LoadRenderModel_Async)(render_model_name.as_ptr(), &mut render_model);
            if error == RenderModelError::None {
                Ok(RenderModel {
                    ptr:    render_model
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_render_model(&mut self, render_model: RenderModel) {
        unsafe {
            ((*self.i).FreeRenderModel)(render_model.ptr)
        }
    }

    pub fn load_texture_async(
        &mut self,
        texture_id: TextureID
    ) -> Result<RenderModelTexture, RenderModelError> {
        unsafe {
            let texture: *mut *mut ffi::RenderModel_TextureMap = mem::zeroed();
            let error = ((*self.i).LoadTexture_Async)(texture_id, texture);
            if error == RenderModelError::None {
                Ok(RenderModelTexture {
                    ptr: *texture
                })
            } else {
                Err(error)
            }
        }
    }

    pub fn free_texture(&mut self, texture: RenderModelTexture) {
        unsafe {
            ((*self.i).FreeTexture)(texture.ptr)
        }
    }
}

pub struct VRSystem {
    i: *mut IVRSystem
}

impl VRSystem {
    fn new(vr_system: *mut IVRSystem) -> Self {
        assert!(vr_system as *const _ != ptr::null());
        VRSystem {
            i:  vr_system
        }
    }

    /// Provides the game with the minimum size that it should use for its offscreen render
    /// target to minimize pixel stretching. This size is matched with the projection matrix
    // and distortion function and will change from display to display depending on resolution,
    // distortion, and field of view.
    pub fn get_recommended_render_target_size(&self) -> (u32, u32) {
        unsafe {
            let mut width = 0;
            let mut height = 0;
            ((*self.i).GetRecommendedRenderTargetSize)(&mut width, &mut height);
            (width, height)
        }
    }

    /// Returns the projection matrix to use for the specified eye.
    pub fn get_projection_matrix(
        &self,
        eye:                Eye,
        near_z:             f32,
        far_z:              f32,
        api:                GraphicsAPIConvention
    ) -> HmdMatrix44 {
        unsafe {
            ((*self.i).GetProjectionMatrix)(
                eye,
                near_z,
                far_z,
                api
            )
        }
    }

    /// Returns the transform between the view space and eye space.
    pub fn get_eye_to_head_transform(&self, eye: Eye) -> HmdMatrix34 {
        unsafe {
            ((*self.i).GetEyeToHeadTransform)(eye)
        }
    }

    /// Calculates updated poses for all devices.
    /// https://github.com/ValveSoftware/openvr/wiki/IVRSystem::GetDeviceToAbsoluteTrackingPose
    pub fn get_device_to_absolute_tracking_pose(
        &self,
        origin: TrackingUniverseOrigin,
        predicted_seconds_to_photons_from_now:  f32,
        tracked_device_pose_array: &mut [TrackedDevicePose]
    ) {
        unsafe {
            ((*self.i).GetDeviceToAbsoluteTrackingPose)(
                origin,
                predicted_seconds_to_photons_from_now,
                tracked_device_pose_array.as_mut_ptr(),
                tracked_device_pose_array.len() as u32
            )
        }
    }

    pub fn reset_seated_zero_pose(&self) {
        unsafe {
            ((*self.i).ResetSeatedZeroPose)()
        }
    }

    pub fn get_tracked_device_class(&self, device_index: usize) -> TrackedDeviceClass {
        unsafe {
            ((*self.i).GetTrackedDeviceClass)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_role_for_tracked_device_index(&self, device_index: usize) -> TrackedControllerRole {
        unsafe {
            ((*self.i).GetControllerRoleForTrackedDeviceIndex)(device_index as ffi::TrackedDeviceIndex)
        }
    }

    pub fn get_controller_state(&self, device_index: usize) -> ControllerState {
        unsafe {
            let mut state = ControllerState::default();
            ((*self.i).GetControllerState)(device_index as ffi::TrackedDeviceIndex, &mut state);
            state
        }
    }

    pub fn get_string_tracked_device_property(
        &self,
        device_index:   usize,
        prop:           TrackedDeviceProperty
    ) -> Result<String, TrackedPropertyError> {
        unsafe {
            let mut error = TrackedPropertyError::TrackedProp_Success;

            let buffer_length = ((*self.i).GetStringTrackedDeviceProperty)(
                device_index as ffi::TrackedDeviceIndex,
                prop,
                ptr::null::<c_char>() as *mut _,
                0,
                &mut error
            );

            assert!(buffer_length > 0);

            let mut str_data = Vec::<u8>::with_capacity(buffer_length as usize);

            ((*self.i).GetStringTrackedDeviceProperty)(
                device_index as ffi::TrackedDeviceIndex,
                prop,
                str_data.as_mut_ptr() as *mut _,
                buffer_length,
                &mut error
            );

            str_data.set_len(buffer_length as usize - 1);

            if error == TrackedPropertyError::TrackedProp_Success {
                Ok(String::from_utf8_unchecked(str_data))
            } else {
                Err(error)
            }
        }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        unsafe {
            let err = CStr::from_ptr((API.VR_GetVRInitErrorAsEnglishDescription)(*self));
            write!(f, "{}", err.to_string_lossy())
        }
    }
}

impl std::error::Error for InitError {
    fn description(&self) -> &str {
        "init error"
    }
}

pub struct VRContext {
    pub system:         VRSystem,
    pub compositor:     VRCompositor,
    pub render_models:  VRRenderModels

    // chaperone:         VRChaperone,
    // chaperone_setup:    IVRChaperoneSetup,
    // overlay:            IVROverlay,
    // IVRExtendedDisplay: *mut IVRExtendedDisplay,
    // IVRSettings: *mut IVRSettings,
    // IVRApplications: *mut IVRApplications,
}

impl Drop for VRContext {
    fn drop(&mut self) {
        // VR_ShutdownInternal();
    }
}

pub fn initialize() -> Result<VRContext, InitError> {
    let mut err = InitError::None;
    let _hmd = (API.VR_InitInternal)(&mut err, ApplicationType::VRApplication_Scene);
    if err != InitError::None {
        Err(err)
    } else {

        let system = (API.VR_GetGenericInterface)(CString::new(IVRSystem_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRSystem;
        if err != InitError::None {
            return Err(err);
        }
        let system = VRSystem::new(system);

        let compositor = (API.VR_GetGenericInterface)(CString::new(IVRCompositor_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRCompositor;
        if err != InitError::None {
            return Err(err);
        }
        let compositor = VRCompositor::new(compositor);

        let render_models = (API.VR_GetGenericInterface)(CString::new(IVRRenderModels_FnTable).unwrap().as_ptr(), &mut err) as *mut IVRRenderModels;
        if err != InitError::None {
            return Err(err);
        }
        let render_models = VRRenderModels::new(render_models);

        Ok(VRContext {
            system:         system,
            compositor:     compositor,
            render_models:  render_models
        })
    }
}

/// Returns true if the system believes that an HMD is present on the system.
pub fn is_hmd_present() -> bool {
    (API.VR_IsHmdPresent)() != 0
}

/// Returns true if the SteamVR runtime is installed.
pub fn is_runtime_installed() -> bool {
    (API.VR_IsRuntimeInstalled)() != 0
}

#[cfg(test)]
mod prerequisites {
    use super::*;

    #[test]
    fn runtime_installed() {
        assert!(is_runtime_installed());
    }

    #[test]
    fn hmd_present() {
        assert!(is_hmd_present());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    #[test]
    fn vr_init() {
        // NOTE: initializing seems to fail if a window has not been created

        // match init() {
        //     Err(err) => {
        //         println!("init failed: {} - {}", err, err.description());
        //         assert!(false);
        //     }
        //     Ok(context) => {
        //         context.system.get_recommended_render_target_size();
        //     }
        // }
    }
}
<|endoftext|>


<commit_before>//! A library providing a generic connection pool.
#![feature(unsafe_destructor)]
#![warn(missing_doc)]

use std::default::Default;
use std::sync::Mutex;
use std::fmt;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E> {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &C) -> bool;
}

/// A struct specifying the runtime configuration of a pool.
///
/// `Config` implements `Default`, which provides a set of reasonable default
/// values.
pub struct Config {
    /// The number of connections that will be made during pool creation.
    ///
    /// Must be no greater than `max_size`.
    ///
    /// Defaults to 3.
    pub initial_size: uint,
    /// The maximum number of connections that the pool will maintain.
    ///
    /// Must be positive and no less than `initial_size`.
    ///
    /// Defaults to 15.
    pub max_size: uint,
    /// The number of connections that will be created at once when the pool is
    /// exhausted.
    ///
    /// Must be positive.
    ///
    /// Defaults to 3.
    pub acquire_increment: uint,
    /// The number of tasks that the pool will use for asynchronous operations
    /// such as connection creation and health checks.
    ///
    /// Must be positive.
    ///
    /// Defaults to 3.
    pub helper_tasks: uint,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            initial_size: 3,
            max_size: 15,
            acquire_increment: 3,
            helper_tasks: 3,
        }
    }
}

impl Config {
    /// Determines if the configuration is valid
    pub fn validate(&self) -> Result<(), &'static str> {
        if self.max_size == 0 {
            return Err("max_size must be positive");
        }

        if self.initial_size > self.max_size {
            return Err("initial_size cannot be greater than max_size");
        }

        if self.acquire_increment == 0 {
            return Err("acquire_increment must be positive");
        }

        if self.helper_tasks == 0 {
            return Err("helper_tasks must be positive");
        }

        Ok(())
    }
}

/// An error type returned if pool creation fails.
#[deriving(PartialEq, Eq)]
pub enum NewPoolError<E> {
    /// The provided pool configuration was invalid.
    InvalidConfig(&'static str),
    /// The manager returned an error when creating a connection.
    ConnectionError(E),
}

impl<E: fmt::Show> fmt::Show for NewPoolError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidConfig(ref error) => write!(f, "Invalid config: {}", error),
            ConnectionError(ref error) => write!(f, "Unable to create connections: {}", error),
        }
    }
}

struct PoolInternals<C> {
    conns: Vec<C>,
    conn_count: uint,
}

/// A generic connection pool.
pub struct Pool<C, M> {
    config: Config,
    manager: M,
    internals: Mutex<PoolInternals<C>>,
}

impl<C: Send, E, M: PoolManager<C, E>> Pool<C, M> {
    /// Creates a new connection pool.
    ///
    /// `Config::initial_size` connections will be created synchronously before
    /// this method returns.
    pub fn new(config: Config, manager: M) -> Result<Pool<C, M>, NewPoolError<E>> {
        match config.validate() {
            Ok(()) => {}
            Err(err) => return Err(InvalidConfig(err))
        }

        let mut internals = PoolInternals {
            conns: vec![],
            conn_count: config.initial_size,
        };

        for _ in range(0, config.initial_size) {
            match manager.connect() {
                Ok(conn) => internals.conns.push(conn),
                Err(err) => return Err(ConnectionError(err)),
            }
        }

        Ok(Pool {
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, M>, E> {
        let mut internals = self.internals.lock();

        loop {
            match internals.conns.pop() {
                Some(conn) => {
                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn)
                    })
                }
                None => internals.cond.wait(),
            }
        }
    }

    fn put_back(&self, conn: C) {
        let mut internals = self.internals.lock();
        internals.conns.push(conn);
        internals.cond.signal();
    }
}

/// A smart pointer wrapping an underlying connection.
///
/// ## Note
///
/// Due to Rust bug [#15905](https://github.com/rust-lang/rust/issues/15905),
/// the connection cannot be automatically returned to its pool when the
/// `PooledConnection` drops out of scope. The `replace` method must be called,
/// or the `PooledConnection`'s destructor `fail!()`.
pub struct PooledConnection<'a, C, M> {
    pool: &'a Pool<C, M>,
    conn: Option<C>,
}

impl<'a, C: Send, E, M: PoolManager<C, E>> PooledConnection<'a, C, M> {
    /// Consumes the `PooledConnection`, returning the connection to its pool.
    ///
    /// This must be called before the `PooledConnection` drops out of scope or
    /// its destructor will `fail!()`.
    pub fn replace(mut self) {
        self.pool.put_back(self.conn.take_unwrap())
    }
}

#[unsafe_destructor]
impl<'a, C, M> Drop for PooledConnection<'a, C, M> {
    fn drop(&mut self) {
        if self.conn.is_some() {
            fail!("You must call conn.return()");
        }
    }
}

impl<'a, C, M> Deref<C> for PooledConnection<'a, C, M> {
    fn deref(&self) -> &C {
        self.conn.get_ref()
    }
}
<commit_msg>Add a doc root<commit_after>//! A library providing a generic connection pool.
#![feature(unsafe_destructor)]
#![warn(missing_doc)]
#![doc(html_root_url="http://www.rust-ci.org/sfackler/r2d2/doc")]

use std::default::Default;
use std::sync::Mutex;
use std::fmt;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E> {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &C) -> bool;
}

/// A struct specifying the runtime configuration of a pool.
///
/// `Config` implements `Default`, which provides a set of reasonable default
/// values.
pub struct Config {
    /// The number of connections that will be made during pool creation.
    ///
    /// Must be no greater than `max_size`.
    ///
    /// Defaults to 3.
    pub initial_size: uint,
    /// The maximum number of connections that the pool will maintain.
    ///
    /// Must be positive and no less than `initial_size`.
    ///
    /// Defaults to 15.
    pub max_size: uint,
    /// The number of connections that will be created at once when the pool is
    /// exhausted.
    ///
    /// Must be positive.
    ///
    /// Defaults to 3.
    pub acquire_increment: uint,
    /// The number of tasks that the pool will use for asynchronous operations
    /// such as connection creation and health checks.
    ///
    /// Must be positive.
    ///
    /// Defaults to 3.
    pub helper_tasks: uint,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            initial_size: 3,
            max_size: 15,
            acquire_increment: 3,
            helper_tasks: 3,
        }
    }
}

impl Config {
    /// Determines if the configuration is valid
    pub fn validate(&self) -> Result<(), &'static str> {
        if self.max_size == 0 {
            return Err("max_size must be positive");
        }

        if self.initial_size > self.max_size {
            return Err("initial_size cannot be greater than max_size");
        }

        if self.acquire_increment == 0 {
            return Err("acquire_increment must be positive");
        }

        if self.helper_tasks == 0 {
            return Err("helper_tasks must be positive");
        }

        Ok(())
    }
}

/// An error type returned if pool creation fails.
#[deriving(PartialEq, Eq)]
pub enum NewPoolError<E> {
    /// The provided pool configuration was invalid.
    InvalidConfig(&'static str),
    /// The manager returned an error when creating a connection.
    ConnectionError(E),
}

impl<E: fmt::Show> fmt::Show for NewPoolError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidConfig(ref error) => write!(f, "Invalid config: {}", error),
            ConnectionError(ref error) => write!(f, "Unable to create connections: {}", error),
        }
    }
}

struct PoolInternals<C> {
    conns: Vec<C>,
    conn_count: uint,
}

/// A generic connection pool.
pub struct Pool<C, M> {
    config: Config,
    manager: M,
    internals: Mutex<PoolInternals<C>>,
}

impl<C: Send, E, M: PoolManager<C, E>> Pool<C, M> {
    /// Creates a new connection pool.
    ///
    /// `Config::initial_size` connections will be created synchronously before
    /// this method returns.
    pub fn new(config: Config, manager: M) -> Result<Pool<C, M>, NewPoolError<E>> {
        match config.validate() {
            Ok(()) => {}
            Err(err) => return Err(InvalidConfig(err))
        }

        let mut internals = PoolInternals {
            conns: vec![],
            conn_count: config.initial_size,
        };

        for _ in range(0, config.initial_size) {
            match manager.connect() {
                Ok(conn) => internals.conns.push(conn),
                Err(err) => return Err(ConnectionError(err)),
            }
        }

        Ok(Pool {
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, M>, E> {
        let mut internals = self.internals.lock();

        loop {
            match internals.conns.pop() {
                Some(conn) => {
                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn)
                    })
                }
                None => internals.cond.wait(),
            }
        }
    }

    fn put_back(&self, conn: C) {
        let mut internals = self.internals.lock();
        internals.conns.push(conn);
        internals.cond.signal();
    }
}

/// A smart pointer wrapping an underlying connection.
///
/// ## Note
///
/// Due to Rust bug [#15905](https://github.com/rust-lang/rust/issues/15905),
/// the connection cannot be automatically returned to its pool when the
/// `PooledConnection` drops out of scope. The `replace` method must be called,
/// or the `PooledConnection`'s destructor `fail!()`.
pub struct PooledConnection<'a, C, M> {
    pool: &'a Pool<C, M>,
    conn: Option<C>,
}

impl<'a, C: Send, E, M: PoolManager<C, E>> PooledConnection<'a, C, M> {
    /// Consumes the `PooledConnection`, returning the connection to its pool.
    ///
    /// This must be called before the `PooledConnection` drops out of scope or
    /// its destructor will `fail!()`.
    pub fn replace(mut self) {
        self.pool.put_back(self.conn.take_unwrap())
    }
}

#[unsafe_destructor]
impl<'a, C, M> Drop for PooledConnection<'a, C, M> {
    fn drop(&mut self) {
        if self.conn.is_some() {
            fail!("You must call conn.return()");
        }
    }
}

impl<'a, C, M> Deref<C> for PooledConnection<'a, C, M> {
    fn deref(&self) -> &C {
        self.conn.get_ref()
    }
}
<|endoftext|>


<commit_before>#![feature(alloc,libc,cstr_memory,cstr_to_str)]
extern crate readline_sys as readline_ffi;
extern crate libc;
extern crate alloc;

use std::ffi::{CStr,CString};
use libc::c_char;

pub enum ReadlineError {
    EndOfFile,
    InvalidUtf8(std::str::Utf8Error)
}

impl std::convert::From<std::str::Utf8Error> for ReadlineError {
    fn from(err: std::str::Utf8Error) -> ReadlineError {
        ReadlineError::InvalidUtf8(err)
    }
}

pub fn readline(prompt: &str) -> Result<String, ReadlineError> {
    unsafe {
        let line_ptr = readline_ffi::readline(
            prompt.as_ptr() as *const c_char);

        if line_ptr.is_null() {
            return Err(ReadlineError::EndOfFile);
        }

        return Ok(try!(CStr::from_ptr(line_ptr).to_str()).to_owned());
    }
}

pub fn add_history(line: &str) {
    unsafe {
        //TODO fix memory leak
        readline_ffi::add_history(CString::new(line).unwrap().into_raw());
    }
}
<commit_msg>fixed missing null termination<commit_after>#![feature(alloc,libc,cstr_memory,cstr_to_str)]
extern crate readline_sys as readline_ffi;
extern crate libc;
extern crate alloc;

use std::ffi::{CStr,CString};

pub enum ReadlineError {
    EndOfFile,
    InvalidUtf8(std::str::Utf8Error)
}

impl std::convert::From<std::str::Utf8Error> for ReadlineError {
    fn from(err: std::str::Utf8Error) -> ReadlineError {
        ReadlineError::InvalidUtf8(err)
    }
}

pub fn readline(prompt: &str) -> Result<String, ReadlineError> {
    unsafe {
        let line_ptr = readline_ffi::readline(
            CString::new(prompt).unwrap().as_ptr());

        if line_ptr.is_null() {
            return Err(ReadlineError::EndOfFile);
        }

        return Ok(try!(CStr::from_ptr(line_ptr).to_str()).to_owned());
    }
}

pub fn add_history(line: &str) {
    unsafe {
        //TODO fix memory leak
        readline_ffi::add_history(CString::new(line).unwrap().into_raw());
    }
}
<|endoftext|>