<commit_before>#![crate_name = "tcp_simple"]
#![crate_type="lib"]

use std::thread;
use std::io::{Read, Write};
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver};
use std::net::{TcpListener, TcpStream, Shutdown, SocketAddrV4, SocketAddr};

pub struct Message {
  count: usize,
  buf: [u8; 1400],
}

pub struct TcpCfg {
  address: SocketAddrV4,
  max_conn: usize,
}

pub struct TcpSock {
  conns: HashMap<SocketAddrV4, TcpStream>,
  listener: TcpListener,
  msg_rx: Receiver<Message>,
  conn_rx: Receiver<(SocketAddrV4, TcpStream)>,
  disc_rx: Receiver<SocketAddrV4>,
}

pub enum TcpErr {
  NotConnected,
  IoErr(std::io::Error),
}

pub enum TcpEvent {
  RecvMsg(Message),
  NewConn(SocketAddrV4),
  Disconn(SocketAddrV4),
  Nil,
}

impl TcpSock {
  pub fn new_from_cfg(cfg: TcpCfg) -> TcpSock {
    let conns = HashMap::new();
    let listener = TcpListener::bind(cfg.address).unwrap();

    let (conn_tx, conn_rx) = channel();
    let (disc_tx, disc_rx) = channel();
    let (recv_tx, recv_rx) = channel();
    let accept_listener = listener.try_clone().unwrap();
    let sock = TcpSock{
      conns: conns,
      listener: listener,
      msg_rx: recv_rx,
      conn_rx: conn_rx,
      disc_rx: disc_rx,
    };

    thread::spawn(move|| {
      TcpSock::accept_loop(conn_tx, recv_tx, disc_tx, &accept_listener);
    });

    sock
  }

  pub fn close(self) {
    drop(self.listener);
  }

  pub fn receive(&mut self) -> Option<Message> {
    match self.msg_rx.try_recv() {
      Ok(m) => Some(m),
      Err(_) => None,
    }
  }

  fn recv_loop(recv_tx: Sender<Message>, disc_tx: Sender<SocketAddrV4>, mut conn: TcpStream) {
    let mut buf = [0; 1400];
    loop {
      match conn.read(&mut buf) {
        Ok(count) if count > 0 => {
          match recv_tx.send(Message{count: count, buf: buf}) {
            Ok(_) => {},
            Err(_) => break,
          }
        },
        _ => break,
      }
    }
    let _ = conn.shutdown(Shutdown::Both);
    match conn.peer_addr().unwrap() {
        SocketAddr::V4(s) => { let _ = disc_tx.send(s); },
        _ => {},
    };
  }

  fn accept_loop(conn_tx: Sender<(SocketAddrV4, TcpStream)>,
                 recv_tx: Sender<Message>,
                 disc_tx: Sender<SocketAddrV4>,
                 listener: &TcpListener)
  {
    for stream in listener.incoming() {
      match stream {
        Ok(stream) => {
          match stream.try_clone() {
            Ok(c) => {
              let rtx = recv_tx.clone();
              let dtx = disc_tx.clone();
              thread::spawn(move|| {
                TcpSock::recv_loop(rtx, dtx, c);
              });
            },
            Err(_) => { continue; },
          }
          match stream.peer_addr().unwrap() {
            SocketAddr::V4(s) => {
              match conn_tx.send((s, stream)) {
                Ok(_) => {},
                Err(_) => return,
              }
            }
            _ => {}
          }
        },
        Err(_) => continue,
      };
    }
  }

  pub fn send(&mut self, to: &SocketAddrV4, buf: &[u8]) -> Result<usize, TcpErr> {
    match self.conns.get_mut(&to) {
      Some(conn) => match conn.write(buf) {
        Ok(s) => Ok(s),
        Err(e) => Err(TcpErr::IoErr(e)),
      },
      _ => Err(TcpErr::NotConnected)
    }
  }

  pub fn send_to_all(&mut self, buf: &[u8]) {
    for (_, conn) in self.conns.iter_mut() {
      let _ = conn.write(buf);
    }
  }

  pub fn poll(&mut self) -> TcpEvent {
    match self.conn_rx.try_recv() {
      Ok((addr, conn)) => {
        self.conns.insert(addr, conn);
        return TcpEvent::NewConn(addr);
      },
      Err(_) => {},
    };

    match self.disc_rx.try_recv() {
      Ok(addr) => {
        self.conns.remove(&addr);
        return TcpEvent::Disconn(addr);
      }
      Err(_) => {},
    }

    match self.msg_rx.try_recv() {
      Ok(msg) => return TcpEvent::RecvMsg(msg),
      Err(_) => {},
    };

    TcpEvent::Nil
  }

  pub fn disconnect(&mut self, disc: &SocketAddrV4) -> Result<(), TcpErr> {
    match self.conns.get_mut(&disc) {
      Some(conn) => match conn.shutdown(Shutdown::Both) {
        Ok(()) => {},
        Err(e) => { return Err(TcpErr::IoErr(e)); },
      },
      _ => { return Err(TcpErr::NotConnected); },
    };
    self.conns.remove(disc).unwrap();
    Ok(())
  }
}
<commit_msg>Message and TcpCfg fields public<commit_after>#![crate_name = "tcp_simple"]
#![crate_type="lib"]

use std::thread;
use std::io::{Read, Write};
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver};
use std::net::{TcpListener, TcpStream, Shutdown, SocketAddrV4, SocketAddr};

pub struct Message {
  pub count: usize,
  pub buf: [u8; 1400],
}

pub struct TcpCfg {
  pub address: SocketAddrV4,
  pub max_conn: usize,
}

pub struct TcpSock {
  conns: HashMap<SocketAddrV4, TcpStream>,
  listener: TcpListener,
  msg_rx: Receiver<Message>,
  conn_rx: Receiver<(SocketAddrV4, TcpStream)>,
  disc_rx: Receiver<SocketAddrV4>,
}

pub enum TcpErr {
  NotConnected,
  IoErr(std::io::Error),
}

pub enum TcpEvent {
  RecvMsg(Message),
  NewConn(SocketAddrV4),
  Disconn(SocketAddrV4),
  Nil,
}

impl TcpSock {
  pub fn new_from_cfg(cfg: TcpCfg) -> TcpSock {
    let conns = HashMap::new();
    let listener = TcpListener::bind(cfg.address).unwrap();

    let (conn_tx, conn_rx) = channel();
    let (disc_tx, disc_rx) = channel();
    let (recv_tx, recv_rx) = channel();
    let accept_listener = listener.try_clone().unwrap();
    let sock = TcpSock{
      conns: conns,
      listener: listener,
      msg_rx: recv_rx,
      conn_rx: conn_rx,
      disc_rx: disc_rx,
    };

    thread::spawn(move|| {
      TcpSock::accept_loop(conn_tx, recv_tx, disc_tx, &accept_listener);
    });

    sock
  }

  pub fn close(self) {
    drop(self.listener);
  }

  pub fn receive(&mut self) -> Option<Message> {
    match self.msg_rx.try_recv() {
      Ok(m) => Some(m),
      Err(_) => None,
    }
  }

  fn recv_loop(recv_tx: Sender<Message>, disc_tx: Sender<SocketAddrV4>, mut conn: TcpStream) {
    let mut buf = [0; 1400];
    loop {
      match conn.read(&mut buf) {
        Ok(count) if count > 0 => {
          match recv_tx.send(Message{count: count, buf: buf}) {
            Ok(_) => {},
            Err(_) => break,
          }
        },
        _ => break,
      }
    }
    let _ = conn.shutdown(Shutdown::Both);
    match conn.peer_addr().unwrap() {
        SocketAddr::V4(s) => { let _ = disc_tx.send(s); },
        _ => {},
    };
  }

  fn accept_loop(conn_tx: Sender<(SocketAddrV4, TcpStream)>,
                 recv_tx: Sender<Message>,
                 disc_tx: Sender<SocketAddrV4>,
                 listener: &TcpListener)
  {
    for stream in listener.incoming() {
      match stream {
        Ok(stream) => {
          match stream.try_clone() {
            Ok(c) => {
              let rtx = recv_tx.clone();
              let dtx = disc_tx.clone();
              thread::spawn(move|| {
                TcpSock::recv_loop(rtx, dtx, c);
              });
            },
            Err(_) => { continue; },
          }
          match stream.peer_addr().unwrap() {
            SocketAddr::V4(s) => {
              match conn_tx.send((s, stream)) {
                Ok(_) => {},
                Err(_) => return,
              }
            }
            _ => {}
          }
        },
        Err(_) => continue,
      };
    }
  }

  pub fn send(&mut self, to: &SocketAddrV4, buf: &[u8]) -> Result<usize, TcpErr> {
    match self.conns.get_mut(&to) {
      Some(conn) => match conn.write(buf) {
        Ok(s) => Ok(s),
        Err(e) => Err(TcpErr::IoErr(e)),
      },
      _ => Err(TcpErr::NotConnected)
    }
  }

  pub fn send_to_all(&mut self, buf: &[u8]) {
    for (_, conn) in self.conns.iter_mut() {
      let _ = conn.write(buf);
    }
  }

