<commit_before>use atom::*;
use symbol;
use errors::*;
use std::fmt;
use std::rc::Rc;
use std::cell::RefCell;

#[derive (Debug, Clone, PartialEq)]
struct Entry {
    key: symbol::InternedStr,
    value: Atom,
}

impl fmt::Display for Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} => {}", self.key, self.value)
    }
}

#[derive(Debug,PartialEq)]
struct EnvGeneration {
    value: Vec<Entry>,
    parent: Option<Env>,
}

impl fmt::Display for EnvGeneration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "EnvGeneration[{:p}]", self));
        for i in &self.value {
            try!(write!(f, "\t{}", i));
        }
        Ok(())
    }
}

impl EnvGeneration {
    fn new(parent: Option<Env>) -> EnvGeneration {
        EnvGeneration {
            value: Vec::new(),
            parent: parent,
        }
    }

    fn find(&self, key: &str) -> Option<&Entry> {
        self.value.iter().rev().find(|entry| entry.key.as_ref() == key)
    }
}

#[derive (Debug, Clone, PartialEq)]
pub struct Env(Rc<RefCell<EnvGeneration>>);

impl Default for Env {
    fn default() -> Env {
        Env::new(None)
    }
}

impl fmt::Display for Env {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let gen = self.0.borrow();
        try!(write!(f, "Top-level: EnvGeneration: {}\n", *gen));

        if let Some(ref parent) = gen.parent {
            try!(write!(f, "parent: {}\n", parent));
        } else {
            try!(write!(f, "no parent\n"));
        }
        Ok(())
    }
}

impl Env {
    pub fn new(parent: Option<Env>) -> Env {
        Env(Rc::new(RefCell::new(EnvGeneration::new(parent))))
    }

    fn find(&self, key: &str) -> Option<Atom> {
        let gen = self.0.borrow();
        let value = &gen.value;
        match value.iter().rev().find(|entry| entry.key.as_ref() == key) {
            Some(ref entry) => Some(entry.value.clone()),
            None => {
                if let Some(ref parent) = gen.parent {
                    parent.find(key)
                } else {
                    None
                }
            }
        }
    }

    #[allow(dead_code)]
    pub fn num_generations(&self) -> usize {
        self.num_gen(1)
    }

    fn num_gen(&self, c: usize) -> usize {
        let gen = self.0.borrow();
        if let Some(ref parent) = gen.parent {
            return parent.num_gen(c + 1);
        } else {
            c
        }
    }

    pub fn bind_mut(&mut self, params: &[Atom], args: &[Atom]) {
        let mut params_iter = params.iter();
        let mut args_iter = args.iter();
        while let Some(&Atom::Symbol(ref sym)) = params_iter.next() {
            if sym.as_ref() == "&" {
                if let Some(&Atom::Symbol(ref splat)) = params_iter.next() {
                    let vals = args_iter.cloned().collect();
                    self.0.borrow_mut().value.push(Entry {
                        key: *splat,
                        value: Atom::list(vals),
                    });
                    break;
                }
            } else {
                let arg = args_iter.next().cloned().unwrap_or(Atom::Nil);

                {
                    // tricking the borrow checker here
                    let mut gen = self.0.borrow_mut();

                    if let Some(mut entry) = gen.value.iter_mut().find(|entry| entry.key == *sym) {
                        entry.value = arg;
                        continue;
                    }
                }

                self.0.borrow_mut().value.push(Entry {
                    key: *sym,
                    value: arg,
                });
            }
        }
    }

    pub fn bind(&self, params: &[Atom], args: &[Atom]) -> Env {
        let mut e = Env::new(Some(self.clone()));
        e.bind_mut(params, args);
        e
    }

    pub fn get(&self, key: &str) -> Option<Atom> {
        self.find(key)
    }

    pub fn define(&mut self, key: symbol::InternedStr, value: Atom) -> Result<Atom, Error> {
        if let Some(_) = self.0.borrow().find(key.as_ref()) {
            // println!("env is: {}", self);
            return Err(invalid_arg(&format!("define has entry already: {}", key.as_ref())));
        }
        self.0.borrow_mut().value.push(Entry {
            key: key,
            value: value,
        });
        Ok(Atom::Symbol(key))
    }

    pub fn set(&mut self, key: symbol::InternedStr, value: Atom) -> Result<Atom, Error> {
        {
            // set in current generation
            let mut gen = self.0.borrow_mut();
            if let Some(mut entry) = gen.value.iter_mut().find(|entry| entry.key == key) {
                entry.value = value;
                return Ok(Atom::Symbol(key));
            }
        }

        if let Some(ref mut parent) = self.0.borrow_mut().parent {
            parent.set(key, value)
        } else {
            Err(invalid_arg("in set"))
        }
    }
}

#[cfg(test)]
mod tests {
    use self::super::*;
    use atom::*;
    use errors::*;
    use symbol::*;

    #[test]
    fn nested_get() {
        let mut env = Env::new(None);

        env.define(intern("foo"), Atom::String("bar".to_owned())).unwrap();

        let env2 = Env::new(Some(env.clone()));

        assert_eq!(Atom::String("bar".to_owned()),
                   env2.get(intern("foo").as_ref()).unwrap());
    }

    #[test]
    fn splat() {
        let env = Env::new(None);

        let params = vec![Atom::symbol("&"), Atom::symbol("body")];

        let e = env.bind(&params, &vec![Atom::from(0), Atom::from(1), Atom::from(2)]);

        let body = e.get("body").unwrap();

        assert_eq!(Atom::list(vec![Atom::from(0), Atom::from(1), Atom::from(2)]),
                   body);
    }

    #[test]
    fn define() {
        let mut env = Env::new(None);

        env.define(intern("foo"), Atom::string("bar")).unwrap();

        if let Err(Error::InvalidArguments(_)) = env.set(intern("bar"), Atom::string("foo")) {
            assert!(true);
        } else {
            assert!(false);
        }

        let mut env2 = Env::new(Some(env.clone()));

        env2.set(intern("foo"), Atom::parse("0")).unwrap();

        assert_eq!(Atom::parse("0"), env.get("foo").unwrap());
        assert_eq!(Atom::parse("0"), env2.get("foo").unwrap());

        env2.define(intern("foo"), Atom::string("baz")).unwrap();

        assert_eq!(Atom::string("baz"), env2.get("foo").unwrap());
        assert_eq!(Atom::parse("0"), env.get("foo").unwrap());
    }

    #[test]
    fn bind_mut() {
        let mut env = Env::default();
        let args = vec![Atom::from(0), Atom::from(1)];
        let params = vec![Atom::symbol("a"), Atom::symbol("b")];
        env.bind_mut(&params, &args);

        assert_eq!(env.get("a").unwrap(), Atom::from(0));
        assert_eq!(env.get("b").unwrap(), Atom::from(1));

        env.bind_mut(&params, &vec![Atom::from(2), Atom::from(42)]);

        assert_eq!(env.get("a").unwrap(), Atom::from(2));
        assert_eq!(env.get("b").unwrap(), Atom::from(42));

        assert_eq!(2, env.0.borrow().value.len());
    }

}
<commit_msg>don't need to rev anymore<commit_after>use atom::*;
use symbol;
use errors::*;
use std::fmt;
use std::rc::Rc;
use std::cell::RefCell;

#[derive (Debug, Clone, PartialEq)]
struct Entry {
    key: symbol::InternedStr,
    value: Atom,
}

impl fmt::Display for Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} => {}", self.key, self.value)
    }
}

#[derive(Debug,PartialEq)]
struct EnvGeneration {
    value: Vec<Entry>,
    parent: Option<Env>,
}

impl fmt::Display for EnvGeneration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "EnvGeneration[{:p}]", self));
        for i in &self.value {
            try!(write!(f, "\t{}", i));
        }
        Ok(())
    }
}

impl EnvGeneration {
    fn new(parent: Option<Env>) -> EnvGeneration {
        EnvGeneration {
            value: Vec::new(),
            parent: parent,
        }
    }

    fn find(&self, key: &str) -> Option<&Entry> {
        self.value.iter().rev().find(|entry| entry.key.as_ref() == key)
    }
}

#[derive (Debug, Clone, PartialEq)]
pub struct Env(Rc<RefCell<EnvGeneration>>);

impl Default for Env {
    fn default() -> Env {
        Env::new(None)
    }
}

impl fmt::Display for Env {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let gen = self.0.borrow();
        try!(write!(f, "Top-level: EnvGeneration: {}\n", *gen));

        if let Some(ref parent) = gen.parent {
            try!(write!(f, "parent: {}\n", parent));
        } else {
            try!(write!(f, "no parent\n"));
        }
        Ok(())
    }
}