  pub fn poll(&mut self) -> TcpEvent {
    match self.conn_rx.try_recv() {
      Ok((addr, conn)) => {
        self.conns.insert(addr, conn);
        return TcpEvent::NewConn(addr);
      },
      Err(_) => {},
    };

    match self.disc_rx.try_recv() {
      Ok(addr) => {
        self.conns.remove(&addr);
        return TcpEvent::Disconn(addr);
      }
      Err(_) => {},
    }

    match self.msg_rx.try_recv() {
      Ok(msg) => return TcpEvent::RecvMsg(msg),
      Err(_) => {},
    };

    TcpEvent::Nil
  }

  pub fn disconnect(&mut self, disc: &SocketAddrV4) -> Result<(), TcpErr> {
    match self.conns.get_mut(&disc) {
      Some(conn) => match conn.shutdown(Shutdown::Both) {
        Ok(()) => {},
        Err(e) => { return Err(TcpErr::IoErr(e)); },
      },
      _ => { return Err(TcpErr::NotConnected); },
    };
    self.conns.remove(disc).unwrap();
    Ok(())
  }
}
<|endoftext|>


<commit_before>#![feature(core,str_char)]

extern crate core;

use core::iter::Iterator;

pub struct Splits<'l>{
	str  : &'l str,
	begin: &'l str,
	end  : &'l str
}

impl<'l> Splits<'l>{
	pub fn from_str(str: &'l str) -> Self{
		Splits{
			str  : str,
			begin: "",
			end  : str
		}
	}
}

impl<'l> Iterator for Splits<'l>{
	type Item = (&'l str,&'l str);

	fn next(&mut self) -> Option<<Self as Iterator>::Item>{
		if self.end.is_empty(){
			None
		}else{
			let head_len = self.end.char_at(0).len_utf8();
			self.begin = unsafe{self.str.slice_unchecked(0,self.begin.len() + head_len)};
			self.end = unsafe{self.end.slice_unchecked(head_len,self.end.len())};

			Some((self.begin,self.end))
		}
	}
}

pub struct SplitsChar<'l>{
	str  : &'l str,
	begin: &'l str,
	end  : &'l str
}

impl<'l> SplitsChar<'l>{
	pub fn from_str(str: &'l str) -> Self{
		SplitsChar{
			str  : str,
			begin: "",
			end  :  str
		}
	}
}

impl<'l> Iterator for SplitsChar<'l>{
	type Item = (&'l str,char,&'l str);

	fn next(&mut self) -> Option<<Self as Iterator>::Item>{
		if self.end.is_empty(){
			None
		}else{
			let c = self.end.char_at(0);
			let c_len = c.len_utf8();

			self.end = unsafe{self.end.slice_unchecked(c_len,self.end.len())};
			let begin = self.begin;
			self.begin = unsafe{self.str.slice_unchecked(0,self.begin.len() + c_len)};

			Some((begin,c,self.end))
		}
	}
}

#[test]
fn test_splits(){
	let mut splits = Splits::from_str("0123456789");
	/*01*/assert_eq!(splits.next().unwrap(),("0","123456789"));
	/*02*/assert_eq!(splits.next().unwrap(),("01","23456789"));
	/*03*/assert_eq!(splits.next().unwrap(),("012","3456789"));
	/*04*/assert_eq!(splits.next().unwrap(),("0123","456789"));
	/*05*/assert_eq!(splits.next().unwrap(),("01234","56789"));
	/*06*/assert_eq!(splits.next().unwrap(),("012345","6789"));
	/*07*/assert_eq!(splits.next().unwrap(),("0123456","789"));
	/*08*/assert_eq!(splits.next().unwrap(),("01234567","89"));
	/*09*/assert_eq!(splits.next().unwrap(),("012345678","9"));
	/*10*/assert_eq!(splits.next().unwrap(),("0123456789",""));
	/*11*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_empty(){
	let mut splits = Splits::from_str("");
	assert!(splits.next().is_none());
}

#[test]
fn test_splits_single(){
	let mut splits = Splits::from_str("a");
	/*01*/assert_eq!(splits.next().unwrap(),("a",""));
	/*02*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char(){
	let mut splits = SplitsChar::from_str("0123456789");
	/*01*/assert_eq!(splits.next().unwrap(),("",'0',"123456789"));
	/*02*/assert_eq!(splits.next().unwrap(),("0",'1',"23456789"));
	/*03*/assert_eq!(splits.next().unwrap(),("01",'2',"3456789"));
	/*04*/assert_eq!(splits.next().unwrap(),("012",'3',"456789"));
	/*05*/assert_eq!(splits.next().unwrap(),("0123",'4',"56789"));
	/*06*/assert_eq!(splits.next().unwrap(),("01234",'5',"6789"));
	/*07*/assert_eq!(splits.next().unwrap(),("012345",'6',"789"));
	/*08*/assert_eq!(splits.next().unwrap(),("0123456",'7',"89"));
	/*09*/assert_eq!(splits.next().unwrap(),("01234567",'8',"9"));
	/*10*/assert_eq!(splits.next().unwrap(),("012345678",'9',""));
	/*11*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_empty(){
	let mut splits = SplitsChar::from_str("");
	assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_single(){
	let mut splits = SplitsChar::from_str("a");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',""));
	/*02*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_two(){
	let mut splits = SplitsChar::from_str("ab");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',"b"));
	/*02*/assert_eq!(splits.next().unwrap(),("a",'b',""));
	/*03*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_three(){
	let mut splits = SplitsChar::from_str("abc");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',"bc"));
	/*02*/assert_eq!(splits.next().unwrap(),("a",'b',"c"));
	/*03*/assert_eq!(splits.next().unwrap(),("ab",'c',""));
	/*04*/assert!(splits.next().is_none());
}
<commit_msg>Removing the str field<commit_after>#![feature(core,str_char)]

extern crate core;

use core::iter::Iterator;

pub struct Splits<'l>{
	begin: &'l str,
	end  : &'l str
}

impl<'l> Splits<'l>{
	pub fn from_str(str: &'l str) -> Self{
		Splits{
			begin: unsafe{str.slice_unchecked(0,0)},
			end  : str
		}
	}
}

impl<'l> Iterator for Splits<'l>{
	type Item = (&'l str,&'l str);

	fn next(&mut self) -> Option<<Self as Iterator>::Item>{
		if self.end.is_empty(){
			None
		}else{
			let head_len = self.end.char_at(0).len_utf8();
			self.begin   = unsafe{self.begin.slice_unchecked(0,self.begin.len() + head_len)};
			self.end     = unsafe{self.end.slice_unchecked(head_len,self.end.len())};

			Some((self.begin,self.end))
		}
	}
}

pub struct SplitsChar<'l>{
	begin: &'l str,
	end  : &'l str
}

impl<'l> SplitsChar<'l>{
	pub fn from_str(str: &'l str) -> Self{
		SplitsChar{
			begin: unsafe{str.slice_unchecked(0,0)},
			end  : str
		}
	}
}

impl<'l> Iterator for SplitsChar<'l>{
	type Item = (&'l str,char,&'l str);

	fn next(&mut self) -> Option<<Self as Iterator>::Item>{
		if self.end.is_empty(){
			None
		}else{
			let c = self.end.char_at(0);
			let c_len = c.len_utf8();

			self.end   = unsafe{self.end.slice_unchecked(c_len,self.end.len())};
			let begin  = self.begin;
			self.begin = unsafe{self.begin.slice_unchecked(0,self.begin.len() + c_len)};

			Some((begin,c,self.end))
		}
	}
}

#[test]
fn test_splits(){
	let mut splits = Splits::from_str("0123456789");
	/*01*/assert_eq!(splits.next().unwrap(),("0","123456789"));
	/*02*/assert_eq!(splits.next().unwrap(),("01","23456789"));
	/*03*/assert_eq!(splits.next().unwrap(),("012","3456789"));
	/*04*/assert_eq!(splits.next().unwrap(),("0123","456789"));
	/*05*/assert_eq!(splits.next().unwrap(),("01234","56789"));
	/*06*/assert_eq!(splits.next().unwrap(),("012345","6789"));
	/*07*/assert_eq!(splits.next().unwrap(),("0123456","789"));
	/*08*/assert_eq!(splits.next().unwrap(),("01234567","89"));
	/*09*/assert_eq!(splits.next().unwrap(),("012345678","9"));
	/*10*/assert_eq!(splits.next().unwrap(),("0123456789",""));
	/*11*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_empty(){
	let mut splits = Splits::from_str("");
	assert!(splits.next().is_none());
}

#[test]
fn test_splits_single(){
	let mut splits = Splits::from_str("a");
	/*01*/assert_eq!(splits.next().unwrap(),("a",""));
	/*02*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char(){
	let mut splits = SplitsChar::from_str("0123456789");
	/*01*/assert_eq!(splits.next().unwrap(),("",'0',"123456789"));
	/*02*/assert_eq!(splits.next().unwrap(),("0",'1',"23456789"));
	/*03*/assert_eq!(splits.next().unwrap(),("01",'2',"3456789"));
	/*04*/assert_eq!(splits.next().unwrap(),("012",'3',"456789"));
	/*05*/assert_eq!(splits.next().unwrap(),("0123",'4',"56789"));
	/*06*/assert_eq!(splits.next().unwrap(),("01234",'5',"6789"));
	/*07*/assert_eq!(splits.next().unwrap(),("012345",'6',"789"));
	/*08*/assert_eq!(splits.next().unwrap(),("0123456",'7',"89"));
	/*09*/assert_eq!(splits.next().unwrap(),("01234567",'8',"9"));
	/*10*/assert_eq!(splits.next().unwrap(),("012345678",'9',""));
	/*11*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_empty(){
	let mut splits = SplitsChar::from_str("");
	assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_single(){
	let mut splits = SplitsChar::from_str("a");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',""));
	/*02*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_two(){
	let mut splits = SplitsChar::from_str("ab");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',"b"));
	/*02*/assert_eq!(splits.next().unwrap(),("a",'b',""));
	/*03*/assert!(splits.next().is_none());
}