impl Env {
    pub fn new(parent: Option<Env>) -> Env {
        Env(Rc::new(RefCell::new(EnvGeneration::new(parent))))
    }

    fn find(&self, key: &str) -> Option<Atom> {
        let gen = self.0.borrow();
        let value = &gen.value;
        match value.iter().find(|entry| entry.key.as_ref() == key) {
            Some(ref entry) => Some(entry.value.clone()),
            None => {
                if let Some(ref parent) = gen.parent {
                    parent.find(key)
                } else {
                    None
                }
            }
        }
    }

    #[allow(dead_code)]
    pub fn num_generations(&self) -> usize {
        self.num_gen(1)
    }

    fn num_gen(&self, c: usize) -> usize {
        let gen = self.0.borrow();
        if let Some(ref parent) = gen.parent {
            return parent.num_gen(c + 1);
        } else {
            c
        }
    }

    pub fn bind_mut(&mut self, params: &[Atom], args: &[Atom]) {
        let mut params_iter = params.iter();
        let mut args_iter = args.iter();
        while let Some(&Atom::Symbol(ref sym)) = params_iter.next() {
            if sym.as_ref() == "&" {
                if let Some(&Atom::Symbol(ref splat)) = params_iter.next() {
                    let vals = args_iter.cloned().collect();
                    self.0.borrow_mut().value.push(Entry {
                        key: *splat,
                        value: Atom::list(vals),
                    });
                    break;
                }
            } else {
                let arg = args_iter.next().cloned().unwrap_or(Atom::Nil);

                {
                    // tricking the borrow checker here
                    let mut gen = self.0.borrow_mut();

                    if let Some(mut entry) = gen.value.iter_mut().find(|entry| entry.key == *sym) {
                        entry.value = arg;
                        continue;
                    }
                }

                self.0.borrow_mut().value.push(Entry {
                    key: *sym,
                    value: arg,
                });
            }
        }
    }

    pub fn bind(&self, params: &[Atom], args: &[Atom]) -> Env {
        let mut e = Env::new(Some(self.clone()));
        e.bind_mut(params, args);
        e
    }

    pub fn get(&self, key: &str) -> Option<Atom> {
        self.find(key)
    }

    pub fn define(&mut self, key: symbol::InternedStr, value: Atom) -> Result<Atom, Error> {
        if let Some(_) = self.0.borrow().find(key.as_ref()) {
            return Err(invalid_arg(&format!("define has entry already: {}", key.as_ref())));
        }
        self.0.borrow_mut().value.push(Entry {
            key: key,
            value: value,
        });
        Ok(Atom::Symbol(key))
    }

    pub fn set(&mut self, key: symbol::InternedStr, value: Atom) -> Result<Atom, Error> {
        {
            // set in current generation
            let mut gen = self.0.borrow_mut();
            if let Some(mut entry) = gen.value.iter_mut().find(|entry| entry.key == key) {
                entry.value = value;
                return Ok(Atom::Symbol(key));
            }
        }

        if let Some(ref mut parent) = self.0.borrow_mut().parent {
            parent.set(key, value)
        } else {
            Err(invalid_arg("in set"))
        }
    }
}

#[cfg(test)]
mod tests {
    use self::super::*;
    use atom::*;
    use errors::*;
    use symbol::*;

    #[test]
    fn nested_get() {
        let mut env = Env::new(None);

        env.define(intern("foo"), Atom::String("bar".to_owned())).unwrap();

        let env2 = Env::new(Some(env.clone()));

        assert_eq!(Atom::String("bar".to_owned()),
                   env2.get(intern("foo").as_ref()).unwrap());
    }

    #[test]
    fn splat() {
        let env = Env::new(None);

        let params = vec![Atom::symbol("&"), Atom::symbol("body")];

        let e = env.bind(&params, &vec![Atom::from(0), Atom::from(1), Atom::from(2)]);

        let body = e.get("body").unwrap();

        assert_eq!(Atom::list(vec![Atom::from(0), Atom::from(1), Atom::from(2)]),
                   body);
    }

    #[test]
    fn define() {
        let mut env = Env::new(None);

        env.define(intern("foo"), Atom::string("bar")).unwrap();

        if let Err(Error::InvalidArguments(_)) = env.set(intern("bar"), Atom::string("foo")) {
            assert!(true);
        } else {
            assert!(false);
        }

        let mut env2 = Env::new(Some(env.clone()));

        env2.set(intern("foo"), Atom::parse("0")).unwrap();

        assert_eq!(Atom::parse("0"), env.get("foo").unwrap());
        assert_eq!(Atom::parse("0"), env2.get("foo").unwrap());

        env2.define(intern("foo"), Atom::string("baz")).unwrap();

        assert_eq!(Atom::string("baz"), env2.get("foo").unwrap());
        assert_eq!(Atom::parse("0"), env.get("foo").unwrap());
    }

    #[test]
    fn bind_mut() {
        let mut env = Env::default();
        let args = vec![Atom::from(0), Atom::from(1)];
        let params = vec![Atom::symbol("a"), Atom::symbol("b")];
        env.bind_mut(&params, &args);

        assert_eq!(env.get("a").unwrap(), Atom::from(0));
        assert_eq!(env.get("b").unwrap(), Atom::from(1));

        env.bind_mut(&params, &vec![Atom::from(2), Atom::from(42)]);

        assert_eq!(env.get("a").unwrap(), Atom::from(2));
        assert_eq!(env.get("b").unwrap(), Atom::from(42));

        assert_eq!(2, env.0.borrow().value.len());
    }

}
<|endoftext|>