#[test]
fn test_splits_char_three(){
	let mut splits = SplitsChar::from_str("abc");
	/*01*/assert_eq!(splits.next().unwrap(),("",'a',"bc"));
	/*02*/assert_eq!(splits.next().unwrap(),("a",'b',"c"));
	/*03*/assert_eq!(splits.next().unwrap(),("ab",'c',""));
	/*04*/assert!(splits.next().is_none());
}
<|endoftext|>


<commit_before>//! Collection traits for generic programming.

#![deny(missing_docs)]
#![feature(set_recovery)]

mod std_impls;

/// A collection.
pub trait Collection {
    /// The type of the collection's items.
    type Item;

    /// Checks if the collection contains zero items.
    ///
    /// This is equivalent to `self.len() == 0`, but may be optimized.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that supports insertion.
pub trait Insert: Collection {
    /// Moves all items from the given collection into the collection.
    fn append(&mut self, other: &mut Self) where Self: Sized;
}

/// A collection that supports removal.
pub trait Remove: Collection {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

pub mod map {
    //! Maps.

    /// A map.
    ///
    /// A map is a collection that associates keys with values, where the keys are distinguished
    /// according to some uniqueness criteria.
    pub trait Map: super::Collection<Item = (<Self as Map>::Key, <Self as Map>::Value)> {
        /// The type of the map's keys.
        type Key;

        /// The type of the map's values.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Map>::Key>: Map {
        /// Checks if the map contains a key that is equivalent to the given key.
        ///
        /// This is equivalent to `self.get(key).is_some()`, but may be optimized.
        fn contains_key(&self, key: &Q) -> bool {
            self.get(key).is_some()
        }

        /// Returns a reference to the value in the map whose key is equivalent to the given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;

        /// Returns a mutable reference to the value in the map whose key is equivalent to the
        /// given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Map>::Key>: Get<Q> + super::Remove {
        /// Removes the key in the map that is equivalent to the given key and returns its value.
        ///
        /// Returns `None` if the map contains no such key.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Map + super::Insert {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map that supports efficient in-place modification.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Insert + Remove {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Map = Self>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Map = Self>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a>: Sized {
        /// The entry's map type.
        type Map: ?Sized + EntryMap<'a, OccupiedEntry = Self>;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &<Self::Map as Map>::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut <Self::Map as Map>::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> <Self::Map as Map>::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a>: Sized {
        /// The entry's map type.
        type Map: ?Sized + EntryMap<'a, VacantEntry = Self>;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<'a, M: ?Sized + EntryMap<'a>> {
        /// An occupied map entry.
        Occupied(M::OccupiedEntry),
        /// A vacant map entry.
        Vacant(M::VacantEntry),
    }

    impl<'a, M: ?Sized + EntryMap<'a>> Entry<'a, M> {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: M::Value) -> &'a mut M::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F: FnOnce() -> M::Value>(self, f: F) -> &'a mut M::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }
}

pub mod seq {
    //! Sequences.

    /// A sequence that supports insertion.
    pub trait PushBack: super::Insert {
        /// Pushes the given item onto the back of the sequence.
        fn push_back(&mut self, item: Self::Item);
    }

    /// A queue.
    pub trait Queue: PushBack + super::Remove {
        /// Returns a reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn pop_front(&mut self) -> Option<Self::Item>;
    }

    /// A stack.
    pub trait Stack: PushBack + super::Remove {
        /// Returns a reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn pop_back(&mut self) -> Option<Self::Item>;
    }

    /// A deque (double-ended queue).
    pub trait Deque: Queue + Stack {
        /// Pushes the given item onto the front of the deque.
        fn push_front(&mut self, item: Self::Item);
    }
}

pub mod set {
    //! Sets.

    use super::Collection;

    /// A set.
    ///
    /// A set is a collection whose items are distinguished according to some uniqueness criteria.
    pub trait Set: Collection {
        /// Checks if the set is disjoint from the given set.
        fn is_disjoint(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a subset of the given set.
        fn is_subset(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a superset of the given set.
        fn is_superset(&self, other: &Self) -> bool where Self: Sized {
            other.is_subset(self)
        }
    }

    /// A set that supports retrievals using items of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Collection>::Item>: Set {
        /// Checks if the set contains an item that is equivalent to the given item.
        ///
        /// This is equivalent to `self.get(item).is_some()`, but may be optimized.
        fn contains(&self, item: &Q) -> bool {
            self.get(item).is_some()
        }

        /// Returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contains no such item.
        fn get(&self, item: &Q) -> Option<&Self::Item>;
    }

    /// A set that supports removal using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Collection>::Item>: Get<Q> + super::Remove {
        /// Removes the item in the set that is equivalent to the given item.
        ///
        /// Returns `true` if the set contained such an item, `false` otherwise.
        ///
        /// This is equivalent to `self.take(item).is_some()`, but may be optimized.
        fn remove(&mut self, item: &Q) -> bool {
            self.take(item).is_some()
        }

        /// Removes and returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contained no such item.
        fn take(&mut self, item: &Q) -> Option<Self::Item>;
    }

    /// A set that supports insertion.
    pub trait Insert: Set + super::Insert {
        /// Inserts the given item into the set without replacement.
        ///
        /// Returns `true` if the set contained an equivalent item, `false` otherwise.
        fn insert(&mut self, item: Self::Item) -> bool;

        /// Inserts the given item into the set with replacement.
        ///
        /// Returns the equivalent item if the set contained one, `None` otherwise.
        fn replace(&mut self, item: Self::Item) -> Option<Self::Item>;
    }
}
<commit_msg>Add object safety tests<commit_after>//! Collection traits for generic programming.

#![deny(missing_docs)]
#![feature(set_recovery)]

mod std_impls;

/// A collection.
pub trait Collection {
    /// The type of the collection's items.
    type Item;

    /// Checks if the collection contains zero items.
    ///
    /// This is equivalent to `self.len() == 0`, but may be optimized.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A collection that supports insertion.
pub trait Insert: Collection {
    /// Moves all items from the given collection into the collection.
    fn append(&mut self, other: &mut Self) where Self: Sized;
}

/// A collection that supports removal.
pub trait Remove: Collection {
    /// Removes all items from the collection.
    fn clear(&mut self);
}

#[test]
fn test_object_safety() {
    let _: &Collection<Item = i32>;
    let _: &Remove<Item = i32>;
    let _: &Insert<Item = i32>;
}

pub mod map {
    //! Maps.

    /// A map.
    ///
    /// A map is a collection that associates keys with values, where the keys are distinguished
    /// according to some uniqueness criteria.
    pub trait Map: super::Collection<Item = (<Self as Map>::Key, <Self as Map>::Value)> {
        /// The type of the map's keys.
        type Key;

        /// The type of the map's values.
        type Value;
    }

    /// A map that supports lookups using keys of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Map>::Key>: Map {
        /// Checks if the map contains a key that is equivalent to the given key.
        ///
        /// This is equivalent to `self.get(key).is_some()`, but may be optimized.
        fn contains_key(&self, key: &Q) -> bool {
            self.get(key).is_some()
        }

        /// Returns a reference to the value in the map whose key is equivalent to the given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get(&self, key: &Q) -> Option<&Self::Value>;

        /// Returns a mutable reference to the value in the map whose key is equivalent to the
        /// given key.
        ///
        /// Returns `None` if the map contains no such key.
        fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;
    }

    /// A map that supports removals using keys of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Map>::Key>: Get<Q> + super::Remove {
        /// Removes the key in the map that is equivalent to the given key and returns its value.
        ///
        /// Returns `None` if the map contains no such key.
        fn remove(&mut self, key: &Q) -> Option<Self::Value>;
    }

    /// A map that supports insertion.
    pub trait Insert: Map + super::Insert {
        /// Inserts the given key and value into the map and returns the previous value
        /// corresponding to the given key, if any.
        fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
    }

    /// A map that supports efficient in-place modification.
    ///
    /// `'a` is the lifetime of the map.
    pub trait EntryMap<'a>: Insert + Remove {
        /// The type of the map's occupied entries.
        type OccupiedEntry: OccupiedEntry<'a, Map = Self>;

        /// The type of the map's vacant entries.
        type VacantEntry: VacantEntry<'a, Map = Self>;

        /// Returns the entry in the map corresponding to the given key.
        fn entry(&'a mut self, key: Self::Key) -> Entry<Self>;
    }

    /// An occupied map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait OccupiedEntry<'a>: Sized {
        /// The entry's map type.
        type Map: ?Sized + EntryMap<'a, OccupiedEntry = Self>;

        /// Returns a reference to the entry's value.
        fn get(&self) -> &<Self::Map as Map>::Value;

        /// Returns a mutable reference to the entry's value.
        fn get_mut(&mut self) -> &mut <Self::Map as Map>::Value;

        /// Returns a mutable reference to the entry's value with the same lifetime as the map.
        fn into_mut(self) -> &'a mut <Self::Map as Map>::Value;

        /// Replaces the entry's value with the given one and returns the old value.
        fn insert(&mut self, value: <Self::Map as Map>::Value) -> <Self::Map as Map>::Value {
            ::std::mem::replace(self.get_mut(), value)
        }

        /// Removes the entry from the map and returns its value.
        fn remove(self) -> <Self::Map as Map>::Value;
    }

    /// A vacant map entry.
    ///
    /// `'a` is the lifetime of the map.
    pub trait VacantEntry<'a>: Sized {
        /// The entry's map type.
        type Map: ?Sized + EntryMap<'a, VacantEntry = Self>;

        /// Inserts the entry into the map with the given value and returns a mutable reference to
        /// it with the same lifetime as the map.
        fn insert(self, value: <Self::Map as Map>::Value) -> &'a mut <Self::Map as Map>::Value;
    }

    /// A map entry.
    #[derive(Debug)]
    pub enum Entry<'a, M: ?Sized + EntryMap<'a>> {
        /// An occupied map entry.
        Occupied(M::OccupiedEntry),
        /// A vacant map entry.
        Vacant(M::VacantEntry),
    }

    impl<'a, M: ?Sized + EntryMap<'a>> Entry<'a, M> {
        /// Ensures the entry is occupied by inserting it with the given default value if it is
        /// vacant.
        pub fn or_insert(self, default: M::Value) -> &'a mut M::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(default),
            }
        }

        /// Ensures the entry is occupied by inserting it with the result of the given function if
        /// it is vacant.
        pub fn or_insert_with<F: FnOnce() -> M::Value>(self, f: F) -> &'a mut M::Value {
            match self {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(f()),
            }
        }
    }

    #[cfg(test)]
    pub fn count<M, I>(items: I) -> M
    where
        M: Default + for<'a> EntryMap<'a, Value = usize>,
        I: IntoIterator<Item = M::Key>,
    {
        let mut map = M::default();
        for item in items { *map.entry(item).or_insert(0) += 1; }
        map
    }

    #[test]
    fn test_object_safety() {
        let _: &Map<Item = (i32, char), Key = i32, Value = char>;
        let _: &Get<i32, Item = (i32, char), Key = i32, Value = char>;
        let _: &Remove<i32, Item = (i32, char), Key = i32, Value = char>;
        let _: &Insert<Item = (i32, char), Key = i32, Value = char>;
    }
}

pub mod seq {
    //! Sequences.

    /// A sequence that supports insertion.
    pub trait PushBack: super::Insert {
        /// Pushes the given item onto the back of the sequence.
        fn push_back(&mut self, item: Self::Item);
    }

    /// A queue.
    pub trait Queue: PushBack + super::Remove {
        /// Returns a reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn front_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the front of the queue.
        ///
        /// Returns `None` if the queue is empty.
        fn pop_front(&mut self) -> Option<Self::Item>;
    }

    /// A stack.
    pub trait Stack: PushBack + super::Remove {
        /// Returns a reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back(&self) -> Option<&Self::Item>;

        /// Returns a mutable reference to the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn back_mut(&mut self) -> Option<&mut Self::Item>;

        /// Removes and returns the item at the back of the stack.
        ///
        /// Returns `None` if the stack is empty.
        fn pop_back(&mut self) -> Option<Self::Item>;
    }

    /// A deque (double-ended queue).
    pub trait Deque: Queue + Stack {
        /// Pushes the given item onto the front of the deque.
        fn push_front(&mut self, item: Self::Item);
    }

    #[test]
    fn test_object_safety() {
        let _: &PushBack<Item = i32>;
        let _: &Queue<Item = i32>;
        let _: &Stack<Item = i32>;
        let _: &Deque<Item = i32>;
    }
}

pub mod set {
    //! Sets.

    use super::Collection;

    /// A set.
    ///
    /// A set is a collection whose items are distinguished according to some uniqueness criteria.
    pub trait Set: Collection {
        /// Checks if the set is disjoint from the given set.
        fn is_disjoint(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a subset of the given set.
        fn is_subset(&self, other: &Self) -> bool where Self: Sized;

        /// Checks if the set is a superset of the given set.
        fn is_superset(&self, other: &Self) -> bool where Self: Sized {
            other.is_subset(self)
        }
    }

    /// A set that supports retrievals using items of type `&Q`.
    pub trait Get<Q: ?Sized = <Self as Collection>::Item>: Set {
        /// Checks if the set contains an item that is equivalent to the given item.
        ///
        /// This is equivalent to `self.get(item).is_some()`, but may be optimized.
        fn contains(&self, item: &Q) -> bool {
            self.get(item).is_some()
        }

        /// Returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contains no such item.
        fn get(&self, item: &Q) -> Option<&Self::Item>;
    }

    /// A set that supports removal using items of type `&Q`.
    pub trait Remove<Q: ?Sized = <Self as Collection>::Item>: Get<Q> + super::Remove {
        /// Removes the item in the set that is equivalent to the given item.
        ///
        /// Returns `true` if the set contained such an item, `false` otherwise.
        ///
        /// This is equivalent to `self.take(item).is_some()`, but may be optimized.
        fn remove(&mut self, item: &Q) -> bool {
            self.take(item).is_some()
        }

        /// Removes and returns the item in the set that is equivalent to the given item.
        ///
        /// Returns `None` if the set contained no such item.
        fn take(&mut self, item: &Q) -> Option<Self::Item>;
    }

    /// A set that supports insertion.
    pub trait Insert: Set + super::Insert {
        /// Inserts the given item into the set without replacement.
        ///
        /// Returns `true` if the set contained an equivalent item, `false` otherwise.
        fn insert(&mut self, item: Self::Item) -> bool;

        /// Inserts the given item into the set with replacement.
        ///
        /// Returns the equivalent item if the set contained one, `None` otherwise.
        fn replace(&mut self, item: Self::Item) -> Option<Self::Item>;
    }

    #[test]
    fn test_object_safety() {
        let _: &Set<Item = i32>;
        let _: &Get<i32, Item = i32>;
        let _: &Remove<i32, Item = i32>;
        let _: &Insert<Item = i32>;
    }
}
<|endoftext|>


<commit_before>use std::io::{IoError, IoErrorKind, Reader};

struct MetadataBlock;
struct Frame;

// TODO: there should be a way to signal IO error.
// This will be handled by the error reform RFCs, I think.
// For now, use IO error to indicate any failure.
type Error = IoError;

fn mk_err() -> Error {
    IoError {
        kind: IoErrorKind::OtherIoError,
        desc: "FLAC decoding error",
        detail: None
    }
}

struct FlacStream {
    metadata_blocks: Vec<MetadataBlock>
}

const HEADER: u32 = 0x66_4c_61_43; // The header 'fLaC' (big endian).

impl FlacStream {
    pub fn new(input: &mut Reader) -> Result<FlacStream, Error> {
        // A FLAC stream starts with a 32-bit header.
        let header = try!(input.read_be_u32());
        if header != HEADER { return Err(mk_err()); }

        // Read the STREAMINFO block
        // Read any metadata
        // Read frames

        let flac_stream = FlacStream {
            metadata_blocks: Vec::new()
        };

        Ok(flac_stream)
    }
}

#[test]
fn read_header() {
    use std::io::fs::File;
    let mut input = File::open(&Path::new("foo.flac")).unwrap();
    let flac_stream = FlacStream::new(&mut input).unwrap();
}
<commit_msg>refactor reading header<commit_after>use std::io::{IoError, IoErrorKind, Reader};
use std::io::fs::File;

struct MetadataBlock;
struct Frame;

// TODO: there should be a way to signal IO error.
// This will be handled by the error reform RFCs, I think.
// For now, use IO error to indicate any failure.
type Error = IoError;

fn mk_err() -> Error {
    IoError {
        kind: IoErrorKind::OtherIoError,
        desc: "FLAC decoding error",
        detail: None
    }
}

struct FlacStream {
    metadata_blocks: Vec<MetadataBlock>
}

#[cfg(test)]
fn get_foo_file() -> File {
    File::open(&Path::new("foo.flac")).unwrap()
}

fn read_header(input: &mut Reader) -> Result<(), Error> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER { return Err(mk_err()); } // TODO: provide more error info.
    Ok(())
}

#[test]
fn test_read_header() {
    let mut input = get_foo_file();
    read_header(&mut input).unwrap();
}

impl FlacStream {
    pub fn new(input: &mut Reader) -> Result<FlacStream, Error> {
        let _ = try!(read_header(input));
        // Read the STREAMINFO block
        // Read any metadata
        // Read frames

        let flac_stream = FlacStream {
            metadata_blocks: Vec::new()
        };

        Ok(flac_stream)
    }
}

#[test]
fn test_open_stream() {
    let mut input = get_foo_file();
    let flac_stream = FlacStream::new(&mut input).unwrap();
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;

#[cfg(test)]
mod tests;

pub type CowStr<'a> = Cow<'a, String, str>;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowStr<'a>, CowStr<'a>>,
    pub prefix: Option<CowStr<'a>>,
    pub command: Option<CowStr<'a>>,
    pub params: Vec<CowStr<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = line.slice_to(n);

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, line.slice_from(p))
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    line.slice_from(p)
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowStr<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(line.slice_from(1));
        let mut raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(line.slice_from(1));
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(rest.slice_from(1)));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<commit_msg>Use std::string::CowString type<commit_after>#![allow(dead_code)]
use std::collections::hash_map::HashMap;
use std::borrow::Cow;
use std::string::CowString;

#[cfg(test)]
mod tests;