<commit_before>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session, ProtocolVersion};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream, SslVersion};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum TransportProtocol {
  Tcp,
  Ssl2,
  Ssl3,
  Tls1_0,
  Tls1_1,
  Tls1_2,
  Tls1_3,
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_write_vectored(&mut self,  buf: &[&iovec::IoVec]) -> (usize, SocketResult) {
    unimplemented!()
  }
  fn has_vectored_writes(&self) -> bool { false }
  fn socket_ref(&self) -> &TcpStream;
  fn protocol(&self) -> TransportProtocol;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.read.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            incr!("tcp.read.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.write.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            incr!("tcp.write.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write_vectored(&mut self,  bufs: &[&iovec::IoVec]) -> (usize, SocketResult) {
    match self.write_bufs(bufs) {
      Ok(0)  => return (0, SocketResult::Continue),
      Ok(sz) => return (sz, SocketResult::Continue),
      Err(e) => match e.kind() {
        ErrorKind::WouldBlock => return (0, SocketResult::WouldBlock),
        ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
          incr!("tcp.write.error");
          return (0, SocketResult::Closed)
        },
        _ => {
          //FIXME: timeout and other common errors should be sent up
          error!("SOCKET\tsocket_write error={:?}", e);
          incr!("tcp.write.error");
          return (0, SocketResult::Error)
        },
      }
    }
  }

  fn has_vectored_writes(&self) -> bool { true }

  fn socket_ref(&self) -> &TcpStream { self }

  fn protocol(&self) -> TransportProtocol {
    TransportProtocol::Tcp
  }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.read.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.write.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }

  fn protocol(&self) -> TransportProtocol {
    self.ssl().version2().map(|version| match version {
      SslVersion::SSL3 => TransportProtocol::Ssl3,
      SslVersion::TLS1 => TransportProtocol::Tls1_0,
      SslVersion::TLS1_1 => TransportProtocol::Tls1_1,
      SslVersion::TLS1_2 => TransportProtocol::Tls1_2,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("rustls.read.error");
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            incr!("rustls.read.error");
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.read.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              incr!("rustls.read.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            incr!("rustls.write.error");
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            incr!("rustls.write.error");
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.write.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              incr!("rustls.write.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }

  fn protocol(&self) -> TransportProtocol {
    self.session.get_protocol_version().map(|version| match version {
      ProtocolVersion::SSLv2 => TransportProtocol::Ssl2,
      ProtocolVersion::SSLv3 => TransportProtocol::Ssl3,
      ProtocolVersion::TLSv1_0 => TransportProtocol::Tls1_0,
      ProtocolVersion::TLSv1_1 => TransportProtocol::Tls1_1,
      ProtocolVersion::TLSv1_2 => TransportProtocol::Tls1_2,
      ProtocolVersion::TLSv1_3 => TransportProtocol::Tls1_3,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4()?,
    SocketAddr::V6(..) => TcpBuilder::new_v6()?,
  };

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    sock.reuse_address(true)?;
  }

  sock.reuse_port(true)?;

  // bind the socket
  sock.bind(addr)?;

  // listen
  // FIXME: make the backlog configurable?
  let listener = sock.listen(1024)?;
  TcpListener::from_std(listener)
}

<commit_msg>close sockets if read() returned 0<commit_after>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session, ProtocolVersion};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream, SslVersion};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum TransportProtocol {
  Tcp,
  Ssl2,
  Ssl3,
  Tls1_0,
  Tls1_1,
  Tls1_2,
  Tls1_3,
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_write_vectored(&mut self,  buf: &[&iovec::IoVec]) -> (usize, SocketResult) {
    unimplemented!()
  }
  fn has_vectored_writes(&self) -> bool { false }
  fn socket_ref(&self) -> &TcpStream;
  fn protocol(&self) -> TransportProtocol;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Closed),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.read.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            incr!("tcp.read.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.write.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            incr!("tcp.write.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write_vectored(&mut self,  bufs: &[&iovec::IoVec]) -> (usize, SocketResult) {
    match self.write_bufs(bufs) {
      Ok(0)  => return (0, SocketResult::Continue),
      Ok(sz) => return (sz, SocketResult::Continue),
      Err(e) => match e.kind() {
        ErrorKind::WouldBlock => return (0, SocketResult::WouldBlock),
        ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
          incr!("tcp.write.error");
          return (0, SocketResult::Closed)
        },
        _ => {
          //FIXME: timeout and other common errors should be sent up
          error!("SOCKET\tsocket_write error={:?}", e);
          incr!("tcp.write.error");
          return (0, SocketResult::Error)
        },
      }
    }
  }

  fn has_vectored_writes(&self) -> bool { true }

  fn socket_ref(&self) -> &TcpStream { self }

  fn protocol(&self) -> TransportProtocol {
    TransportProtocol::Tcp
  }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.read.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.write.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }

  fn protocol(&self) -> TransportProtocol {
    self.ssl().version2().map(|version| match version {
      SslVersion::SSL3 => TransportProtocol::Ssl3,
      SslVersion::TLS1 => TransportProtocol::Tls1_0,
      SslVersion::TLS1_1 => TransportProtocol::Tls1_1,
      SslVersion::TLS1_2 => TransportProtocol::Tls1_2,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("rustls.read.error");
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            incr!("rustls.read.error");
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.read.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              incr!("rustls.read.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            incr!("rustls.write.error");
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            incr!("rustls.write.error");
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.write.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              incr!("rustls.write.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }

  fn protocol(&self) -> TransportProtocol {
    self.session.get_protocol_version().map(|version| match version {
      ProtocolVersion::SSLv2 => TransportProtocol::Ssl2,
      ProtocolVersion::SSLv3 => TransportProtocol::Ssl3,
      ProtocolVersion::TLSv1_0 => TransportProtocol::Tls1_0,
      ProtocolVersion::TLSv1_1 => TransportProtocol::Tls1_1,
      ProtocolVersion::TLSv1_2 => TransportProtocol::Tls1_2,
      ProtocolVersion::TLSv1_3 => TransportProtocol::Tls1_3,
      _ => TransportProtocol::Tls1_3,
    }).unwrap_or(TransportProtocol::Tcp)
  }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4()?,
    SocketAddr::V6(..) => TcpBuilder::new_v6()?,
  };

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    sock.reuse_address(true)?;
  }

  sock.reuse_port(true)?;

  // bind the socket
  sock.bind(addr)?;

  // listen
  // FIXME: make the backlog configurable?
  let listener = sock.listen(1024)?;
  TcpListener::from_std(listener)
}

<|endoftext|>


<commit_before>use std::slice;

extern crate libc;
use self::libc::{c_void, c_double, size_t};

use super::geo::{Point, Polygon, LineString};

use super::polylabel;
use super::num_traits::{Float, Signed};

/// Wrapper for a void pointer to a sequence of [`Array`](struct.Array.html)s, and the sequence length
///
/// Used for inner Polygon rings
#[repr(C)]
pub struct WrapperArray {
    pub data: *const Array,
    pub len: size_t,
}

/// Wrapper for a void pointer to a sequence of 2-element arrays representing points, and the sequence length
///
/// Used for outer Polygon rings. `data` is a `Vec<[c_double; 2]>`
#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

/// FFI struct for returned optimum Polygon label position
#[repr(C)]
pub struct Position {
    pub x_pos: c_double,
    pub y_pos: c_double,
}

// convert a Polylabel result Point into values that can be sent across the FFI boundary
impl<T> From<Point<T>> for Position
where
    T: Float + Signed,
{
    fn from(point: Point<T>) -> Position {
        Position {
            x_pos: point.x().to_f64().unwrap() as c_double,
            y_pos: point.y().to_f64().unwrap() as c_double,
        }
    }
}

fn reconstitute(arr: &Array) -> Vec<[f64; 2]> {
    unsafe { slice::from_raw_parts(arr.data as *mut [f64; 2], arr.len).to_vec() }
}

fn reconstitute2(arr: WrapperArray) -> Vec<Vec<[f64; 2]>> {
    let arrays = unsafe { slice::from_raw_parts(arr.data as *mut Array, arr.len) };
    arrays.into_iter().map(|x| reconstitute(x)).collect()
}

/// FFI access to the [`polylabel`](fn.polylabel.html) function
///
/// Accepts three arguments:
///
/// - an exterior ring [`Array`](struct.Array.html)
/// - an interior rings [`WrapperArray`](struct.WrapperArray.html)
/// - a tolerance `c_double`.
#[no_mangle]
pub extern "C" fn polylabel_ffi(
    outer: Array,
    inners: WrapperArray,
    tolerance: c_double,
) -> Position {
    let exterior: Vec<[f64; 2]> =
        unsafe { slice::from_raw_parts(outer.data as *mut [c_double; 2], outer.len).to_vec() };
    let interior: Vec<Vec<[f64; 2]>> = reconstitute2(inners);
    let ls_ext = LineString(exterior.iter().map(|e| Point::new(e[0], e[1])).collect());
    let ls_int: Vec<LineString<c_double>> = interior
        .iter()
        .map(|vec| {
            LineString(vec.iter().map(|e| Point::new(e[0], e[1])).collect())
        })
        .collect();
    let poly = Polygon::new(ls_ext, ls_int);
    polylabel(&poly, &tolerance).into()
}

#[cfg(test)]
mod tests {
    use super::{Array, WrapperArray, polylabel_ffi, reconstitute2};
    use super::libc::{c_void, size_t};
    use geo::Point;
    use std::mem;

    // Only used for testing
    fn gen_array(v: Vec<[f64; 2]>) -> Array {
        let array = Array {
            data: v.as_ptr() as *const c_void,
            len: v.len() as size_t,
        };
        mem::forget(v);
        array
    }
    // only used for testing
    fn gen_wrapperarray(v: Vec<Vec<[f64; 2]>>) -> WrapperArray {
        let converted: Vec<Array> = v.into_iter().map(|x| gen_array(x)).collect();
        let array2 = WrapperArray {
            data: converted.as_ptr() as *const Array,
            len: converted.len() as size_t,
        };
        mem::forget(converted);
        array2
    }
    #[test]
    fn test_array() {
        let i_a = vec![[0.5, 0.5], [1.0, 1.0], [1.5, 0.5]];
        let i_b = vec![[0.55, 0.55], [0.8, 0.8], [1.2, 0.55]];
        let inners = vec![i_a, i_b];
        let array = gen_wrapperarray(inners);
        let rec_inners = reconstitute2(array);
        assert_eq!(rec_inners[0][2], [1.5, 0.5])
    }
    #[test]
    fn test_ffi() {
        let ext_vec = vec![
            [4.0, 1.0],
            [5.0, 2.0],
            [5.0, 3.0],
            [4.0, 4.0],
            [3.0, 4.0],
            [2.0, 3.0],
            [2.0, 2.0],
            [3.0, 1.0],
            [4.0, 1.0],
        ];
        let int_vec = vec![
            vec![[3.5, 3.5], [4.4, 2.0], [2.6, 2.0], [3.5, 3.5]],
            vec![[4.0, 3.0], [4.0, 3.2], [4.5, 3.2], [4.0, 3.0]],
        ];

        let outer = gen_array(ext_vec);
        let inners = gen_wrapperarray(int_vec);
        let res = polylabel_ffi(outer, inners, 0.1);
        let res_point = Point::new(res.x_pos, res.y_pos);
        assert_eq!(res_point, Point::new(3.125, 2.875));
    }

}
<commit_msg>Update field docs<commit_after>use std::slice;

extern crate libc;
use self::libc::{c_void, c_double, size_t};

use super::geo::{Point, Polygon, LineString};

use super::polylabel;
use super::num_traits::{Float, Signed};

/// Wrapper for a void pointer to a sequence of [`Array`](struct.Array.html)s, and the sequence length
///
/// Each sequence entry represents an inner Polygon ring.
#[repr(C)]
pub struct WrapperArray {
    pub data: *const Array,
    pub len: size_t,
}

/// Wrapper for a void pointer to a sequence of 2-element arrays representing points, and the sequence length
///
/// Used for the outer Polygon shell. `data` is a `Vec<[c_double; 2]>`.
#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

/// FFI struct for returned optimum Polygon label position
#[repr(C)]
pub struct Position {
    pub x_pos: c_double,
    pub y_pos: c_double,
}

// convert a Polylabel result Point into values that can be sent across the FFI boundary
impl<T> From<Point<T>> for Position
where
    T: Float + Signed,
{
    fn from(point: Point<T>) -> Position {
        Position {
            x_pos: point.x().to_f64().unwrap() as c_double,
            y_pos: point.y().to_f64().unwrap() as c_double,
        }
    }
}

fn reconstitute(arr: &Array) -> Vec<[f64; 2]> {
    unsafe { slice::from_raw_parts(arr.data as *mut [f64; 2], arr.len).to_vec() }
}

fn reconstitute2(arr: WrapperArray) -> Vec<Vec<[f64; 2]>> {
    let arrays = unsafe { slice::from_raw_parts(arr.data as *mut Array, arr.len) };
    arrays.into_iter().map(|x| reconstitute(x)).collect()
}

/// FFI access to the [`polylabel`](fn.polylabel.html) function
///
/// Accepts three arguments:
///
/// - an exterior ring [`Array`](struct.Array.html)
/// - an interior rings [`WrapperArray`](struct.WrapperArray.html)
/// - a tolerance `c_double`.
#[no_mangle]
pub extern "C" fn polylabel_ffi(
    outer: Array,
    inners: WrapperArray,
    tolerance: c_double,
) -> Position {
    let exterior: Vec<[f64; 2]> =
        unsafe { slice::from_raw_parts(outer.data as *mut [c_double; 2], outer.len).to_vec() };
    let interior: Vec<Vec<[f64; 2]>> = reconstitute2(inners);
    let ls_ext = LineString(exterior.iter().map(|e| Point::new(e[0], e[1])).collect());
    let ls_int: Vec<LineString<c_double>> = interior
        .iter()
        .map(|vec| {
            LineString(vec.iter().map(|e| Point::new(e[0], e[1])).collect())
        })
        .collect();
    let poly = Polygon::new(ls_ext, ls_int);
    polylabel(&poly, &tolerance).into()
}

#[cfg(test)]
mod tests {
    use super::{Array, WrapperArray, polylabel_ffi, reconstitute2};
    use super::libc::{c_void, size_t};
    use geo::Point;
    use std::mem;

    // Only used for testing
    fn gen_array(v: Vec<[f64; 2]>) -> Array {
        let array = Array {
            data: v.as_ptr() as *const c_void,
            len: v.len() as size_t,
        };
        mem::forget(v);
        array
    }
    // only used for testing
    fn gen_wrapperarray(v: Vec<Vec<[f64; 2]>>) -> WrapperArray {
        let converted: Vec<Array> = v.into_iter().map(|x| gen_array(x)).collect();
        let array2 = WrapperArray {
            data: converted.as_ptr() as *const Array,
            len: converted.len() as size_t,
        };
        mem::forget(converted);
        array2
    }
    #[test]
    fn test_array() {
        let i_a = vec![[0.5, 0.5], [1.0, 1.0], [1.5, 0.5]];
        let i_b = vec![[0.55, 0.55], [0.8, 0.8], [1.2, 0.55]];
        let inners = vec![i_a, i_b];
        let array = gen_wrapperarray(inners);
        let rec_inners = reconstitute2(array);
        assert_eq!(rec_inners[0][2], [1.5, 0.5])
    }
    #[test]
    fn test_ffi() {
        let ext_vec = vec![
            [4.0, 1.0],
            [5.0, 2.0],
            [5.0, 3.0],
            [4.0, 4.0],
            [3.0, 4.0],
            [2.0, 3.0],
            [2.0, 2.0],
            [3.0, 1.0],
            [4.0, 1.0],
        ];
        let int_vec = vec![
            vec![[3.5, 3.5], [4.4, 2.0], [2.6, 2.0], [3.5, 3.5]],
            vec![[4.0, 3.0], [4.0, 3.2], [4.5, 3.2], [4.0, 3.0]],
        ];

        let outer = gen_array(ext_vec);
        let inners = gen_wrapperarray(int_vec);
        let res = polylabel_ffi(outer, inners, 0.1);
        let res_point = Point::new(res.x_pos, res.y_pos);
        assert_eq!(res_point, Point::new(3.125, 2.875));
    }

}
<|endoftext|>


<commit_before>use core::mem::size_of;

use common::debug::*;
use common::memory::*;
use common::pio::*;

//Status port bits
const ATA_SR_BSY: u8 = 0x80;
const ATA_SR_DRDY: u8 = 0x40;
const ATA_SR_DF: u8 = 0x20;
const ATA_SR_DSC: u8 = 0x10;
const ATA_SR_DRQ: u8 = 0x08;
const ATA_SR_CORR: u8 = 0x04;
const ATA_SR_IDX: u8 = 0x02;
const ATA_SR_ERR: u8 = 0x01;

//Error port bits
const ATA_ER_BBK: u8 = 0x80;
const ATA_ER_UNC: u8 = 0x40;
const ATA_ER_MC: u8 = 0x20;
const ATA_ER_IDNF: u8 = 0x10;
const ATA_ER_MCR: u8 = 0x08;
const ATA_ER_ABRT: u8 = 0x04;
const ATA_ER_TK0NF: u8 = 0x02;
const ATA_ER_AMNF: u8 = 0x01;

//Commands
const ATA_CMD_READ_PIO: u8 = 0x20;
const ATA_CMD_READ_PIO_EXT: u8 = 0x24;
const ATA_CMD_READ_DMA: u8 = 0xC8;
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
const ATA_CMD_WRITE_PIO: u8 = 0x30;
const ATA_CMD_WRITE_PIO_EXT: u8 = 0x34;
const ATA_CMD_WRITE_DMA: u8 = 0xCA;
const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35;
const ATA_CMD_CACHE_FLUSH: u8 = 0xE7;
const ATA_CMD_CACHE_FLUSH_EXT: u8 = 0xEA;
const ATA_CMD_PACKET: u8 = 0xA0;
const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1;
const ATA_CMD_IDENTIFY: u8 = 0xEC;

//Identification
const ATA_IDENT_DEVICETYPE: u8 = 0;
const ATA_IDENT_CYLINDERS: u8 = 2;
const ATA_IDENT_HEADS: u8 = 6;
const ATA_IDENT_SECTORS: u8 = 12;
const ATA_IDENT_SERIAL: u8 = 20;
const ATA_IDENT_MODEL: u8 = 54;
const ATA_IDENT_CAPABILITIES: u8 = 98;
const ATA_IDENT_FIELDVALID: u8 = 106;
const ATA_IDENT_MAX_LBA: u8 = 120;
const ATA_IDENT_COMMANDSETS: u8 = 164;
const ATA_IDENT_MAX_LBA_EXT: u8 = 200;

//Selection
const ATA_MASTER: u8 = 0x00;
const ATA_SLAVE: u8 = 0x01;

//Types
const IDE_ATA: u8 = 0x00;
const IDE_ATAPI: u8 = 0x01;

//Registers
const ATA_REG_DATA: u16 = 0x00;
const ATA_REG_ERROR: u16 = 0x01;
const ATA_REG_FEATURES: u16 = 0x01;
const ATA_REG_SECCOUNT0: u16 = 0x02;
const ATA_REG_LBA0: u16 = 0x03;
const ATA_REG_LBA1: u16 = 0x04;
const ATA_REG_LBA2: u16 = 0x05;
const ATA_REG_HDDEVSEL: u16 = 0x06;
const ATA_REG_COMMAND: u16 = 0x07;
const ATA_REG_STATUS: u16 = 0x07;
const ATA_REG_SECCOUNT1: u16 = 0x08;
const ATA_REG_LBA3: u16 = 0x09;
const ATA_REG_LBA4: u16 = 0x0A;
const ATA_REG_LBA5: u16 = 0x0B;
const ATA_REG_CONTROL: u16 = 0x0C;
const ATA_REG_ALTSTATUS: u16 = 0x0C;
const ATA_REG_DEVADDRESS: u16 = 0x0D;

pub struct PRDTE {
    pub ptr: u32,
    pub size: u16,
    pub reserved: u16
}

pub struct Disk{
    base: u16,
    ctrl: u16
}

impl Disk {
    pub fn new() -> Disk{
        Disk{
            base: 0x1F0,
            ctrl: 0x3F4
        }
    }

    unsafe fn ide_read(&self, reg: u16) -> u8{
        let ret;
        if reg < 0x08 {
            ret = inb(self.base + reg - 0x00);
        } else if reg < 0x0C {
            ret = inb(self.base + reg - 0x06);
        } else if reg < 0x0E {
            ret = inb(self.ctrl + reg - 0x0A);
        }else{
            ret = 0;
        }
        ret
    }

    unsafe fn ide_write(&self, reg: u16, data: u8){
        if reg < 0x08 {
            outb(self.base + reg - 0x00, data);
        } else if reg < 0x0C {
            outb(self.base + reg - 0x06, data);
        } else if reg < 0x0E {
            outb(self.ctrl + reg - 0x0A, data);
        }
    }

    unsafe fn ide_poll(&self, check_error: bool) -> u8{
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);

        while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

        }

        if check_error {
            let state = self.ide_read(ATA_REG_STATUS);
            if state & ATA_SR_ERR == ATA_SR_ERR {
                return 2;
            }
            if state & ATA_SR_DF == ATA_SR_DF {
                return 1;
            }
            if !(state & ATA_SR_DRQ == ATA_SR_DRQ) {
                return 3;
            }
        }

        return 0;
    }

    //TODO: Make sure count is not zero!
    pub unsafe fn read(&self, lba: u64, count: u16, destination: usize) -> u8{
        if destination > 0 {
            while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

            }

            self.ide_write(ATA_REG_HDDEVSEL, 0x40);

            self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

            self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA0, (lba & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);
            self.ide_write(ATA_REG_COMMAND, ATA_CMD_READ_PIO_EXT);

            for sector in 0..count as usize {
                let err = self.ide_poll(true);
                if err > 0{
                    return err;
                }

                for word in 0..256 {
                    let data = inw(self.base + ATA_REG_DATA);
                    *((destination + sector*512 + word*2) as *mut u16) = data;
                }
            }
        }

        return 0;
    }

    pub unsafe fn read_dma(&self, lba: u64, count: u16, destination: usize, busmaster: u16) -> u8{
        if destination > 0 {
            //Allocate PDTR
            let mut prdt = ind(busmaster + 4) as usize;

            if prdt == 0 {
                let size = count as usize * 512;
                let entries = (size + 65535)/65536;
                prdt = alloc(size_of::<PRDTE>() * entries);
                for i in 0..entries {
                    if i == entries - 1 {
                        *(prdt as *mut PRDTE).offset(i as isize) = PRDTE {
                            ptr: (destination + i * 65536) as u32,
                            size: (size % 65536) as u16,
                            reserved: 0x8000
                        };
                    }else{
                        *(prdt as *mut PRDTE).offset(i as isize) = PRDTE {
                            ptr: (destination + i * 65536) as u32,
                            size: 0,
                            reserved: 0
                        };
                    }
                }

                outd(busmaster + 4, prdt as u32);

                //Set read bit
                outb(busmaster, 8);

                //Clear interrupt, error bit
                outb(busmaster + 2, 0);

                //DMA Transfer Command
                while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

                }

                self.ide_write(ATA_REG_HDDEVSEL, 0x40);

                self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

                self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA0, (lba & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);
                self.ide_write(ATA_REG_COMMAND, ATA_CMD_READ_DMA_EXT);

                //Engage bus mastering
                outb(busmaster, inb(busmaster) | 1);
            }else{
                d("Operation Running!\n");
            }
        }

        return 0;
    }

    //TODO: Fix and make sure count is not zero!
    pub unsafe fn write(&self, lba: u64, count: u16, source: usize) -> u8{
        if source > 0 {
            while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

            }

            self.ide_write(ATA_REG_HDDEVSEL, 0x40);

            self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

            self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA0, ((lba >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);

            self.ide_write(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT);

            for sector in 0..count as usize {
                let err = self.ide_poll(true);
                if err > 0{
                    return err;
                }

                for word in 0..256 {
                    outw(self.base + ATA_REG_DATA, *((source + sector*512 + word*2) as *const u16));
                }

                self.ide_write(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH_EXT);
                self.ide_poll(false);
            }
        }

        return 0;
    }
}
<commit_msg>Allow slave/master selection<commit_after>use core::mem::size_of;