#[derive(Debug)]
pub struct IrcMessage<'a> {
    pub tags: HashMap<CowString<'a>, CowString<'a>>,
    pub prefix: Option<CowString<'a>>,
    pub command: Option<CowString<'a>>,
    pub params: Vec<CowString<'a>>
}

impl <'b> IrcMessage<'b> {
    pub fn new_empty<'a>() -> IrcMessage<'a> {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }

    /// Parse a message from a string to an owned `IrcMessage`.
    pub fn parse_owned<'a>(s: &'a str) -> Result<IrcMessage<'static>, ()> {
        return parse_owned(s);
    }

    /// Parse a message from a string to an `IrcMessage` that still refers
    /// to the original `str`.  Useful for minimizing allocations.
    pub fn parse_slice<'a>(s: &'a str) -> Result<IrcMessage<'a>, ()> {
        return parse_slice(s);
    }
}

fn next_segment<'a>(line: &'a str) -> (&'a str, &'a str) {
    match line.find(' ') {
        Some(n) => {
            if line.len() == 0 {
                return (line, line);
            }
            let segment = line.slice_to(n);

            let mut p = n;

            while line.char_at(p) == ' ' && p < line.len() - 1 {
                p += 1;
            }

            (segment, line.slice_from(p))
        },
        None => (line, "")
    }
}

fn trim_space<'a>(line: &'a str) -> &'a str {
    if line.len() == 0 {
        return line;
    }

    let mut p = 0;
    while line.char_at(p) == ' ' && p < line.len() - 1 {
        p += 1;
    }

    line.slice_from(p)
}

fn parse_owned<'a>(line: &'a str) -> Result<IrcMessage<'static>, ()> {
    parse_into(line, |a| Cow::Owned(a.to_string()))
}

fn parse_slice<'a>(line: &'a str) -> Result<IrcMessage<'a>, ()> {
    parse_into(line, |a| Cow::Borrowed(a))
}

fn parse_into<'a, 'b, F>(line: &'a str, wrap: F) -> Result<IrcMessage<'b>, ()>
where F: Fn(&'a str) -> CowString<'b> {
    let mut message = IrcMessage::new_empty();

    // TAGS
    let line = if line.char_at(0) == '@' {
        let (tags, rest) = next_segment(line.slice_from(1));
        let mut raw_tags = tags.split(';');
        for tag in raw_tags {
            println!("{}", tag);
            if tag.contains_char('=') {
                let mut pair = tag.split('=');
                message.tags.insert(wrap(pair.next().unwrap()), wrap(pair.next().unwrap()));
            } else {
                message.tags.insert(wrap(tag), wrap("true"));
            }
        }
        rest
    } else {
        line
    };

    // PREFIX
    let line = if line.char_at(0) == ':' {
        let (prefix, rest) = next_segment(line.slice_from(1));
        message.prefix = Some(wrap(prefix));
        rest
    } else {
        line
    };

    // COMMAND
    let (command, line) = next_segment(line);
    message.command = Some(wrap(command));

    // PARAMS
    let mut rest = trim_space(line);
    while !rest.is_empty() {
        match next_segment(rest) {
            ("", _) => {
                break;
            }
            (_, _) if rest.char_at(0) == ':' => {
                message.params.push(wrap(rest.slice_from(1)));
                break;
            }
            (last, "") => {
                message.params.push(wrap(last));
                break;
            }
            (next, tail) => {
                message.params.push(wrap(next));
                rest = tail;
            }
        }
    }

    return Ok(message);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
extern crate num_traits;
#[cfg(test)]
use std as core;

pub use angle::Angle;
pub use box2d::Box2D;
pub use length::Length;
pub use scale::Scale;
pub use transform2d::Transform2D;
pub use transform3d::Transform3D;
pub use point::{Point2D, Point3D, point2, point3};
pub use vector::{Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;
pub use nonempty::NonEmpty;

pub use rect::{rect, Rect};
pub use rigid::{RigidTransform3D};
pub use box3d::{box3d, Box3D};
pub use translation::{Translation2D, Translation3D};
pub use rotation::{Rotation2D, Rotation3D};
pub use side_offsets::SideOffsets2D;
pub use size::{Size2D, Size3D, size2, size3};
pub use trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<commit_msg>Add Length to defaults<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
extern crate num_traits;
#[cfg(test)]
use std as core;

pub use angle::Angle;
pub use box2d::Box2D;
pub use length::Length;
pub use scale::Scale;
pub use transform2d::Transform2D;
pub use transform3d::Transform3D;
pub use point::{Point2D, Point3D, point2, point3};
pub use vector::{Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;
pub use nonempty::NonEmpty;

pub use rect::{rect, Rect};
pub use rigid::{RigidTransform3D};
pub use box3d::{box3d, Box3D};
pub use translation::{Translation2D, Translation3D};
pub use rotation::{Rotation2D, Rotation3D};
pub use side_offsets::SideOffsets2D;
pub use size::{Size2D, Size3D, size2, size3};
pub use trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Length<T> = super::Length<T, UnknownUnit>;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use env::Env;
use library;
use nameutil;
use super::ffi_type::*;
use traits::*;

pub fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, classes: &[&library::Class]) -> Result<()> {
    for klass in classes {
        try!(generate_object_funcs(w, env, &klass.c_type,
            &klass.glib_get_type, &klass.functions));
    }

    Ok(())
}

pub fn generate_interfaces_funcs<W: Write>(w: &mut W, env: &Env, interfaces: &[&library::Interface]) -> Result<()> {
    for interface in interfaces {
        try!(generate_object_funcs(w, env,  &interface.c_type,
            &interface.glib_get_type, &interface.functions));
    }

    Ok(())
}

pub fn generate_other_funcs<W: Write>(w: &mut W, env: &Env, functions: &[library::Function]) -> Result<()> {
    generate_object_funcs(w, env,  "Other functions", "intern", functions)
}

fn generate_object_funcs<W: Write>(w: &mut W, env: &Env, c_type: &str,
    glib_get_type: &str, functions: &[library::Function]) -> Result<()> {
    let write_get_type = glib_get_type != "intern";
    if write_get_type || !functions.is_empty() {
        try!(writeln!(w, ""));
        try!(writeln!(w, "    //========================================================================="));
        try!(writeln!(w, "    // {}", c_type));
        try!(writeln!(w, "    //========================================================================="));
    }
    if write_get_type {
        try!(writeln!(w, "    pub fn {:<36}() -> GType;", glib_get_type));
    }

    for func in functions {
        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "    {}pub fn {:<36}{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn generate_callbacks<W: Write>(w: &mut W, env: &Env, callbacks: &[&library::Function]) -> Result<()> {
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "{}pub type {} = unsafe extern \"C\" fn{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    (commented, format!("({}){}", parameter_strs.connect(", "), ret_str))
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let &library::Type::Fundamental(library::Fundamental::VarArgs) = env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.as_str().into()
    }
    else {
        format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.as_str())
    };
    (commented, res)
}
<commit_msg>Made const "intern"<commit_after>use std::io::{Result, Write};

use env::Env;
use library;
use nameutil;
use super::ffi_type::*;
use traits::*;

//used as glib:get-type in GLib-2.0.gir
const INTERN: &'static str= "intern";

pub fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, classes: &[&library::Class]) -> Result<()> {
    for klass in classes {
        try!(generate_object_funcs(w, env, &klass.c_type,
            &klass.glib_get_type, &klass.functions));
    }

    Ok(())
}

pub fn generate_interfaces_funcs<W: Write>(w: &mut W, env: &Env, interfaces: &[&library::Interface]) -> Result<()> {
    for interface in interfaces {
        try!(generate_object_funcs(w, env,  &interface.c_type,
            &interface.glib_get_type, &interface.functions));
    }

    Ok(())
}

pub fn generate_other_funcs<W: Write>(w: &mut W, env: &Env, functions: &[library::Function]) -> Result<()> {
    generate_object_funcs(w, env,  "Other functions", INTERN, functions)
}

fn generate_object_funcs<W: Write>(w: &mut W, env: &Env, c_type: &str,
    glib_get_type: &str, functions: &[library::Function]) -> Result<()> {
    let write_get_type = glib_get_type != INTERN;
    if write_get_type || !functions.is_empty() {
        try!(writeln!(w, ""));
        try!(writeln!(w, "    //========================================================================="));
        try!(writeln!(w, "    // {}", c_type));
        try!(writeln!(w, "    //========================================================================="));
    }
    if write_get_type {
        try!(writeln!(w, "    pub fn {:<36}() -> GType;", glib_get_type));
    }

    for func in functions {
        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "    {}pub fn {:<36}{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn generate_callbacks<W: Write>(w: &mut W, env: &Env, callbacks: &[&library::Function]) -> Result<()> {
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "{}pub type {} = unsafe extern \"C\" fn{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    (commented, format!("({}){}", parameter_strs.connect(", "), ret_str))
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let &library::Type::Fundamental(library::Fundamental::VarArgs) = env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.as_str().into()
    }
    else {
        format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.as_str())
    };
    (commented, res)
}
<|endoftext|>


<commit_before>pub mod lines;

#[macro_use]
extern crate nom;

extern crate regex;
extern crate memmap;
extern crate memchr;
extern crate ascii;

use std::path::Path;
use std::cmp;
use std::fmt;

use memmap::{Mmap, Protection};
use memchr::memchr;

// Why is it called partialEq?
#[derive(Debug, PartialEq, Default, Clone)]
pub struct Count {
    pub code: u32,
    pub comment: u32,
    pub blank: u32,
    pub lines: u32,
}

impl Count {
    pub fn merge(&mut self, o: &Count) {
        self.code += o.code;
        self.comment += o.comment;
        self.blank += o.blank;
        self.lines += o.lines;
    }
}

pub enum LineConfig<'a> {
    Multi {
        single_start: &'a str,
        multi_start: &'a str,
        multi_end: &'a str,
    },
    Single {
        single_start: &'a str,
    },
}

// Do any languages actually use utf8 chars as comment chars?
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
pub enum Lang {
    C,
    CCppHeader,
    Rust,
    Ruby,
    Haskell,
    Perl,
    BourneShell,
    Make,
    INI,
    Assembly,
    Yacc,
    Awk,
    Unrecognized,
}

impl Lang {
    pub fn to_s(&self) -> &str {
        match *self {
            Lang::C => "C",
            Lang::CCppHeader => "C/C++ Header",
            Lang::Rust => "Rust",
            Lang::Ruby => "Ruby",
            Lang::Haskell => "Haskell",
            Lang::Perl => "Perl",
            Lang::BourneShell => "Bourne Shell",
            Lang::Make => "Make",
            Lang::INI => "INI",
            Lang::Assembly => "Assembly",
            Lang::Yacc => "Yacc",
            Lang::Awk => "Awk",
            Lang::Unrecognized => "Unrecognized",
        }
    }
}

impl fmt::Display for Lang {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(self.to_s())
    }
}

pub fn lang_from_ext(filepath: &str) -> Lang {
    let path = Path::new(filepath);
    let ext = match path.extension() {
        Some(os_str) => os_str.to_str().unwrap().to_lowercase(),
        None => path.file_name().unwrap().to_str().unwrap().to_lowercase(),
    };

    match &*ext {
        "c" => Lang::C,
        "h" | "hh" | "hpp" | "hxx" => Lang::CCppHeader,
        "rs" => Lang::Rust,
        "hs" => Lang::Haskell,
        "pl" => Lang::Perl,
        "rb" => Lang::Ruby,
        "makefile" | "mk" => Lang::Make,
        "ini" => Lang::INI,
        "s" | "asm" => Lang::Assembly,
        "y" => Lang::Yacc,
        "awk" => Lang::Awk,

        // TODO(cgag): What's the correct extension? Any? Pragma?
        "sh" => Lang::BourneShell,
        // Probably dumb to just default to C.
        _ => Lang::Unrecognized,
    }
}

pub fn counter_config_for_lang<'a>(lang: &Lang) -> LineConfig<'a> {
    enum CT<'a> {
        Single(&'a str),
        Multi(&'a str, &'a str, &'a str),
    }
    // use self::ConfigTuple::*;

    let c_style = CT::Multi("//", "/*", "*/");
    let sh_style = CT::Single("#");

    let ctuple = match *lang {
        Lang::Haskell => CT::Multi("--", "{-", "-}"),
        Lang::Perl => CT::Multi("#", "=pod", "=cut"),
        Lang::INI => CT::Single(";"),
        // TODO(cgag): Well, some architectures use ;, @, |, etc.
        // Need a way to specify more than one possible comment char.
        Lang::Assembly => CT::Multi("#", "/*", "*/"),
        Lang::BourneShell | Lang::Ruby | Lang::Make | Lang::Awk => sh_style,
        // TODO(cgag): not 100% that yacc belongs here.
        Lang::C | Lang::CCppHeader | Lang::Rust | Lang::Yacc => c_style,
        // Default to C style
        Lang::Unrecognized => c_style,
    };

    match ctuple {
        CT::Multi(single, start, end) => {
            LineConfig::Multi {
                single_start: single,
                multi_start: start,
                multi_end: end,
            }
        }
        CT::Single(single) => LineConfig::Single { single_start: single },
    }
}

struct AsciiLines<'a> {
    buf: &'a [u8],
    pos: usize,
}

struct Ascii<'a>(&'a [u8]);
impl<'a> Ascii<'a> {
    fn lines(&self) -> AsciiLines {
        AsciiLines {
            buf: self.0,
            pos: 0,
        }
    }
}

// Appears to work, now we just neeed
impl<'a> Iterator for AsciiLines<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        match memchr(b'\n', &self.buf[self.pos..self.buf.len()]) {
            Some(n) => {
                let start = self.pos;
                self.pos = self.pos + n + 1;
                // - 1 to drop \n char
                Some(&self.buf[start..(self.pos - 1)])
            }
            None => {
                if self.pos == self.buf.len() {
                    return None;
                }
                let start = self.pos;
                self.pos = self.buf.len();
                Some(&self.buf[start..self.pos])
            }
        }
    }
}

pub fn count(filepath: &str) -> Count {
    let lang = lang_from_ext(filepath);
    let config = counter_config_for_lang(&lang);
    match config {
        LineConfig::Single { single_start: single } => count_mmap_unsafe_single(filepath, single),
        LineConfig::Multi { single_start: single, multi_start, multi_end } => {
            count_mmap_unsafe_multi(filepath, single, multi_start, multi_end)
        }
    }
}

pub fn count_mmap_unsafe_single(filepath: &str, single_start: &str) -> Count {
    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
        } else if trimmed.starts_with(single_start) {
            comments += 1;
        } else {
            code += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}

pub fn count_mmap_unsafe_multi(filepath: &str,
                               single_start: &str,
                               multi_start: &str,
                               multi_end: &str)
                               -> Count {

    let single_line_start = single_start;
    let multiline_start = multi_start;
    let multiline_end = multi_end;

    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let mut in_comment = false;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
            continue;
        };

        if !in_comment && trimmed.starts_with(single_line_start) {
            comments += 1;
            continue;
        }

        if !(trimmed.contains(multiline_start) || trimmed.contains(multiline_end)) {
            if in_comment {
                comments += 1;
            } else {
                code += 1;
            }
            continue;
        }

        let mut pos = 0;
        let mut found_code = false;

        let start_len = multiline_start.len();
        let end_len = multiline_end.len();

        'outer: while pos < trimmed.len() {
            // TODO(cgag): must be a less stupid way to do this
            for i in pos..(pos + cmp::max(start_len, end_len) + 1) {
                if !trimmed.is_char_boundary(i) {
                    pos += 1;
                    continue 'outer;
                }
            }

            if pos + start_len <= trimmed.len() &&
               &trimmed[pos..pos + start_len] == multiline_start {
                pos += start_len;
                in_comment = true;
            } else if pos + end_len <= trimmed.len() && &trimmed[pos..pos + end_len] == multiline_end {
                pos += end_len;
                in_comment = false;
            } else if !in_comment {
                found_code = true;
                pos += 1;
            } else {
                pos += 1;
            }
        }

        if found_code {
            code += 1;
        } else {
            comments += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}
<commit_msg>use safe uf8 conversion. Got bit by the c with the squiggle<commit_after>pub mod lines;

#[macro_use]
extern crate nom;

extern crate regex;
extern crate memmap;
extern crate memchr;
extern crate ascii;

use std::path::Path;
use std::cmp;
use std::fmt;

use memmap::{Mmap, Protection};
use memchr::memchr;

// Why is it called partialEq?
#[derive(Debug, PartialEq, Default, Clone)]
pub struct Count {
    pub code: u32,
    pub comment: u32,
    pub blank: u32,
    pub lines: u32,
}

impl Count {
    pub fn merge(&mut self, o: &Count) {
        self.code += o.code;
        self.comment += o.comment;
        self.blank += o.blank;
        self.lines += o.lines;
    }
}

pub enum LineConfig<'a> {
    Multi {
        single_start: &'a str,
        multi_start: &'a str,
        multi_end: &'a str,
    },
    Single {
        single_start: &'a str,
    },
}

// Do any languages actually use utf8 chars as comment chars?
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
pub enum Lang {
    C,
    CCppHeader,
    Rust,
    Ruby,
    Haskell,
    Perl,
    BourneShell,
    Make,
    INI,
    Assembly,
    Yacc,
    Awk,
    Unrecognized,
}

impl Lang {
    pub fn to_s(&self) -> &str {
        match *self {
            Lang::C => "C",
            Lang::CCppHeader => "C/C++ Header",
            Lang::Rust => "Rust",
            Lang::Ruby => "Ruby",
            Lang::Haskell => "Haskell",
            Lang::Perl => "Perl",
            Lang::BourneShell => "Bourne Shell",
            Lang::Make => "Make",
            Lang::INI => "INI",
            Lang::Assembly => "Assembly",
            Lang::Yacc => "Yacc",
            Lang::Awk => "Awk",
            Lang::Unrecognized => "Unrecognized",
        }
    }
}

impl fmt::Display for Lang {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(self.to_s())
    }
}

pub fn lang_from_ext(filepath: &str) -> Lang {
    let path = Path::new(filepath);
    let ext = match path.extension() {
        Some(os_str) => os_str.to_str().unwrap().to_lowercase(),
        None => path.file_name().unwrap().to_str().unwrap().to_lowercase(),
    };

    match &*ext {
        "c" => Lang::C,
        "h" | "hh" | "hpp" | "hxx" => Lang::CCppHeader,
        "rs" => Lang::Rust,
        "hs" => Lang::Haskell,
        "pl" => Lang::Perl,
        "rb" => Lang::Ruby,
        "makefile" | "mk" => Lang::Make,
        "ini" => Lang::INI,
        "s" | "asm" => Lang::Assembly,
        "y" => Lang::Yacc,
        "awk" => Lang::Awk,

        // TODO(cgag): What's the correct extension? Any? Pragma?
        "sh" => Lang::BourneShell,
        // Probably dumb to just default to C.
        _ => Lang::Unrecognized,
    }
}