use common::debug::*;
use common::memory::*;
use common::pio::*;

//Status port bits
const ATA_SR_BSY: u8 = 0x80;
const ATA_SR_DRDY: u8 = 0x40;
const ATA_SR_DF: u8 = 0x20;
const ATA_SR_DSC: u8 = 0x10;
const ATA_SR_DRQ: u8 = 0x08;
const ATA_SR_CORR: u8 = 0x04;
const ATA_SR_IDX: u8 = 0x02;
const ATA_SR_ERR: u8 = 0x01;

//Error port bits
const ATA_ER_BBK: u8 = 0x80;
const ATA_ER_UNC: u8 = 0x40;
const ATA_ER_MC: u8 = 0x20;
const ATA_ER_IDNF: u8 = 0x10;
const ATA_ER_MCR: u8 = 0x08;
const ATA_ER_ABRT: u8 = 0x04;
const ATA_ER_TK0NF: u8 = 0x02;
const ATA_ER_AMNF: u8 = 0x01;

//Commands
const ATA_CMD_READ_PIO: u8 = 0x20;
const ATA_CMD_READ_PIO_EXT: u8 = 0x24;
const ATA_CMD_READ_DMA: u8 = 0xC8;
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
const ATA_CMD_WRITE_PIO: u8 = 0x30;
const ATA_CMD_WRITE_PIO_EXT: u8 = 0x34;
const ATA_CMD_WRITE_DMA: u8 = 0xCA;
const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35;
const ATA_CMD_CACHE_FLUSH: u8 = 0xE7;
const ATA_CMD_CACHE_FLUSH_EXT: u8 = 0xEA;
const ATA_CMD_PACKET: u8 = 0xA0;
const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1;
const ATA_CMD_IDENTIFY: u8 = 0xEC;

//Identification
const ATA_IDENT_DEVICETYPE: u8 = 0;
const ATA_IDENT_CYLINDERS: u8 = 2;
const ATA_IDENT_HEADS: u8 = 6;
const ATA_IDENT_SECTORS: u8 = 12;
const ATA_IDENT_SERIAL: u8 = 20;
const ATA_IDENT_MODEL: u8 = 54;
const ATA_IDENT_CAPABILITIES: u8 = 98;
const ATA_IDENT_FIELDVALID: u8 = 106;
const ATA_IDENT_MAX_LBA: u8 = 120;
const ATA_IDENT_COMMANDSETS: u8 = 164;
const ATA_IDENT_MAX_LBA_EXT: u8 = 200;

//Selection
const ATA_MASTER: u8 = 0x00;
const ATA_SLAVE: u8 = 0x01;

//Types
const IDE_ATA: u8 = 0x00;
const IDE_ATAPI: u8 = 0x01;

//Registers
const ATA_REG_DATA: u16 = 0x00;
const ATA_REG_ERROR: u16 = 0x01;
const ATA_REG_FEATURES: u16 = 0x01;
const ATA_REG_SECCOUNT0: u16 = 0x02;
const ATA_REG_LBA0: u16 = 0x03;
const ATA_REG_LBA1: u16 = 0x04;
const ATA_REG_LBA2: u16 = 0x05;
const ATA_REG_HDDEVSEL: u16 = 0x06;
const ATA_REG_COMMAND: u16 = 0x07;
const ATA_REG_STATUS: u16 = 0x07;
const ATA_REG_SECCOUNT1: u16 = 0x08;
const ATA_REG_LBA3: u16 = 0x09;
const ATA_REG_LBA4: u16 = 0x0A;
const ATA_REG_LBA5: u16 = 0x0B;
const ATA_REG_CONTROL: u16 = 0x0C;
const ATA_REG_ALTSTATUS: u16 = 0x0C;
const ATA_REG_DEVADDRESS: u16 = 0x0D;

pub struct PRDTE {
    pub ptr: u32,
    pub size: u16,
    pub reserved: u16
}

pub struct Disk{
    base: u16,
    ctrl: u16,
    master: bool
}