pub fn counter_config_for_lang<'a>(lang: &Lang) -> LineConfig<'a> {
    enum CT<'a> {
        Single(&'a str),
        Multi(&'a str, &'a str, &'a str),
    }
    // use self::ConfigTuple::*;

    let c_style = CT::Multi("//", "/*", "*/");
    let sh_style = CT::Single("#");

    let ctuple = match *lang {
        Lang::Haskell => CT::Multi("--", "{-", "-}"),
        Lang::Perl => CT::Multi("#", "=pod", "=cut"),
        Lang::INI => CT::Single(";"),
        // TODO(cgag): Well, some architectures use ;, @, |, etc.
        // Need a way to specify more than one possible comment char.
        Lang::Assembly => CT::Multi("#", "/*", "*/"),
        Lang::BourneShell | Lang::Ruby | Lang::Make | Lang::Awk => sh_style,
        // TODO(cgag): not 100% that yacc belongs here.
        Lang::C | Lang::CCppHeader | Lang::Rust | Lang::Yacc => c_style,
        // Default to C style
        Lang::Unrecognized => c_style,
    };

    match ctuple {
        CT::Multi(single, start, end) => {
            LineConfig::Multi {
                single_start: single,
                multi_start: start,
                multi_end: end,
            }
        }
        CT::Single(single) => LineConfig::Single { single_start: single },
    }
}

struct AsciiLines<'a> {
    buf: &'a [u8],
    pos: usize,
}

struct Ascii<'a>(&'a [u8]);
impl<'a> Ascii<'a> {
    fn lines(&self) -> AsciiLines {
        AsciiLines {
            buf: self.0,
            pos: 0,
        }
    }
}

// Appears to work, now we just neeed
impl<'a> Iterator for AsciiLines<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        match memchr(b'\n', &self.buf[self.pos..self.buf.len()]) {
            Some(n) => {
                let start = self.pos;
                self.pos = self.pos + n + 1;
                // - 1 to drop \n char
                Some(&self.buf[start..(self.pos - 1)])
            }
            None => {
                if self.pos == self.buf.len() {
                    return None;
                }
                let start = self.pos;
                self.pos = self.buf.len();
                Some(&self.buf[start..self.pos])
            }
        }
    }
}

pub fn count(filepath: &str) -> Count {
    let lang = lang_from_ext(filepath);
    let config = counter_config_for_lang(&lang);
    match config {
        LineConfig::Single { single_start: single } => count_mmap_unsafe_single(filepath, single),
        LineConfig::Multi { single_start: single, multi_start, multi_end } => {
            count_mmap_unsafe_multi(filepath, single, multi_start, multi_end)
        }
    }
}

pub fn count_mmap_unsafe_single(filepath: &str, single_start: &str) -> Count {
    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        // let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        let line = match std::str::from_utf8(byte_line) {
            Ok(s) => s,
            Err(_) => return Count::default(),
        };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
        } else if trimmed.starts_with(single_start) {
            comments += 1;
        } else {
            code += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}

pub fn count_mmap_unsafe_multi(filepath: &str,
                               single_start: &str,
                               multi_start: &str,
                               multi_end: &str)
                               -> Count {

    let single_line_start = single_start;
    let multiline_start = multi_start;
    let multiline_end = multi_end;

    let fmmap = match Mmap::open_path(filepath, Protection::Read) {
        Ok(mmap) => mmap,
        Err(e) => {
            println!("mmap err for {}: {}", filepath, e);
            return Count::default();
        }
    };
    let bytes: &[u8] = unsafe { fmmap.as_slice() };

    let mut lines = 0;
    let mut code = 0;
    let mut comments = 0;
    let mut blanks = 0;

    let mut in_comment = false;

    let a = Ascii(bytes);
    for byte_line in a.lines() {
        // let line = unsafe { std::str::from_utf8_unchecked(byte_line) };
        let line = match std::str::from_utf8(byte_line) {
            Ok(s) => s,
            Err(_) => return Count::default(),
        };
        lines += 1;

        let trimmed = line.trim_left();
        if trimmed.is_empty() {
            blanks += 1;
            continue;
        };

        if !in_comment && trimmed.starts_with(single_line_start) {
            comments += 1;
            continue;
        }

        if !(trimmed.contains(multiline_start) || trimmed.contains(multiline_end)) {
            if in_comment {
                comments += 1;
            } else {
                code += 1;
            }
            continue;
        }

        let mut pos = 0;
        let mut found_code = false;

        let start_len = multiline_start.len();
        let end_len = multiline_end.len();

        'outer: while pos < trimmed.len() {
            // TODO(cgag): must be a less stupid way to do this
            for i in pos..(pos + cmp::max(start_len, end_len) + 1) {
                if !trimmed.is_char_boundary(i) {
                    pos += 1;
                    continue 'outer;
                }
            }

            if pos + start_len <= trimmed.len() &&
               &trimmed[pos..pos + start_len] == multiline_start {
                pos += start_len;
                in_comment = true;
            } else if pos + end_len <= trimmed.len() && &trimmed[pos..pos + end_len] == multiline_end {
                pos += end_len;
                in_comment = false;
            } else if !in_comment {
                found_code = true;
                pos += 1;
            } else {
                pos += 1;
            }
        }

        if found_code {
            code += 1;
        } else {
            comments += 1;
        }
    }

    Count {
        code: code,
        comment: comments,
        blank: blanks,
        lines: lines,
    }
}
<|endoftext|>


<commit_before>use std::io;

/// Main bitmap structure
pub struct Bitmap {
    width:  i32,
    height: i32,
    pixels: Vec<u8>,
}

impl Bitmap {
    /// Create a new blank (white) bitmap of a specified size.
    pub fn new(width: i32, height: i32) -> Bitmap {
        Bitmap {
            width: width,
            height: height,
            // Create a vector to store the pixels in, ensuring that it is padded to a multiple of 4
            // bytes of each row.
            pixels: Vec::from_elem((height * (width * 3 + width % 4)) as uint, 0xFFu8)
        }
    }

    /// Set a pixel at (x, y) to a specified color (r, g, b).
    pub fn set_pixel(&mut self, x: i32, y: i32, color: (u8, u8, u8)) {
        // Calculate the byte offset for x
        let i = ((self.height - y - 1) * (self.width * 3) + x * 3) as uint;

        let (r, g, b) = color;
        // Note: Pixel order for bitmaps is (blue, green, red)
        self.pixels[i + 0] = b;
        self.pixels[i + 1] = g;
        self.pixels[i + 2] = r;
    }

    /// Write the stored data to a file with given filename.
    pub fn write_to_file(&self, filename: &str) -> io::IoResult<()> {
        const FILE_HEADER_SIZE: u32 = 14;
        const BMP_INFO_SIZE: u32 = 40;
        const TOTAL_HEADER_SIZE: u32 = FILE_HEADER_SIZE + BMP_INFO_SIZE;

        let image_size = (self.height * self.width*3 + self.height * (self.width % 4)) as u32;
        let file_size = image_size + TOTAL_HEADER_SIZE;

        // Bitmap file header
        let file_header: [u8, ..FILE_HEADER_SIZE as uint] = [
            'B' as u8, 'M' as u8,
            file_size as u8, (file_size>>8) as u8, (file_size>>16) as u8, (file_size>>24) as u8,
            0, 0,
            0, 0,
            TOTAL_HEADER_SIZE as u8, 0, 0, 0
        ];
        // Bitmap information header
        let info_header: [u8, ..BMP_INFO_SIZE as uint] = [
            BMP_INFO_SIZE as u8, 0, 0, 0,
            self.width as u8, (self.width>>8) as u8, (self.width>>16) as u8, (self.width>>24) as u8,
            self.height as u8, (self.height>>8) as u8, (self.height>>16) as u8, (self.height>>24) as u8,
            1, 0,
            24, 0,
            0, 0, 0, 0,
            image_size as u8, (image_size>>8) as u8, (image_size>>16) as u8, (image_size>>24) as u8,
            72, 0, 0, 0,
            72, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0
        ];

        // Set up the file writer
        let mut file = io::File::create(&Path::new(filename));

        // Write the bitmap headers to file
        try!(file.write(file_header));
        try!(file.write(info_header));

        // Write data to file
        file.write(self.pixels.as_slice())
    }

    /// Get the width of the bitmap.
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Get the height of the bitmap.
    pub fn height(&self) -> i32 {
        self.height
    }
}
<commit_msg>Update for latest version of Rust.<commit_after>use std::io;

/// Main bitmap structure
pub struct Bitmap {
    width:  i32,
    height: i32,
    pixels: Vec<u8>,
}

impl Bitmap {
    /// Create a new blank (white) bitmap of a specified size.
    pub fn new(width: i32, height: i32) -> Bitmap {
        Bitmap {
            width: width,
            height: height,
            // Create a vector to store the pixels in, ensuring that it is padded to a multiple of 4
            // bytes of each row.
            pixels: Vec::from_elem((height * (width * 3 + width % 4)) as uint, 0xFFu8)
        }
    }