impl Disk {
    pub fn new() -> Disk{
        Disk{
            base: 0x1F0,
            ctrl: 0x3F4,
            master: true
        }
    }

    unsafe fn ide_read(&self, reg: u16) -> u8{
        let ret;
        if reg < 0x08 {
            ret = inb(self.base + reg - 0x00);
        } else if reg < 0x0C {
            ret = inb(self.base + reg - 0x06);
        } else if reg < 0x0E {
            ret = inb(self.ctrl + reg - 0x0A);
        }else{
            ret = 0;
        }
        ret
    }

    unsafe fn ide_write(&self, reg: u16, data: u8){
        if reg < 0x08 {
            outb(self.base + reg - 0x00, data);
        } else if reg < 0x0C {
            outb(self.base + reg - 0x06, data);
        } else if reg < 0x0E {
            outb(self.ctrl + reg - 0x0A, data);
        }
    }

    unsafe fn ide_poll(&self, check_error: bool) -> u8{
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);
        self.ide_read(ATA_REG_ALTSTATUS);

        while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

        }

        if check_error {
            let state = self.ide_read(ATA_REG_STATUS);
            if state & ATA_SR_ERR == ATA_SR_ERR {
                return 2;
            }
            if state & ATA_SR_DF == ATA_SR_DF {
                return 1;
            }
            if !(state & ATA_SR_DRQ == ATA_SR_DRQ) {
                return 3;
            }
        }

        return 0;
    }

    //TODO: Make sure count is not zero!
    pub unsafe fn read(&self, lba: u64, count: u16, destination: usize) -> u8{
        if destination > 0 {
            while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

            }

            if self.master {
                self.ide_write(ATA_REG_HDDEVSEL, 0x40);
            }else{
                self.ide_write(ATA_REG_HDDEVSEL, 0x50);
            }

            self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

            self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA0, (lba & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);
            self.ide_write(ATA_REG_COMMAND, ATA_CMD_READ_PIO_EXT);

            for sector in 0..count as usize {
                let err = self.ide_poll(true);
                if err > 0{
                    return err;
                }

                for word in 0..256 {
                    let data = inw(self.base + ATA_REG_DATA);
                    *((destination + sector*512 + word*2) as *mut u16) = data;
                }
            }
        }

        return 0;
    }

    pub unsafe fn read_dma(&self, lba: u64, count: u16, destination: usize, busmaster: u16) -> u8{
        if destination > 0 {
            //Allocate PDTR
            let mut prdt = ind(busmaster + 4) as usize;

            if prdt == 0 {
                let size = count as usize * 512;
                let entries = (size + 65535)/65536;
                prdt = alloc(size_of::<PRDTE>() * entries);
                for i in 0..entries {
                    if i == entries - 1 {
                        *(prdt as *mut PRDTE).offset(i as isize) = PRDTE {
                            ptr: (destination + i * 65536) as u32,
                            size: (size % 65536) as u16,
                            reserved: 0x8000
                        };
                    }else{
                        *(prdt as *mut PRDTE).offset(i as isize) = PRDTE {
                            ptr: (destination + i * 65536) as u32,
                            size: 0,
                            reserved: 0
                        };
                    }
                }

                outd(busmaster + 4, prdt as u32);

                //Set read bit
                outb(busmaster, 8);

                //Clear interrupt, error bit
                outb(busmaster + 2, 0);

                //DMA Transfer Command
                while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

                }

                if self.master {
                    self.ide_write(ATA_REG_HDDEVSEL, 0x40);
                }else{
                    self.ide_write(ATA_REG_HDDEVSEL, 0x50);
                }

                self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

                self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA0, (lba & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
                self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);
                self.ide_write(ATA_REG_COMMAND, ATA_CMD_READ_DMA_EXT);

                //Engage bus mastering
                outb(busmaster, inb(busmaster) | 1);
            }else{
                d("Operation Running!\n");
            }
        }

        return 0;
    }

    //TODO: Fix and make sure count is not zero!
    pub unsafe fn write(&self, lba: u64, count: u16, source: usize) -> u8{
        if source > 0 {
            while self.ide_read(ATA_REG_STATUS) & ATA_SR_BSY == ATA_SR_BSY {

            }

            if self.master {
                self.ide_write(ATA_REG_HDDEVSEL, 0x40);
            }else{
                self.ide_write(ATA_REG_HDDEVSEL, 0x50);
            }

            self.ide_write(ATA_REG_SECCOUNT1, ((count >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA3, ((lba >> 24) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA4, ((lba >> 32) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA5, ((lba >> 40) & 0xFF) as u8);

            self.ide_write(ATA_REG_SECCOUNT0, ((count >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA0, ((lba >> 0) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA1, ((lba >> 8) & 0xFF) as u8);
            self.ide_write(ATA_REG_LBA2, ((lba >> 16) & 0xFF) as u8);

            self.ide_write(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT);

            for sector in 0..count as usize {
                let err = self.ide_poll(true);
                if err > 0{
                    return err;
                }

                for word in 0..256 {
                    outw(self.base + ATA_REG_DATA, *((source + sector*512 + word*2) as *const u16));
                }

                self.ide_write(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH_EXT);
                self.ide_poll(false);
            }
        }

        return 0;
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

#[macro_export]
macro_rules! next {
     ($state:ident) => {
         (StateFn(stringify!($state), $state), Vec::new())
     };
     ($state:ident, $output:expr) => {
         (StateFn(stringify!($state), $state), $output)
     };
}

#[macro_export]
macro_rules! state_fn {
     ($state:ident) => {
         StateFn(stringify!($state), $state)
     }
}

pub trait FsmTypes: Sized {
    // The application state of the fsm
    type Context: Send + Clone + Debug;
    type Msg: Send + Clone + Debug;
    type Output: Send + Clone + Debug;
}

// A recursive tuple struct indicating the name of current state and the function pointer that
// handles messages in that that state. Calling that function returns a pair containing the next
// state and any output.
pub struct StateFn<T: FsmTypes>(
    pub &'static str,
    pub fn(&mut T::Context, T::Msg) -> (StateFn<T>, Vec<T::Output>)
);

// Function pointers aren't `Clone` due to this [bug](https://github.com/rust-lang/rust/issues/24000)
// Since we can't derive clone, we just implement it manually, since function pointers are `Copy`
impl<T: FsmTypes> Clone for StateFn<T> {
    fn clone(&self) -> StateFn<T> {
        StateFn(self.0, self.1)
    }
}

#[derive(Clone)]
pub struct Fsm<T: FsmTypes> {
    pub state: StateFn<T>,
    pub ctx: T::Context
}

impl<T: FsmTypes> Fsm<T> {
    pub fn new(ctx: T::Context, state: StateFn<T>) -> Fsm<T> {
        Fsm {
            state: state,
            ctx: ctx
        }
    }

    pub fn get_state(&self) -> (&'static str, &T::Context) {
        (self.state.0, &self.ctx)
    }

    pub fn send(&mut self, msg: T::Msg) -> Vec<T::Output> {
        let StateFn(_name, f) = self.state;
        let (new_state, output) = f(&mut self.ctx, msg);
        self.state = new_state;
        output
    }
}
<commit_msg>Enhance state_fn! to accept module qualified functions<commit_after>use std::fmt::Debug;

#[macro_export]
macro_rules! next {
     ($state:ident) => {
         (StateFn(stringify!($state), $state), Vec::new())
     };
     ($state:ident, $output:expr) => {
         (StateFn(stringify!($state), $state), $output)
     };
}

#[macro_export]
macro_rules! state_fn {
     ($state:ident) => {
         StateFn(stringify!($state), $state)
     };
     ($m:ident::$state:ident) => {
         StateFn(stringify!($state), $m::$state)
     }
}

pub trait FsmTypes: Sized {
    // The application state of the fsm
    type Context: Send + Clone + Debug;
    type Msg: Send + Clone + Debug;
    type Output: Send + Clone + Debug;
}

// A recursive tuple struct indicating the name of current state and the function pointer that
// handles messages in that that state. Calling that function returns a pair containing the next
// state and any output.
pub struct StateFn<T: FsmTypes>(
    pub &'static str,
    pub fn(&mut T::Context, T::Msg) -> (StateFn<T>, Vec<T::Output>)
);

// Function pointers aren't `Clone` due to this [bug](https://github.com/rust-lang/rust/issues/24000)
// Since we can't derive clone, we just implement it manually, since function pointers are `Copy`
impl<T: FsmTypes> Clone for StateFn<T> {
    fn clone(&self) -> StateFn<T> {
        StateFn(self.0, self.1)
    }
}

#[derive(Clone)]
pub struct Fsm<T: FsmTypes> {
    pub state: StateFn<T>,
    pub ctx: T::Context
}

impl<T: FsmTypes> Fsm<T> {
    pub fn new(ctx: T::Context, state: StateFn<T>) -> Fsm<T> {
        Fsm {
            state: state,
            ctx: ctx
        }
    }

    pub fn get_state(&self) -> (&'static str, &T::Context) {
        (self.state.0, &self.ctx)
    }

    pub fn send(&mut self, msg: T::Msg) -> Vec<T::Output> {
        let StateFn(_name, f) = self.state;
        let (new_state, output) = f(&mut self.ctx, msg);
        self.state = new_state;
        output
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate cc;
extern crate glob;

use std::env;
use std::fs;
use std::path::PathBuf;

fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.get(2) == Some(&"windows") {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target.get(3) == Some(&"gnu") {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}

fn fail_on_empty_directory(name: &str) {
    if fs::read_dir(name).unwrap().count() == 0 {
        println!(
            "The `{}` directory is empty, did you forget to pull the submodules?",
            name
        );
        println!("Try `git submodule update --init --recursive`");
        panic!();
    }
}

fn bindgen_rocksdb() {
    let bindings = bindgen::Builder::default()
        .header("rocksdb/include/rocksdb/c.h")
        .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550
        .ctypes_prefix("libc")
        .generate()
        .expect("unable to generate rocksdb bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("unable to write rocksdb bindings");
}

fn build_rocksdb() {
    let target = env::var("TARGET").unwrap();

    let mut config = cc::Build::new();
    config.include("rocksdb/include/");
    config.include("rocksdb/");
    config.include("rocksdb/third-party/gtest-1.7.0/fused-src/");

    if cfg!(feature = "snappy") {
        config.define("SNAPPY", Some("1"));
        config.include("snappy/");
    }

    if cfg!(feature = "lz4") {
        config.define("LZ4", Some("1"));
        config.include("lz4/lib/");
    }

    if cfg!(feature = "zstd") {
        config.define("ZSTD", Some("1"));
        config.include("zstd/lib/");
        config.include("zstd/lib/dictBuilder/");
    }

    if cfg!(feature = "zlib") {
        config.define("ZLIB", Some("1"));
        config.include("zlib/");
    }

    if cfg!(feature = "bzip2") {
        config.define("BZIP2", Some("1"));
        config.include("bzip2/");
    }

    config.include(".");
    config.define("NDEBUG", Some("1"));

    let mut lib_sources = include_str!("rocksdb_lib_sources.txt")
        .split(" ")
        .collect::<Vec<&'static str>>();

    // We have a pregenerated a version of build_version.cc in the local directory
    lib_sources = lib_sources
        .iter()
        .cloned()
        .filter(|file| *file != "util/build_version.cc")
        .collect::<Vec<&'static str>>();

    if target.contains("x86_64") {
        // This is needed to enable hardware CRC32C. Technically, SSE 4.2 is
        // only available since Intel Nehalem (about 2010) and AMD Bulldozer
        // (about 2011).
        config.define("HAVE_PCLMUL", Some("1"));
        config.define("HAVE_SSE42", Some("1"));
        config.flag("-msse2");
        config.flag("-msse4.1");
        config.flag("-msse4.2");
        config.flag("-mpclmul");
    }

    if target.contains("darwin") {
        config.define("OS_MACOSX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }
    if target.contains("linux") {
        config.define("OS_LINUX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
        // COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
    }
    if target.contains("freebsd") {
        config.define("OS_FREEBSD", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }

    if target.contains("windows") {
        link("rpcrt4", false);
        link("shlwapi", false);
        config.define("OS_WIN", Some("1"));
        config.define("ROCKSDB_WINDOWS_UTF8_FILENAMES", Some("1"));

        // Remove POSIX-specific sources
        lib_sources = lib_sources
            .iter()
            .cloned()
            .filter(|file| match *file {
                "port/port_posix.cc" | "env/env_posix.cc" | "env/io_posix.cc" => false,
                _ => true,
            })
            .collect::<Vec<&'static str>>();

        // Add Windows-specific sources
        lib_sources.push("port/win/port_win.cc");
        lib_sources.push("port/win/env_win.cc");
        lib_sources.push("port/win/env_default.cc");
        lib_sources.push("port/win/win_logger.cc");
        lib_sources.push("port/win/io_win.cc");
        lib_sources.push("port/win/win_thread.cc");
    }

    if target.contains("msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
        // this was breaking the build on travis due to
        // > 4mb of warnings emitted.
        config.flag("-Wno-unused-parameter");
    }

    for file in lib_sources {
        let file = "rocksdb/".to_string() + file;
        config.file(&file);
    }

    config.file("build_version.cc");

    config.cpp(true);
    config.compile("librocksdb.a");
}

fn build_snappy() {
    let target = env::var("TARGET").unwrap();

    let mut config = cc::Build::new();
    config.include("snappy/");
    config.include(".");

    config.define("NDEBUG", Some("1"));

    if target.contains("msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
    }

    config.file("snappy/snappy.cc");
    config.file("snappy/snappy-sinksource.cc");
    config.file("snappy/snappy-c.cc");
    config.cpp(true);
    config.compile("libsnappy.a");
}

fn build_lz4() {
    let mut compiler = cc::Build::new();

    compiler
        .file("lz4/lib/lz4.c")
        .file("lz4/lib/lz4frame.c")
        .file("lz4/lib/lz4hc.c")
        .file("lz4/lib/xxhash.c");

    compiler.opt_level(3);

    match env::var("TARGET").unwrap().as_str() {
        "i686-pc-windows-gnu" => {
            compiler.flag("-fno-tree-vectorize");
        }
        _ => {}
    }

    compiler.compile("liblz4.a");
}

fn build_zstd() {
    let mut compiler = cc::Build::new();

    compiler.include("zstd/lib/");
    compiler.include("zstd/lib/common");
    compiler.include("zstd/lib/legacy");

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/dictBuilder/*.c",
        "zstd/lib/legacy/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.opt_level(3);

    compiler.define("ZSTD_LIB_DEPRECATED", Some("0"));
    compiler.compile("libzstd.a");
}

fn build_zlib() {
    let mut compiler = cc::Build::new();

    let globs = &["zlib/*.c"];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.flag_if_supported("-Wno-implicit-function-declaration");
    compiler.opt_level(3);
    compiler.compile("libz.a");
}

fn build_bzip2() {
    let mut compiler = cc::Build::new();

    compiler
        .file("bzip2/blocksort.c")
        .file("bzip2/bzlib.c")
        .file("bzip2/compress.c")
        .file("bzip2/crctable.c")
        .file("bzip2/decompress.c")
        .file("bzip2/huffman.c")
        .file("bzip2/randtable.c");

    compiler
        .define("_FILE_OFFSET_BITS", Some("64"))
        .define("BZ_NO_STDIO", None);

    compiler.extra_warnings(false);
    compiler.opt_level(3);
    compiler.compile("libbz2.a");
}

fn try_to_find_and_link_lib(lib_name: &str) -> bool {
    if let Ok(lib_dir) = env::var(&format!("{}_LIB_DIR", lib_name)) {
        println!("cargo:rustc-link-search=native={}", lib_dir);
        let mode = match env::var_os(&format!("{}_STATIC", lib_name)) {
            Some(_) => "static",
            None => "dylib",
        };
        println!("cargo:rustc-link-lib={}={}", mode, lib_name.to_lowercase());
        return true;
    }
    false
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=rocksdb/");
    println!("cargo:rerun-if-changed=snappy/");
    println!("cargo:rerun-if-changed=lz4/");
    println!("cargo:rerun-if-changed=zstd/");
    println!("cargo:rerun-if-changed=zlib/");
    println!("cargo:rerun-if-changed=bzip2/");

    fail_on_empty_directory("rocksdb");
    fail_on_empty_directory("snappy");
    fail_on_empty_directory("lz4");
    fail_on_empty_directory("zstd");
    fail_on_empty_directory("zlib");
    fail_on_empty_directory("bzip2");

    bindgen_rocksdb();

    if !try_to_find_and_link_lib("ROCKSDB") {
        build_rocksdb();
    }
    if cfg!(feature = "snappy") && !try_to_find_and_link_lib("SNAPPY") {
        build_snappy();
    }
    if cfg!(feature = "lz4") && !try_to_find_and_link_lib("LZ4") {
        build_lz4();
    }
    if cfg!(feature = "zstd") && !try_to_find_and_link_lib("ZSTD") {
        build_zstd();
    }
    if cfg!(feature = "zlib") && !try_to_find_and_link_lib("ZLIB") {
        build_zlib();
    }
    if cfg!(feature = "bzip2") && !try_to_find_and_link_lib("BZIP2") {
        build_bzip2();
    }
}
<commit_msg>Try to fix build on windows<commit_after>extern crate bindgen;
extern crate cc;
extern crate glob;

use std::env;
use std::fs;
use std::path::PathBuf;

fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.get(2) == Some(&"windows") {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target.get(3) == Some(&"gnu") {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}

fn fail_on_empty_directory(name: &str) {
    if fs::read_dir(name).unwrap().count() == 0 {
        println!(
            "The `{}` directory is empty, did you forget to pull the submodules?",
            name
        );
        println!("Try `git submodule update --init --recursive`");
        panic!();
    }
}

fn bindgen_rocksdb() {
    let bindings = bindgen::Builder::default()
        .header("rocksdb/include/rocksdb/c.h")
        .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550
        .ctypes_prefix("libc")
        .generate()
        .expect("unable to generate rocksdb bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("unable to write rocksdb bindings");
}

fn build_rocksdb() {
    let target = env::var("TARGET").unwrap();

    let mut config = cc::Build::new();
    config.include("rocksdb/include/");
    config.include("rocksdb/");
    config.include("rocksdb/third-party/gtest-1.7.0/fused-src/");

    if cfg!(feature = "snappy") {
        config.define("SNAPPY", Some("1"));
        config.include("snappy/");
    }

    if cfg!(feature = "lz4") {
        config.define("LZ4", Some("1"));
        config.include("lz4/lib/");
    }

    if cfg!(feature = "zstd") {
        config.define("ZSTD", Some("1"));
        config.include("zstd/lib/");
        config.include("zstd/lib/dictBuilder/");
    }

    if cfg!(feature = "zlib") {
        config.define("ZLIB", Some("1"));
        config.include("zlib/");
    }

    if cfg!(feature = "bzip2") {
        config.define("BZIP2", Some("1"));
        config.include("bzip2/");
    }

    config.include(".");
    config.define("NDEBUG", Some("1"));

    let mut lib_sources = include_str!("rocksdb_lib_sources.txt")
        .split(" ")
        .collect::<Vec<&'static str>>();

    // We have a pregenerated a version of build_version.cc in the local directory
    lib_sources = lib_sources
        .iter()
        .cloned()
        .filter(|file| *file != "util/build_version.cc")
        .collect::<Vec<&'static str>>();

    if target.contains("x86_64") {
        // This is needed to enable hardware CRC32C. Technically, SSE 4.2 is
        // only available since Intel Nehalem (about 2010) and AMD Bulldozer
        // (about 2011).
        config.define("HAVE_PCLMUL", Some("1"));
        config.define("HAVE_SSE42", Some("1"));
        config.flag_if_supported("-msse2");
        config.flag_if_supported("-msse4.1");
        config.flag_if_supported("-msse4.2");
        config.flag_if_supported("-mpclmul");
    }

    if target.contains("darwin") {
        config.define("OS_MACOSX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }
    if target.contains("linux") {
        config.define("OS_LINUX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
        // COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
    }
    if target.contains("freebsd") {
        config.define("OS_FREEBSD", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }

    if target.contains("windows") {
        link("rpcrt4", false);
        link("shlwapi", false);
        config.define("OS_WIN", Some("1"));
        config.define("ROCKSDB_WINDOWS_UTF8_FILENAMES", Some("1"));

        // Remove POSIX-specific sources
        lib_sources = lib_sources
            .iter()
            .cloned()
            .filter(|file| match *file {
                "port/port_posix.cc" | "env/env_posix.cc" | "env/io_posix.cc" => false,
                _ => true,
            })
            .collect::<Vec<&'static str>>();

        // Add Windows-specific sources
        lib_sources.push("port/win/port_win.cc");
        lib_sources.push("port/win/env_win.cc");
        lib_sources.push("port/win/env_default.cc");
        lib_sources.push("port/win/win_logger.cc");
        lib_sources.push("port/win/io_win.cc");
        lib_sources.push("port/win/win_thread.cc");
    }

    if target.contains("msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
        // this was breaking the build on travis due to
        // > 4mb of warnings emitted.
        config.flag("-Wno-unused-parameter");
    }

    for file in lib_sources {
        let file = "rocksdb/".to_string() + file;
        config.file(&file);
    }

    config.file("build_version.cc");

    config.cpp(true);
    config.compile("librocksdb.a");
}

fn build_snappy() {
    let target = env::var("TARGET").unwrap();

    let mut config = cc::Build::new();
    config.include("snappy/");
    config.include(".");

    config.define("NDEBUG", Some("1"));

    if target.contains("msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
    }

    config.file("snappy/snappy.cc");
    config.file("snappy/snappy-sinksource.cc");
    config.file("snappy/snappy-c.cc");
    config.cpp(true);
    config.compile("libsnappy.a");
}

fn build_lz4() {
    let mut compiler = cc::Build::new();

    compiler
        .file("lz4/lib/lz4.c")
        .file("lz4/lib/lz4frame.c")
        .file("lz4/lib/lz4hc.c")
        .file("lz4/lib/xxhash.c");

    compiler.opt_level(3);

    match env::var("TARGET").unwrap().as_str() {
        "i686-pc-windows-gnu" => {
            compiler.flag("-fno-tree-vectorize");
        }
        _ => {}
    }

    compiler.compile("liblz4.a");
}

fn build_zstd() {
    let mut compiler = cc::Build::new();

    compiler.include("zstd/lib/");
    compiler.include("zstd/lib/common");
    compiler.include("zstd/lib/legacy");

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/dictBuilder/*.c",
        "zstd/lib/legacy/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.opt_level(3);

    compiler.define("ZSTD_LIB_DEPRECATED", Some("0"));
    compiler.compile("libzstd.a");
}

fn build_zlib() {
    let mut compiler = cc::Build::new();

    let globs = &["zlib/*.c"];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.flag_if_supported("-Wno-implicit-function-declaration");
    compiler.opt_level(3);
    compiler.compile("libz.a");
}

fn build_bzip2() {
    let mut compiler = cc::Build::new();

    compiler
        .file("bzip2/blocksort.c")
        .file("bzip2/bzlib.c")
        .file("bzip2/compress.c")
        .file("bzip2/crctable.c")
        .file("bzip2/decompress.c")
        .file("bzip2/huffman.c")
        .file("bzip2/randtable.c");

    compiler
        .define("_FILE_OFFSET_BITS", Some("64"))
        .define("BZ_NO_STDIO", None);

    compiler.extra_warnings(false);
    compiler.opt_level(3);
    compiler.compile("libbz2.a");
}

fn try_to_find_and_link_lib(lib_name: &str) -> bool {
    if let Ok(lib_dir) = env::var(&format!("{}_LIB_DIR", lib_name)) {
        println!("cargo:rustc-link-search=native={}", lib_dir);
        let mode = match env::var_os(&format!("{}_STATIC", lib_name)) {
            Some(_) => "static",
            None => "dylib",
        };
        println!("cargo:rustc-link-lib={}={}", mode, lib_name.to_lowercase());
        return true;
    }
    false
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=rocksdb/");
    println!("cargo:rerun-if-changed=snappy/");
    println!("cargo:rerun-if-changed=lz4/");
    println!("cargo:rerun-if-changed=zstd/");
    println!("cargo:rerun-if-changed=zlib/");
    println!("cargo:rerun-if-changed=bzip2/");

    fail_on_empty_directory("rocksdb");
    fail_on_empty_directory("snappy");
    fail_on_empty_directory("lz4");
    fail_on_empty_directory("zstd");
    fail_on_empty_directory("zlib");
    fail_on_empty_directory("bzip2");

    bindgen_rocksdb();

    if !try_to_find_and_link_lib("ROCKSDB") {
        build_rocksdb();
    }
    if cfg!(feature = "snappy") && !try_to_find_and_link_lib("SNAPPY") {
        build_snappy();
    }
    if cfg!(feature = "lz4") && !try_to_find_and_link_lib("LZ4") {
        build_lz4();
    }
    if cfg!(feature = "zstd") && !try_to_find_and_link_lib("ZSTD") {
        build_zstd();
    }
    if cfg!(feature = "zlib") && !try_to_find_and_link_lib("ZLIB") {
        build_zlib();
    }
    if cfg!(feature = "bzip2") && !try_to_find_and_link_lib("BZIP2") {
        build_bzip2();
    }
}
<|endoftext|>