    /// Set a pixel at (x, y) to a specified color (r, g, b).
    pub fn set_pixel(&mut self, x: i32, y: i32, color: (u8, u8, u8)) {
        // Calculate the byte offset for x
        let i = ((self.height - y - 1) * (self.width * 3) + x * 3) as uint;

        let (r, g, b) = color;
        // Note: Pixel order for bitmaps is (blue, green, red)
        self.pixels[i + 0] = b;
        self.pixels[i + 1] = g;
        self.pixels[i + 2] = r;
    }

    /// Write the stored data to a file with given filename.
    pub fn write_to_file(&self, filename: &str) -> io::IoResult<()> {
        const FILE_HEADER_SIZE: u32 = 14;
        const BMP_INFO_SIZE: u32 = 40;
        const TOTAL_HEADER_SIZE: u32 = FILE_HEADER_SIZE + BMP_INFO_SIZE;

        let image_size = (self.height * self.width*3 + self.height * (self.width % 4)) as u32;
        let file_size = image_size + TOTAL_HEADER_SIZE;

        // Bitmap file header
        let file_header: [u8, ..FILE_HEADER_SIZE as uint] = [
            'B' as u8, 'M' as u8,
            file_size as u8, (file_size>>8) as u8, (file_size>>16) as u8, (file_size>>24) as u8,
            0, 0,
            0, 0,
            TOTAL_HEADER_SIZE as u8, 0, 0, 0
        ];
        // Bitmap information header
        let info_header: [u8, ..BMP_INFO_SIZE as uint] = [
            BMP_INFO_SIZE as u8, 0, 0, 0,
            self.width as u8, (self.width>>8) as u8, (self.width>>16) as u8, (self.width>>24) as u8,
            self.height as u8, (self.height>>8) as u8, (self.height>>16) as u8, (self.height>>24) as u8,
            1, 0,
            24, 0,
            0, 0, 0, 0,
            image_size as u8, (image_size>>8) as u8, (image_size>>16) as u8, (image_size>>24) as u8,
            72, 0, 0, 0,
            72, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0
        ];

        // Set up the file writer
        let mut file = io::File::create(&Path::new(filename));

        // Write the bitmap headers to file
        try!(file.write(&file_header));
        try!(file.write(&info_header));

        // Write data to file
        file.write(&*self.pixels)
    }

    /// Get the width of the bitmap.
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Get the height of the bitmap.
    pub fn height(&self) -> i32 {
        self.height
    }
}
<|endoftext|>


<commit_before>extern crate cocoa;
extern crate metal_sys;
#[macro_use]
extern crate objc;

#[macro_use]
mod raw;

mod command_buffer;
mod command_queue;
mod compile_options;
mod device;
mod drawable;
mod function;
mod internal;
mod library;
mod value_types;

pub mod sys {
    pub use metal_sys::*;
}

pub use command_buffer::CommandBuffer;
pub use command_queue::{CommandQueue, CommandQueueError};
pub use compile_options::{CompileOptions, LanguageVersion, PreprocessorMacroValue,
                          SpecificLanguageVersion};
pub use device::{Device, DeviceError};
pub use drawable::Drawable;
pub use function::{Function, FunctionType};
pub use library::{Library, LibraryError};
pub use raw::{AsRaw, FromRaw, FromRawError, IntoRaw};
pub use value_types::{ClearColor, Origin, Region, ScissorRect, Size, Viewport};
<commit_msg>Add more warnings<commit_after>#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces, unused_qualifications)]

extern crate cocoa;
extern crate metal_sys;
#[macro_use]
extern crate objc;

#[macro_use]
mod raw;

mod command_buffer;
mod command_queue;
mod compile_options;
mod device;
mod drawable;
mod function;
mod internal;
mod library;
mod value_types;

pub mod sys {
    pub use metal_sys::*;
}

pub use command_buffer::CommandBuffer;
pub use command_queue::{CommandQueue, CommandQueueError};
pub use compile_options::{CompileOptions, LanguageVersion, PreprocessorMacroValue,
                          SpecificLanguageVersion};
pub use device::{Device, DeviceError};
pub use drawable::Drawable;
pub use function::{Function, FunctionType};
pub use library::{Library, LibraryError};
pub use raw::{AsRaw, FromRaw, FromRawError, IntoRaw};
pub use value_types::{ClearColor, Origin, Region, ScissorRect, Size, Viewport};
<|endoftext|>


<commit_before>use std::path::Path;
use std::collections::HashMap;
use std::io::{self, BufReader};
use std::io::prelude::*;
use std::fs::File;

type IniData = HashMap<String, HashMap<String, String>>;

#[derive(Debug)]
pub struct Ini(IniData);

impl<'a> Ini {
    fn new() -> Ini {
        Ini(HashMap::new())
    }
    pub fn from_file<S: AsRef<Path> + ?Sized>(path: &S) -> Ini {
        let file = File::open(path)
                        .ok()
                        .expect(&format!("Can't open `{}` file!", path.as_ref().display()));
        let reader = BufReader::new(file);
        let mut result = Ini::new();
        let mut section_name = String::new();
        let mut entry_list = HashMap::new();
        for line in reader.lines().filter_map(|l| l.ok()) {
            println!("line = `{}`", line);
            if line.contains('[') && line.contains(']') {
                let left_pos = line.find('[').unwrap() + 1;
                let right_pos = line.find(']').unwrap();
                if section_name.len() != 0 {
                    result.0.insert(section_name, entry_list.clone());
                    entry_list.clear();
                }
                section_name = (&line[left_pos..right_pos]).to_owned();
            } else if !line.starts_with(';') {
                let vec: Vec<&str> = line.split('=').collect();
                if vec.len() < 2 { continue; }
                let token = vec[0].trim_right();
                let value = if vec[1].contains(';') {
                    vec[1].split(';').nth(0).unwrap().trim()
                } else {
                    vec[1].trim()
                };
                entry_list.insert(token.to_owned(), value.to_owned());
            }
        }
        // add last section
        if section_name.len() != 0 {
            result.0.insert(section_name, entry_list.clone());
            entry_list.clear();
        }
        result
    }
    pub fn from_buffer<S: Into<String>>(buf: S) -> Ini {
        unimplemented!()
    }
    pub fn section<S: Into<String>>(&'a self, name: S) -> Option<&'a HashMap<String, String>> {
        let name = name.into();
        self.0.get(&name)
    }
}
<commit_msg>[add] minimalistic parser and convert to given type<commit_after>mod parser;

use std::path::Path;
use std::collections::HashMap;
use std::io::{BufReader, Read};
use std::fs::File;
use std::str::FromStr;

use parser::{parse_line, Parsed};

type IniParsed = HashMap<String, HashMap<String, String>>;

#[derive(Debug)]
pub struct Ini(IniParsed);

impl<'a> Ini {
    fn new() -> Ini {
        Ini(HashMap::new())
    }
    fn from_string(string: &str) -> Ini {
        let mut result = Ini::new();
        let mut section_name = String::new();
        let mut entry_list = HashMap::new();
        for (i, line) in string.lines().enumerate() {
            match parse_line(&line) {
                Parsed::Section(name) => {
                    if section_name.len() != 0 {
                        result.0.insert(section_name, entry_list.clone());
                        entry_list.clear();
                    }
                    section_name = name;
                }
                Parsed::Value(name, value) => {
                    entry_list.insert(name, value);
                }
                Parsed::Error(msg) => println!("line {}: error: {}", i, msg),
                _ => (),
            };
        }
        // add last section
        if section_name.len() != 0 {
            result.0.insert(section_name, entry_list.clone());
            entry_list.clear();
        }
        result
    }

    pub fn from_file<S: AsRef<Path> + ?Sized>(path: &S) -> Ini {
        let file = File::open(path)
                       .ok()
                       .expect(&format!("Can't open `{}`!", path.as_ref().display()));
        let mut reader = BufReader::new(file);
        let mut buffer = String::new();
        let _ = reader.read_to_string(&mut buffer)
                      .ok()
                      .expect(&format!("Can't read `{}`!", path.as_ref().display()));
        Ini::from_string(&buffer)
    }
    pub fn from_buffer<S: Into<String>>(buf: S) -> Ini {
        Ini::from_string(&buf.into())
    }
    fn get_raw(&'a self, section: &str, key: &str, default: &str) -> String {
        let s = self.0.get(section);
        let result = match s {
            Some(hm) => {
                let k = hm.get(key);
                let value = match k {
                    Some(v) => v.to_owned(),
                    None => default.to_owned(),
                };
                value
            }
            None => default.to_owned(),
        };
        result
    }
    pub fn get<T: FromStr>(&'a self, section: &str, key: &str, default: &str) -> T {
        self.get_raw(section, key, default)
            .parse()
            .ok()
            .expect(&format!("cannot convert to given type"))
    }
    pub fn get_vec<T: FromStr>(&'a self, section: &str, key: &str, default: &str) -> Vec<T> {
        self.get_raw(section, key, default)
            .split(',')
            .map(|s| s.trim().parse().ok().expect(&format!("cannot convert {} to given type", s)))
            .collect()
    }
}

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

    #[test]
    fn test_float() {
        let ini = Ini::from_string("[section]\nname=10.5");
        let name: f64 = ini.get("section", "name", "0");
        assert_eq!(name, 10.5);
    }

    #[test]
    fn test_float_vec() {
        let ini = Ini::from_string("[section]\nname=1.2, 3.4, 5.6");
        let name: Vec<f64> = ini.get_vec("section", "name", "0");
        assert_eq!(name, [1.2, 3.4, 5.6]);
    }
}
<|endoftext|>