<commit_before>use std;
use std::collections::HashMap;
use std::{fmt, io, result};
use std::fmt::Display;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc::{self, channel, Receiver, Sender};

use message;

#[derive(Debug)]
pub enum Error {
    NotificationSend(mpsc::SendError<Option<message::Notification>>),
    Message(message::Error),
    Io(io::Error),
}

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

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::NotificationSend(ref err) => Some(err),
            Error::Message(ref err) => Some(err),
            Error::Io(ref err) => Some(err),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        std::error::Error::description(self).fmt(f)
    }
}

impl From<message::Error> for Error {
    fn from(err: message::Error) -> Error {
        Error::Message(err)
    }
}

impl From<mpsc::SendError<Option<message::Notification>>> for Error {
    fn from(err: mpsc::SendError<Option<message::Notification>>) -> Error {
        Error::NotificationSend(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

pub type Result<T> = result::Result<T, Error>;

pub fn execute(host: String, port: i32) -> Result<()> {
    let listener = try!(TcpListener::bind(&format!("{}:{}", host, port)[..]));
    let mut channels = Channels { channels: HashMap::new() };

    info!("Starting hokaido server on {}", listener.local_addr().unwrap());

    for stream in listener.incoming() {
        let _ = handle_client(stream, &mut channels);
    }

    Ok(())
}

fn handle_client(stream: result::Result<TcpStream, io::Error>, channels: &mut Channels) -> Result<()> {
    let stream = try!(stream);
    let request = try!(message::JoinRequest::receive(&stream));

    info!("{} Connected", stream.peer_addr().unwrap());

    match request {
        message::JoinRequest::Broadcast(ch) =>
            BroadcastHandler::spawn(&stream, channels.fetch(&ch)),
        message::JoinRequest::Watch(ch) =>
            WatchHandler::spawn(&stream, channels.fetch(&ch)),
    }

    Ok(())
}

struct Channels {
    channels: HashMap<String, Arc<Mutex<Channel>>>,
}

struct Channel {
    broadcaster: Option<TcpStream>,
    watchers: Vec<TcpStream>,
}

struct BroadcastHandler {
    stream: TcpStream,
    channel: Arc<Mutex<Channel>>,
}

struct WatchHandler {
    stream: TcpStream,
    channel: Arc<Mutex<Channel>>,
}

impl Channels {
    fn fetch<K: AsRef<str>>(&mut self, key: &K) -> &Arc<Mutex<Channel>> {
        let ch = key.as_ref();

        if self.channels.contains_key(&ch[..]) {
            self.channels.get(&ch[..]).unwrap()
        } else {
            let channel = Channel {
                broadcaster: None,
                watchers: Vec::new(),
            };

            info!("Creating new channel: {}", ch);
            self.channels.insert(ch.to_owned(), Arc::new(Mutex::new(channel)));

            self.fetch(&ch)
        }
    }
}

impl Channel {
    fn takeover(&mut self, stream: TcpStream) -> Result<()> {
        match self.broadcaster.as_mut() {
            Some(mut current) => {
                info!("{} Takeover from {}", stream.peer_addr().unwrap(), current.peer_addr().unwrap());

                try!(message::Notification::Closed("Broadcaster has changed".to_owned()).send(&mut current));
                try!(current.shutdown(Shutdown::Both));
            }
            None => ()
        }

        self.broadcaster = Some(stream);
        Ok(())
    }
}

impl BroadcastHandler {
    fn spawn(stream: &TcpStream, channel: &Arc<Mutex<Channel>>) {
        info!("{} Broadcast", stream.peer_addr().unwrap());

        let mut handler = BroadcastHandler {
            stream: stream.try_clone().unwrap(),
            channel: channel.clone(),
        };

        let _ = channel.lock().and_then(|mut ch| {
            let _ = ch.takeover(stream.try_clone().unwrap());
            Ok(ch)
        });

        thread::spawn(move || {
            handler.process().unwrap_or_else(|e| {
                warn!("{}", e);
            });

            info!("{} Shutting down", handler.stream.peer_addr().unwrap());
            let _ = handler.stream.shutdown(Shutdown::Both);
        });
    }

    fn process(&mut self) -> Result<()> {
        try!(message::JoinResponse::Success.send(&mut self.stream));

        let (sender, receiver) = channel();

        try!(self.spawn_relay(sender.clone()));
        try!(self.broadcast(receiver));

        Ok(())
    }

    fn spawn_relay(&self, sender: Sender<Option<message::Notification>>) -> Result<()> {
        let stream = try!(self.stream.try_clone());

        thread::spawn(move || -> Result<()> {
            while let Ok(notification) = message::Notification::receive(&stream) {
                match notification {
                    message::Notification::Output(data)   => {
                        sender.send(Some(message::Notification::Output(data))).unwrap_or_else(|e| warn!("{}", e));
                    }
                    _ => break,
                }
            };

            info!("{} Relay stopped", stream.peer_addr().unwrap());

            try!(sender.send(None));

            Ok(())
        });

        Ok(())
    }

    fn broadcast(&self, receiver: Receiver<Option<message::Notification>>) -> Result<()> {
        for message in receiver {
            match message {
                Some(notification) => {
                    let mut channel = self.channel.lock().unwrap();

                    for watcher in &mut channel.watchers {
                        let _ = notification.send(watcher);
                    }
                },
                None => break
            }
        }

        Ok(())
    }
}

impl WatchHandler {
    fn spawn(stream: &TcpStream, channel: &Arc<Mutex<Channel>>) {
        info!("{} Watch", stream.peer_addr().unwrap());

        let mut handler = WatchHandler {
            stream: stream.try_clone().unwrap(),
            channel: channel.clone(),
        };

        thread::spawn(move || {
            handler.process().unwrap_or_else(|e| {
                warn!("{}", e);
            });
        });
    }

    fn process(&mut self) -> Result<()> {
        try!(message::JoinResponse::Success.send(&mut self.stream));

        let mut channel = self.channel.lock().unwrap();

        channel.watchers.push(try!(self.stream.try_clone()));

        match channel.broadcaster.as_mut() {
            Some(mut broadcaster) => message::Notification::WatcherJoined("".to_owned())
                                         .send(&mut broadcaster)
                                         .unwrap(),
            None => ()
        }

        Ok(())
    }
}
<commit_msg>Don't have to notify to the former broadcaster if it has already gone<commit_after>use std;
use std::collections::HashMap;
use std::{fmt, io, result};
use std::fmt::Display;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc::{self, channel, Receiver, Sender};

use message;

#[derive(Debug)]
pub enum Error {
    NotificationSend(mpsc::SendError<Option<message::Notification>>),
    Message(message::Error),
    Io(io::Error),
}

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

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::NotificationSend(ref err) => Some(err),
            Error::Message(ref err) => Some(err),
            Error::Io(ref err) => Some(err),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        std::error::Error::description(self).fmt(f)
    }
}

impl From<message::Error> for Error {
    fn from(err: message::Error) -> Error {
        Error::Message(err)
    }
}

impl From<mpsc::SendError<Option<message::Notification>>> for Error {
    fn from(err: mpsc::SendError<Option<message::Notification>>) -> Error {
        Error::NotificationSend(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

pub type Result<T> = result::Result<T, Error>;

pub fn execute(host: String, port: i32) -> Result<()> {
    let listener = try!(TcpListener::bind(&format!("{}:{}", host, port)[..]));
    let mut channels = Channels { channels: HashMap::new() };

    info!("Starting hokaido server on {}", listener.local_addr().unwrap());

    for stream in listener.incoming() {
        let _ = handle_client(stream, &mut channels);
    }

    Ok(())
}

fn handle_client(stream: result::Result<TcpStream, io::Error>, channels: &mut Channels) -> Result<()> {
    let stream = try!(stream);
    let request = try!(message::JoinRequest::receive(&stream));

    info!("{} Connected", stream.peer_addr().unwrap());

    match request {
        message::JoinRequest::Broadcast(ch) =>
            BroadcastHandler::spawn(&stream, channels.fetch(&ch)),
        message::JoinRequest::Watch(ch) =>
            WatchHandler::spawn(&stream, channels.fetch(&ch)),
    }

    Ok(())
}

struct Channels {
    channels: HashMap<String, Arc<Mutex<Channel>>>,
}

struct Channel {
    broadcaster: Option<TcpStream>,
    watchers: Vec<TcpStream>,
}

struct BroadcastHandler {
    stream: TcpStream,
    channel: Arc<Mutex<Channel>>,
}

struct WatchHandler {
    stream: TcpStream,
    channel: Arc<Mutex<Channel>>,
}

impl Channels {
    fn fetch<K: AsRef<str>>(&mut self, key: &K) -> &Arc<Mutex<Channel>> {
        let ch = key.as_ref();

        if self.channels.contains_key(&ch[..]) {
            self.channels.get(&ch[..]).unwrap()
        } else {
            let channel = Channel {
                broadcaster: None,
                watchers: Vec::new(),
            };

            info!("Creating new channel: {}", ch);
            self.channels.insert(ch.to_owned(), Arc::new(Mutex::new(channel)));

            self.fetch(&ch)
        }
    }
}

impl Channel {
    fn takeover(&mut self, stream: TcpStream) -> Result<()> {
        match self.broadcaster.as_mut() {
            Some(mut former) => {
                match former.peer_addr() {
                    Ok(addr) => {
                        info!("{} Takeover from {}", stream.peer_addr().unwrap(), addr);

                        try!(message::Notification::Closed("Broadcaster has changed".to_owned()).send(&mut former));
                        try!(former.shutdown(Shutdown::Both));
                    }
                    Err(_) => () // former has gone
                }
            }
            None => () // no broadcaster yet
        }

        self.broadcaster = Some(stream);

        Ok(())
    }
}

impl BroadcastHandler {
    fn spawn(stream: &TcpStream, channel: &Arc<Mutex<Channel>>) {
        info!("{} Broadcast", stream.peer_addr().unwrap());

        let mut handler = BroadcastHandler {
            stream: stream.try_clone().unwrap(),
            channel: channel.clone(),
        };

        let _ = channel.lock().and_then(|mut ch| {
            let _ = ch.takeover(stream.try_clone().unwrap());
            Ok(ch)
        });

        thread::spawn(move || {
            handler.process().unwrap_or_else(|e| {
                warn!("{}", e);
            });

            info!("{} Shutting down", handler.stream.peer_addr().unwrap());
            let _ = handler.stream.shutdown(Shutdown::Both);
        });
    }

    fn process(&mut self) -> Result<()> {
        try!(message::JoinResponse::Success.send(&mut self.stream));

        let (sender, receiver) = channel();

        try!(self.spawn_relay(sender.clone()));
        try!(self.broadcast(receiver));

        Ok(())
    }

    fn spawn_relay(&self, sender: Sender<Option<message::Notification>>) -> Result<()> {
        let stream = try!(self.stream.try_clone());

        thread::spawn(move || -> Result<()> {
            while let Ok(notification) = message::Notification::receive(&stream) {
                match notification {
                    message::Notification::Output(data)   => {
                        sender.send(Some(message::Notification::Output(data))).unwrap_or_else(|e| warn!("{}", e));
                    }
                    _ => break,
                }
            };

            info!("{} Relay stopped", stream.peer_addr().unwrap());

            try!(sender.send(None));

            Ok(())
        });

        Ok(())
    }

    fn broadcast(&self, receiver: Receiver<Option<message::Notification>>) -> Result<()> {
        for message in receiver {
            match message {
                Some(notification) => {
                    let mut channel = self.channel.lock().unwrap();

                    for watcher in &mut channel.watchers {
                        let _ = notification.send(watcher);
                    }
                },
                None => break
            }
        }

        Ok(())
    }
}

impl WatchHandler {
    fn spawn(stream: &TcpStream, channel: &Arc<Mutex<Channel>>) {
        info!("{} Watch", stream.peer_addr().unwrap());

        let mut handler = WatchHandler {
            stream: stream.try_clone().unwrap(),
            channel: channel.clone(),
        };

        thread::spawn(move || {
            handler.process().unwrap_or_else(|e| {
                warn!("{}", e);
            });
        });
    }

    fn process(&mut self) -> Result<()> {
        try!(message::JoinResponse::Success.send(&mut self.stream));

        let mut channel = self.channel.lock().unwrap();

        channel.watchers.push(try!(self.stream.try_clone()));

        match channel.broadcaster.as_mut() {
            Some(mut broadcaster) => message::Notification::WatcherJoined("".to_owned())
                                         .send(&mut broadcaster)
                                         .unwrap(),
            None => ()
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! This module implements the basic structures of an atomic system.
//!
//! A final ```System``` consists of a set of ```Residue```s, which
//! can be moved around and translated with ease. Each ```Residue```
//! in turn consists of some ```Atom```s. These atoms have positions
//! relative to their parent.
//!
//! This somewhat convoluted structure is inherited from molecular
//! simulation packages in which atoms are commonly grouped as such.
//!  A proper physical way to look at is that atoms can be
//! similarly grouped into molecules.

/// A finalized atomic system which consists of a list of residues, each of which contains
/// some atoms.
pub struct System {
    /// System dimensions.
    pub dimensions: Coord,
    /// List of residues.
    pub residues: Vec<Residue>,
}

impl System {
    /// Count and return the number of atoms in the system.
    pub fn num_atoms(&self) -> usize {
        self.residues.iter().map(|r| r.atoms.len()).sum()
    }

    /// Translate all residues within the system and return a copy.
    pub fn translate(&self, add: &Coord) -> System {
        System {
            dimensions: self.dimensions,
            residues: self.residues.iter().map(|r| r.translate(&add)).collect(),
        }
    }
}

/// Every residue has a name and a list of atoms that belong to it
/// with their relative base coordinates. The names are static since
/// they are generated only once from a single source.
pub struct Residue {
    /// Residue code.
    pub code: &'static str,
    /// Position of residue in system.
    pub position: Coord,
    /// List of atoms belonging to the residue. Their positions are relative to the residue.
    pub atoms: Vec<Atom>,
}

impl Residue {
    /// Translate the residue position. Does not alter the atom relative positions.
    fn translate(&self, add: &Coord) -> Residue {
        Residue {
            code: self.code,
            position: self.position.add(&add),
            atoms: self.atoms.clone(),
        }
    }
}

/// A base for generating atoms belonging to a residue.
#[derive(Debug, PartialEq)]
pub struct ResidueBase {
    pub code: &'static str,
    pub atoms: Vec<Atom>,
}

impl ResidueBase {
    /// Generate a proper residue at the input position.
    pub fn to_residue(&self, position: &Coord) -> Residue {
        Residue {
            code: self.code,
            position: *position,
            atoms: self.atoms.clone(),
        }
    }

    /// Graphene is a single carbon atom at each lattice point.
    pub fn graphene(bond_length: f64) -> ResidueBase {
        let dx = bond_length / 2.0;
        ResidueBase {
            code: "GRPH",
            atoms: vec![Atom {
                            code: "C",
                            position: Coord::new(dx, dx, 0.0),
                        }],
        }
    }

    /// Silica is a rigid SiO2 molecule at each lattice point.
    pub fn silica(bond_length: f64) -> ResidueBase {
        let dz = 0.151;
        let base_coord = Coord::new(bond_length / 4.0, bond_length / 6.0, 0.0);

        ResidueBase {
            code: "SIO",
            atoms: vec![Atom {
                            code: "O1",
                            position: base_coord.add(&Coord::new(0.0, 0.0, dz)),
                        },
                        Atom {
                            code: "SI",
                            position: base_coord,
                        },
                        Atom {
                            code: "O2",
                            position: base_coord.add(&Coord::new(0.0, 0.0, -dz)),
                        }],
        }
    }
}

#[macro_export]
/// Construct a ResidueBase with a code and atoms.
///
/// At least one atom has to be present in the base. This is not a limitation
/// when explicitly constructing a residue, but it makes no sense to allow
/// it when invoking a constructor like this.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate grafen;
/// use grafen::system::{Atom, Coord, ResidueBase};
/// # fn main() {
///
/// let expect = ResidueBase {
///     code: "RES",
///     atoms: vec![
///         Atom { code: "A", position: Coord::new(0.0, 0.0, 0.0) },
///         Atom { code: "B", position: Coord::new(1.0, 2.0, 3.0) }
///     ],
/// };
///
/// let residue = resbase![
///     "RES",
///     ("A", 0.0, 0.0, 0.0),
///     ("B", 1.0, 2.0, 3.0)
/// ];
///
/// assert_eq!(expect, residue);
/// # }
/// ```
macro_rules! resbase {
    (
        $rescode:expr,
        $(($atname:expr, $x:expr, $y:expr, $z:expr)),+
    ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push(
                    Atom {
                        code: $atname,
                        position: Coord::new($x, $y, $z),
                    }
                );
            )*

            ResidueBase {
                code: $rescode,
                atoms: temp_vec,
            }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
/// Every atom in a residue has their own code and relative
/// position some base coordinate.
pub struct Atom {
    /// Atom code.
    pub code: &'static str,
    /// Relative position.
    pub position: Coord,
}

#[derive(Clone, Copy, Debug)]
/// A three-dimensional coordinate.
///
/// # Examples
/// ```
/// use grafen::system::Coord;
///
/// let coord1 = Coord::new(1.0, 0.0, 1.0);
/// let coord2 = Coord::new(0.5, 0.5, 0.5);
///
/// assert_eq!(Coord::new(1.5, 0.5, 1.5), coord1.add(&coord2));
/// ```
pub struct Coord {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Coord {
    /// Construct a new coordinate.
    pub fn new(x: f64, y: f64, z: f64) -> Coord {
        Coord { x: x, y: y, z: z }
    }

    /// Add a coordinate to another.
    pub fn add(&self, other: &Coord) -> Coord {
        Coord::new(self.x + other.x, self.y + other.y, self.z + other.z)
    }
}

impl PartialEq for Coord {
    fn eq(&self, other: &Coord) -> bool {
        let atol = 1e-9;
        (self.x - other.x).abs() < atol
            && (self.y - other.y).abs() < atol
            && (self.z - other.z).abs() < atol
    }
}

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

    #[test]
    fn coord_translations() {
        let coord = Coord::new(0.0, 1.0, 2.0);
        let coord_add = coord.add(&coord);
        let expected = Coord::new(0.0, 2.0, 4.0);
        assert_eq!(expected, coord_add);
    }

    #[test]
    fn coord_eq_tolerance_small_deviation_passes() {
        // Allow for some deviation when testing for equality, since floating point
        // numbers are stupid.
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-10, 2e-10, 3e-10));
    }

    #[test]
    #[should_panic]
    fn coord_eq_tolerance_larger_deviation_does_not() {
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-9, 2e-9, 3e-9));
    }

    // A simple system with two different residues and five atoms
    fn setup_system() -> System {
        let coord0 = Coord::new(0.0, 0.0, 0.0);

        let residue_one = Residue {
            code: "R1",
            position: Coord::new(0.0, 0.0, 0.0),
            atoms: vec![
                Atom { code: "A1", position: coord0, },
                Atom { code: "A2", position: coord0, },
                Atom { code: "A3", position: coord0, },
            ]
        };
        let residue_two = Residue {
            code: "R2",
            position: Coord::new(1.0, 1.0, 1.0),
            atoms: vec![
                Atom { code: "B1", position: coord0, },
                Atom { code: "B2", position: coord0, },
            ]
        };

        System {
            dimensions: Coord::new(0.0, 0.0, 0.0),
            residues: vec![
                residue_one,
                residue_two
            ]
        }
    }

    #[test]
    fn count_atoms_in_system() {
        let system = setup_system();
        assert_eq!(5, system.num_atoms());
    }

    #[test]
    fn translate_a_system() {
        let system = setup_system();
        let translate = Coord::new(0.0, 1.0, 2.0);

        let translated_system = system.translate(&translate);
        for (orig, updated) in system.residues.iter().zip(translated_system.residues.iter()) {
            assert_eq!(orig.position.add(&translate), updated.position);
        }
    }

    #[test]
    fn residue_base_to_residue() {
        let base = ResidueBase {
            code: "RES",
            atoms: vec![
                Atom { code: "A1", position: Coord::new(0.0, 0.0, 0.0) },
                Atom { code: "A2", position: Coord::new(0.0, 1.0, 2.0) }
            ],
        };
        let position = Coord::new(1.0, 1.0, 1.0);

        let residue = base.to_residue(&position);
        assert_eq!("RES", residue.code);
        assert_eq!(position, residue.position);
        assert_eq!(base.atoms, residue.atoms);
    }

    #[test]
    fn create_residue_base_macro() {
        let expect = ResidueBase {
            code: "RES",
            atoms: vec![
                Atom { code: "A1", position: Coord::new(0.0, 0.0, 0.0) },
                Atom { code: "A2", position: Coord::new(0.0, 1.0, 2.0) }
            ],
        };
        let result = resbase![
            "RES",
            ("A1", 0.0, 0.0, 0.0),
            ("A2", 0.0, 1.0, 2.0)
        ];

        assert_eq!(expect, result);
    }
}
<commit_msg>Reorder some structs in `system`<commit_after>//! This module implements the basic structures of an atomic system.
//!
//! A final ```System``` consists of a set of ```Residue```s, which
//! can be moved around and translated with ease. Each ```Residue```
//! in turn consists of some ```Atom```s. These atoms have positions
//! relative to their parent.
//!
//! This somewhat convoluted structure is inherited from molecular
//! simulation packages in which atoms are commonly grouped as such.
//!  A proper physical way to look at is that atoms can be
//! similarly grouped into molecules.

/// A finalized atomic system which consists of a list of residues,
/// each of which contains some atoms.
pub struct System {
    /// System dimensions.
    pub dimensions: Coord,
    /// List of residues.
    pub residues: Vec<Residue>,
}

impl System {
    /// Count and return the number of atoms in the system.
    pub fn num_atoms(&self) -> usize {
        self.residues.iter().map(|r| r.atoms.len()).sum()
    }

    /// Translate all residues within the system and return a copy.
    pub fn translate(&self, add: &Coord) -> System {
        System {
            dimensions: self.dimensions,
            residues: self.residues.iter().map(|r| r.translate(&add)).collect(),
        }
    }
}

/// Every residue has a name and a list of atoms that belong to it
/// with their relative base coordinates. The names are static since
/// they are generated only once from a single source.
pub struct Residue {
    /// Residue code.
    pub code: &'static str,
    /// Position of residue in system.
    pub position: Coord,
    /// List of atoms belonging to the residue. Their positions are relative to the residue.
    pub atoms: Vec<Atom>,
}

impl Residue {
    /// Translate the residue position. Does not alter the atom relative positions.
    fn translate(&self, add: &Coord) -> Residue {
        Residue {
            code: self.code,
            position: self.position.add(&add),
            atoms: self.atoms.clone(),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
/// Every atom in a residue has their own code and relative
/// position some base coordinate.
pub struct Atom {
    /// Atom code.
    pub code: &'static str,
    /// Relative position.
    pub position: Coord,
}

/// A base for generating atoms belonging to a residue.
#[derive(Debug, PartialEq)]
pub struct ResidueBase {
    pub code: &'static str,
    pub atoms: Vec<Atom>,
}

#[macro_export]
/// Construct a ResidueBase with a code and atoms.
///
/// At least one atom has to be present in the base. This is not a limitation
/// when explicitly constructing a residue, but it makes no sense to allow
/// it when invoking a constructor like this.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate grafen;
/// use grafen::system::{Atom, Coord, ResidueBase};
/// # fn main() {
///
/// let expect = ResidueBase {
///     code: "RES",
///     atoms: vec![
///         Atom { code: "A", position: Coord::new(0.0, 0.0, 0.0) },
///         Atom { code: "B", position: Coord::new(1.0, 2.0, 3.0) }
///     ],
/// };
///
/// let residue = resbase![
///     "RES",
///     ("A", 0.0, 0.0, 0.0),
///     ("B", 1.0, 2.0, 3.0)
/// ];
///
/// assert_eq!(expect, residue);
/// # }
/// ```
macro_rules! resbase {
    (
        $rescode:expr,
        $(($atname:expr, $x:expr, $y:expr, $z:expr)),+
    ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push(
                    Atom {
                        code: $atname,
                        position: Coord::new($x, $y, $z),
                    }
                );
            )*

            ResidueBase {
                code: $rescode,
                atoms: temp_vec,
            }
        }
    }
}

impl ResidueBase {
    /// Generate a proper residue at the input position.
    pub fn to_residue(&self, position: &Coord) -> Residue {
        Residue {
            code: self.code,
            position: *position,
            atoms: self.atoms.clone(),
        }
    }

    /// Graphene is a single carbon atom at each lattice point.
    pub fn graphene(bond_length: f64) -> ResidueBase {
        let dx = bond_length / 2.0;

        resbase!["GRPH", ("C", dx, dx, 0.0)]
    }

    /// Silica is a rigid SiO2 molecule at each lattice point.
    pub fn silica(bond_length: f64) -> ResidueBase {
        let x0 = bond_length / 4.0;
        let y0 = bond_length / 6.0;
        let dz = 0.151;

        resbase![
            "SIO",
            ("O1", x0, y0, dz),
            ("SI", x0, y0, 0.0),
            ("O2", x0, y0, -dz)
        ]
    }
}

#[derive(Clone, Copy, Debug)]
/// A three-dimensional coordinate.
///
/// # Examples
/// ```
/// use grafen::system::Coord;
///
/// let coord1 = Coord::new(1.0, 0.0, 1.0);
/// let coord2 = Coord::new(0.5, 0.5, 0.5);
///
/// assert_eq!(Coord::new(1.5, 0.5, 1.5), coord1.add(&coord2));
/// ```
pub struct Coord {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Coord {
    /// Construct a new coordinate.
    pub fn new(x: f64, y: f64, z: f64) -> Coord {
        Coord { x: x, y: y, z: z }
    }

    /// Add a coordinate to another.
    pub fn add(&self, other: &Coord) -> Coord {
        Coord::new(self.x + other.x, self.y + other.y, self.z + other.z)
    }
}

impl PartialEq for Coord {
    fn eq(&self, other: &Coord) -> bool {
        let atol = 1e-9;
        (self.x - other.x).abs() < atol
            && (self.y - other.y).abs() < atol
            && (self.z - other.z).abs() < atol
    }
}

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

    #[test]
    fn coord_translations() {
        let coord = Coord::new(0.0, 1.0, 2.0);
        let coord_add = coord.add(&coord);
        let expected = Coord::new(0.0, 2.0, 4.0);
        assert_eq!(expected, coord_add);
    }

    #[test]
    fn coord_eq_tolerance_small_deviation_passes() {
        // Allow for some deviation when testing for equality, since floating point
        // numbers are stupid.
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-10, 2e-10, 3e-10));
    }

    #[test]
    #[should_panic]
    fn coord_eq_tolerance_larger_deviation_does_not() {
        let coord = Coord::new(0.0, 0.0, 0.0);
        assert_eq!(coord, Coord::new(1e-9, 2e-9, 3e-9));
    }

    // A simple system with two different residues and five atoms
    fn setup_system() -> System {
        let coord0 = Coord::new(0.0, 0.0, 0.0);

        let residue_one = Residue {
            code: "R1",
            position: Coord::new(0.0, 0.0, 0.0),
            atoms: vec![
                Atom { code: "A1", position: coord0, },
                Atom { code: "A2", position: coord0, },
                Atom { code: "A3", position: coord0, },
            ]
        };
        let residue_two = Residue {
            code: "R2",
            position: Coord::new(1.0, 1.0, 1.0),
            atoms: vec![
                Atom { code: "B1", position: coord0, },
                Atom { code: "B2", position: coord0, },
            ]
        };

        System {
            dimensions: Coord::new(0.0, 0.0, 0.0),
            residues: vec![
                residue_one,
                residue_two
            ]
        }
    }

    #[test]
    fn count_atoms_in_system() {
        let system = setup_system();
        assert_eq!(5, system.num_atoms());
    }

    #[test]
    fn translate_a_system() {
        let system = setup_system();
        let translate = Coord::new(0.0, 1.0, 2.0);

        let translated_system = system.translate(&translate);
        for (orig, updated) in system.residues.iter().zip(translated_system.residues.iter()) {
            assert_eq!(orig.position.add(&translate), updated.position);
        }
    }

    #[test]
    fn residue_base_to_residue() {
        let base = ResidueBase {
            code: "RES",
            atoms: vec![
                Atom { code: "A1", position: Coord::new(0.0, 0.0, 0.0) },
                Atom { code: "A2", position: Coord::new(0.0, 1.0, 2.0) }
            ],
        };
        let position = Coord::new(1.0, 1.0, 1.0);

        let residue = base.to_residue(&position);
        assert_eq!("RES", residue.code);
        assert_eq!(position, residue.position);
        assert_eq!(base.atoms, residue.atoms);
    }

    #[test]
    fn create_residue_base_macro() {
        let expect = ResidueBase {
            code: "RES",
            atoms: vec![
                Atom { code: "A1", position: Coord::new(0.0, 0.0, 0.0) },
                Atom { code: "A2", position: Coord::new(0.0, 1.0, 2.0) }
            ],
        };
        let result = resbase![
            "RES",
            ("A1", 0.0, 0.0, 0.0),
            ("A2", 0.0, 1.0, 2.0)
        ];

        assert_eq!(expect, result);
    }
}
<|endoftext|>


<commit_before>//! Various useful traits

use num::FromPrimitive;

/// Useful constants for radians.
pub trait Radians: FromPrimitive {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(&self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(&self) -> Self {
        *self * (::std::f32::consts::PI / 180.0f32)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(&self) -> Self {
        *self * (::std::f64::consts::PI / 180.0f64)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(Float::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(Float::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<commit_msg>Made `Radians::deg_to_rad` take `self`<commit_after>//! Various useful traits

use num::FromPrimitive;

/// Useful constants for radians.
pub trait Radians: FromPrimitive {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(Float::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(Float::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<|endoftext|>


<commit_before>use std::boxed::Box;
use std::collections::HashMap;

use node::{NodeKind, FuncDef};
use id;

#[derive(Debug, Clone, PartialEq)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Float,
    Char,
    Func(Box<[Type]>, Box<Type>), // (param types, return type)
    Var(usize), // id
}

#[derive(Debug)]
pub enum TypeError {
    Unify(Type, Type),
}

fn deref_ty(ty: &Type, tyenv: &HashMap<usize, Type>) -> Type {
    macro_rules! deref_typ_list {
        ($ls:expr) => ($ls.iter().map(|x| deref_ty(x, tyenv))
                                  .collect::<Vec<_>>()
                                 .into_boxed_slice());
    }
    match *ty {
        Type::Func(ref p, ref r) => Type::Func(deref_typ_list!(p), Box::new(deref_ty(r, tyenv))),
        // Type::Tuple(ref ts) => Type::Tuple(deref_ty_list!(ts)),
        // Type::Array(ref t) => Type::Array(Box::new(deref_ty(t, tyenv))),
        Type::Var(ref n) => {
            if let Some(t) = tyenv.get(n) {
                deref_ty(t, tyenv)
            } else {
                Type::Var(*n)
                // panic!("uninstantiated variable is not allowed now")
            }
        }
        _ => ty.clone(),
    }
}

fn deref_term(node: &NodeKind, tyenv: &HashMap<usize, Type>) -> NodeKind {
    macro_rules! apply_deref {
        ($ary:expr) => ($ary.iter().map(|x| deref_term(x, tyenv)).collect::<Vec<_>>());
    }
    match *node {
        NodeKind::IntBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::IntBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::FloatBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::FloatBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::Call(ref e, ref args) => {
            NodeKind::Call(Box::new(deref_term(e, tyenv)), apply_deref!(args))
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            NodeKind::LetExpr(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
                Box::new(deref_term(&**body, tyenv)),
            )
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncExpr(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
                Box::new(deref_term(body, tyenv)),
            )
        }
        _ => node.clone(),
    }
}

fn occur(r1: usize, ty: &Type) -> bool {
    macro_rules! occur_list {
        ($ls:expr) => ($ls.iter().any(|ty| occur(r1, ty)))
    }
    match *ty {
        Type::Func(ref t2s, ref t2) => occur_list!(t2s) || occur(r1, t2),
        // Type::Tuple(ref t2s) => occur_list!(t2s),
        // Type::Array(ref t2) => occur(r1, t2),
        Type::Var(r2) => r1 == r2,
        _ => false,
    }
}

pub fn unify(t1: &Type, t2: &Type, tyenv: &mut HashMap<usize, Type>) -> Result<(), TypeError> {
    match (t1, t2) {
        (&Type::Bool, &Type::Bool) => Ok(()),
        (&Type::Char, &Type::Char) => Ok(()),
        (&Type::Int, &Type::Int) => Ok(()),
        (&Type::Float, &Type::Float) => Ok(()),
        (&Type::Func(ref t1p, ref t1r), &Type::Func(ref t2p, ref t2r)) => {
            if t1p.len() != t2p.len() {
                return Err(TypeError::Unify(t1.clone(), t2.clone()));
            }
            for (a, b) in t1p.iter().zip(t2p.iter()) {
                try!(unify(a, b, tyenv));
            }
            unify(t1r, t2r, tyenv)
        }
        (&Type::Var(i1), &Type::Var(i2)) if i1 == i2 => Ok(()),
        (&Type::Var(ref i1), _) => {
            if let Some(t1sub) = tyenv.get(i1).cloned() {
                unify(&t1sub, t2, tyenv)
            } else {
                if occur(*i1, t2) {
                    return Err(TypeError::Unify(t1.clone(), t2.clone()));
                }
                tyenv.insert(*i1, t2.clone());
                Ok(())
            }
        }
        (_, &Type::Var(_)) => unify(t2, t1, tyenv),
        // TODO: implement more types
        _ => Err(TypeError::Unify(t1.clone(), t2.clone())),
    }
}

pub fn g(
    node: &NodeKind,
    env: &HashMap<String, Type>,
    tyenv: &mut HashMap<usize, Type>,
    idgen: &mut id::IdGen,
) -> Result<Type, TypeError> {
    macro_rules! g_seq {
        ($es:expr) => ({
            let mut argtype = Vec::new();
            for e in $es.iter() {
                argtype.push(try!(g(e, env, tyenv, idgen)));
            }
            argtype.into_boxed_slice()
        });
    }
    match *node {
        NodeKind::Bool(_) => Ok(Type::Bool),
        NodeKind::Int(_) => Ok(Type::Int),
        NodeKind::Float(_) => Ok(Type::Float),
        NodeKind::Ident(ref name) => {
            if let Some(t) = env.get(name).cloned() {
                Ok(t)
            } else {
                panic!("TODO: implement")
            }
        }
        NodeKind::IntBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Int, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Int, tyenv));
            Ok(Type::Int)
        }
        NodeKind::FloatBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Float, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Float, tyenv));
            Ok(Type::Float)
        }
        // Call(Box<NodeKind>, Vec<NodeKind>),
        NodeKind::Call(ref callee, ref args) => {
            let ty = idgen.get_type();
            let functy = Type::Func(g_seq!(args), Box::new(ty.clone()));
            try!(unify(&try!(g(callee, env, tyenv, idgen)), &functy, tyenv));
            Ok(ty)
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            let mut newenv = HashMap::new();
            newenv.insert(name.clone(), ty.clone());
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params
                        .iter()
                        .map(|p| p.1.clone())
                        .collect::<Vec<_>>()
                        .into_boxed_slice(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            Ok(Type::Unit)
        }
        _ => panic!(),
    }
}

pub fn f(node: &NodeKind, idgen: &mut id::IdGen) -> NodeKind {
    let mut tyenv = HashMap::new();
    let infered_ty = g(node, &HashMap::new(), &mut tyenv, idgen);
    // TODO: originally maybe infered_ty must be Type::Unit
    deref_term(node, &tyenv)
}
<commit_msg>impl Debug for Type<commit_after>use std::boxed::Box;
use std::collections::HashMap;

use node::{NodeKind, FuncDef};
use id;

#[derive(Clone, PartialEq)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Float,
    Char,
    Func(Vec<Type>, Box<Type>), // (param types, return type)
    Var(usize), // id
}

impl Type {
    pub fn to_string(&self) -> String {
        match self {
            &Type::Unit => "unit".to_string(),
            &Type::Bool => "bool".to_string(),
            &Type::Char => "char".to_string(),
            &Type::Int => "int".to_string(),
            &Type::Float => "float".to_string(),
            &Type::Func(ref param_tys, ref ret_ty) => {
                param_tys.into_iter().fold("".to_string(), |acc, ts| {
                    acc + ts.to_string().as_str() + " -> "
                }) + ret_ty.to_string().as_str() + " = <fun>"
            }
            &Type::Var(id) => format!("var({})", id),
        }
    }
}

use std::fmt;
impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

#[derive(Debug)]
pub enum TypeError {
    Unify(Type, Type),
}

fn deref_ty(ty: &Type, tyenv: &HashMap<usize, Type>) -> Type {
    macro_rules! deref_typ_list {
        ($list:expr) => ($list.iter().map(|x| deref_ty(x, tyenv))
                                  .collect::<Vec<_>>());
    }
    match *ty {
        Type::Func(ref p, ref r) => Type::Func(deref_typ_list!(p), Box::new(deref_ty(r, tyenv))),
        // Type::Tuple(ref ts) => Type::Tuple(deref_ty_list!(ts)),
        // Type::Array(ref t) => Type::Array(Box::new(deref_ty(t, tyenv))),
        Type::Var(ref n) => {
            if let Some(t) = tyenv.get(n) {
                deref_ty(t, tyenv)
            } else {
                Type::Var(*n)
                // panic!("uninstantiated variable is not allowed now")
            }
        }
        _ => ty.clone(),
    }
}

fn deref_term(node: &NodeKind, tyenv: &HashMap<usize, Type>) -> NodeKind {
    macro_rules! apply_deref {
        ($ary:expr) => ($ary.iter().map(|x| deref_term(x, tyenv)).collect::<Vec<_>>());
    }
    match *node {
        NodeKind::IntBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::IntBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::FloatBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::FloatBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::Call(ref e, ref args) => {
            NodeKind::Call(Box::new(deref_term(e, tyenv)), apply_deref!(args))
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            NodeKind::LetExpr(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
                Box::new(deref_term(&**body, tyenv)),
            )
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncExpr(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
                Box::new(deref_term(body, tyenv)),
            )
        }
        _ => node.clone(),
    }
}

fn occur(r1: usize, ty: &Type) -> bool {
    macro_rules! occur_list {
        ($ls:expr) => ($ls.iter().any(|ty| occur(r1, ty)))
    }
    match *ty {
        Type::Func(ref t2s, ref t2) => occur_list!(t2s) || occur(r1, t2),
        // Type::Tuple(ref t2s) => occur_list!(t2s),
        // Type::Array(ref t2) => occur(r1, t2),
        Type::Var(r2) => r1 == r2,
        _ => false,
    }
}

pub fn unify(t1: &Type, t2: &Type, tyenv: &mut HashMap<usize, Type>) -> Result<(), TypeError> {
    match (t1, t2) {
        (&Type::Bool, &Type::Bool) => Ok(()),
        (&Type::Char, &Type::Char) => Ok(()),
        (&Type::Int, &Type::Int) => Ok(()),
        (&Type::Float, &Type::Float) => Ok(()),
        (&Type::Func(ref t1p, ref t1r), &Type::Func(ref t2p, ref t2r)) => {
            if t1p.len() != t2p.len() {
                return Err(TypeError::Unify(t1.clone(), t2.clone()));
            }
            for (a, b) in t1p.iter().zip(t2p.iter()) {
                try!(unify(a, b, tyenv));
            }
            unify(t1r, t2r, tyenv)
        }
        (&Type::Var(i1), &Type::Var(i2)) if i1 == i2 => Ok(()),
        (&Type::Var(ref i1), _) => {
            if let Some(t1sub) = tyenv.get(i1).cloned() {
                unify(&t1sub, t2, tyenv)
            } else {
                if occur(*i1, t2) {
                    return Err(TypeError::Unify(t1.clone(), t2.clone()));
                }
                tyenv.insert(*i1, t2.clone());
                Ok(())
            }
        }
        (_, &Type::Var(_)) => unify(t2, t1, tyenv),
        // TODO: implement more types
        _ => Err(TypeError::Unify(t1.clone(), t2.clone())),
    }
}

pub fn g(
    node: &NodeKind,
    env: &HashMap<String, Type>,
    tyenv: &mut HashMap<usize, Type>,
    idgen: &mut id::IdGen,
) -> Result<Type, TypeError> {
    macro_rules! g_seq {
        ($es:expr) => ({
            let mut argtys = Vec::new();
            for e in $es.iter() { argtys.push(try!(g(e, env, tyenv, idgen))); }
            argtys
        });
    }
    match *node {
        NodeKind::Bool(_) => Ok(Type::Bool),
        NodeKind::Int(_) => Ok(Type::Int),
        NodeKind::Float(_) => Ok(Type::Float),
        NodeKind::Ident(ref name) => {
            if let Some(t) = env.get(name).cloned() {
                Ok(t)
            } else {
                panic!("TODO: implement")
            }
        }
        NodeKind::IntBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Int, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Int, tyenv));
            Ok(Type::Int)
        }
        NodeKind::FloatBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Float, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Float, tyenv));
            Ok(Type::Float)
        }
        NodeKind::Call(ref callee, ref args) => {
            let ty = idgen.get_type();
            let functy = Type::Func(g_seq!(args), Box::new(ty.clone()));
            try!(unify(&try!(g(callee, env, tyenv, idgen)), &functy, tyenv));
            Ok(ty)
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            let mut newenv = HashMap::new();
            newenv.insert(name.clone(), ty.clone());
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params.iter().map(|p| p.1.clone()).collect::<Vec<_>>(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            Ok(Type::Unit)
        }
        _ => panic!(),
    }
}

pub fn f(node: &NodeKind, idgen: &mut id::IdGen) -> NodeKind {
    let mut tyenv = HashMap::new();
    let infered_ty = g(node, &HashMap::new(), &mut tyenv, idgen);
    // TODO: originally maybe infered_ty must be Type::Unit
    deref_term(node, &tyenv)
}
<|endoftext|>


<commit_before>use std::ptr::null;
use libc::{c_int, c_char, c_double};
use std::ffi::CString;
use std::sync::{StaticMutex, MUTEX_INIT};
use utils::_string;

#[link(name="gdal")]
extern {
    fn OGRRegisterAll();
    fn OGROpen(pszName: *const c_char, bUpdate: c_int, pahDriverList: *const ()) -> *const ();
    fn OGR_DS_GetLayerCount(hDS: *const ()) -> c_int;
    fn OGR_DS_Destroy(hDataSource: *const ());
    fn OGR_DS_GetLayer(hDS: *const (), iLayer: c_int) -> *const ();
    fn OGR_L_GetLayerDefn(hLayer: *const ()) -> *const ();
    fn OGR_L_GetNextFeature(hLayer: *const ()) -> *const ();
    fn OGR_FD_GetFieldCount(hDefn: *const ()) -> c_int;
    fn OGR_FD_GetFieldDefn(hDefn: *const (), iField: c_int) -> *const ();
    fn OGR_F_GetFieldIndex(hFeat: *const (), pszName: *const c_char) -> c_int;
    fn OGR_F_GetFieldDefnRef(hFeat: *const (), i: c_int) -> *const ();
    fn OGR_F_GetFieldAsString(hFeat: *const (), iField: c_int) -> *const c_char;
    fn OGR_F_GetFieldAsDouble(hFeat: *const (), iField: c_int) -> c_double;
    fn OGR_F_GetGeometryRef(hFeat: *const ()) -> *const ();
    fn OGR_F_Destroy(hFeat: *const ());
    fn OGR_G_ExportToWkt(hGeom: *const (), ppszSrcText: &mut *const c_char) -> c_int;
    fn OGR_G_ExportToJson(hGeometry: *const ()) -> *const c_char;
    fn OGR_Fld_GetNameRef(hDefn: *const ()) -> *const c_char;
    fn OGR_Fld_GetType(hDefn: *const ()) -> c_int;
    fn OGRFree(ptr: *mut ());
    fn VSIFree(ptr: *mut ());
}

const OGRERR_NONE:          c_int = 0;

const OFT_REAL:             c_int = 2;
const OFT_STRING:           c_int = 4;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            OGRRegisterAll();
            registered_drivers = true;
        }
    }
}

pub struct VectorDataset {
    c_dataset: *const (),
}

impl VectorDataset {
    pub fn count(&self) -> isize {
        return unsafe { OGR_DS_GetLayerCount(self.c_dataset) } as isize;
    }

    pub fn layer<'a>(&'a self, idx: isize) -> Option<Layer<'a>> {
        let c_layer = unsafe { OGR_DS_GetLayer(self.c_dataset, idx as c_int) };
        return match c_layer.is_null() {
            true  => None,
            false => Some(Layer{_vector_dataset: self, c_layer: c_layer}),
        };
    }
}

impl Drop for VectorDataset {
    fn drop(&mut self) {
        unsafe { OGR_DS_Destroy(self.c_dataset); }
    }
}

pub struct Layer<'a> {
    _vector_dataset: &'a VectorDataset,
    c_layer: *const (),
}

impl<'a> Layer<'a> {
    pub fn fields(&'a self) -> FieldIterator<'a> {
        let c_feature_defn = unsafe { OGR_L_GetLayerDefn(self.c_layer) };
        let total = unsafe { OGR_FD_GetFieldCount(c_feature_defn) } as isize;
        return FieldIterator{
            layer: self,
            c_feature_defn: c_feature_defn,
            next_id: 0,
            total: total
        };
    }

    pub fn features(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator{layer: self};
    }
}

pub struct FieldIterator<'a> {
    layer: &'a Layer<'a>,
    c_feature_defn: *const (),
    next_id: isize,
    total: isize,
}

impl<'a> Iterator for FieldIterator<'a> {
    type Item = Field<'a>;

    #[inline]
    fn next(&mut self) -> Option<Field<'a>> {
        if self.next_id == self.total {
            return None;
        }
        let field = Field{
            _layer: self.layer,
            c_field_defn: unsafe { OGR_FD_GetFieldDefn(
                self.c_feature_defn,
                self.next_id as c_int
            ) }
        };
        self.next_id += 1;
        return Some(field);
    }
}

pub struct Field<'a> {
    _layer: &'a Layer<'a>,
    c_field_defn: *const (),
}

impl<'a> Field<'a> {
    pub fn name(&'a self) -> String {
        let rv = unsafe { OGR_Fld_GetNameRef(self.c_field_defn) };
        return _string(rv);
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator for FeatureIterator<'a> {
    type Item = Feature<'a>;

    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(Feature{_layer: self.layer, c_feature: c_feature}),
        };
    }
}

pub struct Feature<'a> {
    _layer: &'a Layer<'a>,
    c_feature: *const (),
}

impl<'a> Feature<'a> {
    pub fn field(&self, name: &str) -> Option<FieldValue> {
        let c_name = CString::from_slice(name.as_bytes());
        let field_id = unsafe { OGR_F_GetFieldIndex(self.c_feature, c_name.as_ptr()) };
        if field_id == -1 {
            return None;
        }
        let field_defn = unsafe { OGR_F_GetFieldDefnRef(self.c_feature, field_id) };
        let field_type = unsafe { OGR_Fld_GetType(field_defn) };
        return match field_type {
            OFT_STRING => {
                let rv = unsafe { OGR_F_GetFieldAsString(self.c_feature, field_id) };
                return Some(FieldValue::StringValue(_string(rv)));
            },
            OFT_REAL => {
                let rv = unsafe { OGR_F_GetFieldAsDouble(self.c_feature, field_id) };
                return Some(FieldValue::RealValue(rv as f64));
            },
            _ => panic!("Unknown field type {}", field_type)
        }
    }

    pub fn wkt(&self) -> String {
        let c_geom = unsafe { OGR_F_GetGeometryRef(self.c_feature) };
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { OGR_G_ExportToWkt(c_geom, &mut c_wkt) };
        assert_eq!(_err, OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub fn json(&self) -> String {
        let c_geom = unsafe { OGR_F_GetGeometryRef(self.c_feature) };
        let c_json = unsafe { OGR_G_ExportToJson(c_geom) };
        let json = _string(c_json);
        unsafe { VSIFree(c_json as *mut ()) };
        return json;
    }
}

#[unsafe_destructor]
impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { OGR_F_Destroy(self.c_feature); }
    }
}

pub fn open(path: &Path) -> Option<VectorDataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_filename = CString::from_slice(filename.as_bytes());
    let c_dataset = unsafe { OGROpen(c_filename.as_ptr(), 0, null()) };
    return match c_dataset.is_null() {
        true  => None,
        false => Some(VectorDataset{c_dataset: c_dataset}),
    };
}

pub enum FieldValue {
    StringValue(String),
    RealValue(f64),
}

impl FieldValue {
    pub fn as_string(self) -> String {
        match self {
            FieldValue::StringValue(rv) => rv,
            _ => panic!("not a StringValue")
        }
    }

    pub fn as_real(self) -> f64 {
        match self {
            FieldValue::RealValue(rv) => rv,
            _ => panic!("not a RealValue")
        }
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use super::{Feature, FeatureIterator, open};

    fn fixtures() -> Path {
        return Path::new(file!()).dir_path().dir_path().join("fixtures");
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_layer_count() {
        let ds = open(&fixtures().join("roads.geojson")).unwrap();
        assert_eq!(ds.count(), 1);
    }

    fn with_features<F>(fixture: &str, f: F) where F: Fn(FeatureIterator) {
        let ds = open(&fixtures().join(fixture)).unwrap();
        let layer = ds.layer(0).unwrap();
        f(layer.features());
    }

    fn with_first_feature<F>(fixture: &str, f: F) where F: Fn(Feature) {
        with_features(fixture, |mut features| f(features.next().unwrap()));
    }

    #[test]
    fn test_iterate_features() {
        with_features("roads.geojson", |features| {
            let feature_vec: Vec<Feature> = features.collect();
            assert_eq!(feature_vec.len(), 21);
        });
    }

    #[test]
    fn test_string_field() {
        with_features("roads.geojson", |mut features| {
            let feature = features.next().unwrap();
            assert_eq!(feature.field("highway")
                              .unwrap()
                              .as_string(),
                       "footway".to_string());
            assert_eq!(
                features.filter(|field| {
                    let highway = field.field("highway")
                                       .unwrap()
                                       .as_string();
                    highway == "residential".to_string() })
                    .count(),
                2);
        });
    }

    #[test]
    fn test_float_field() {
        with_first_feature("roads.geojson", |feature| {
            assert_almost_eq(
                feature.field("sort_key")
                       .unwrap()
                       .as_real(),
                -9.0
            );
        });
    }

    #[test]
    fn test_missing_field() {
        with_first_feature("roads.geojson", |feature| {
            assert!(feature.field("no such field").is_none());
        });
    }

    #[test]
    fn test_wkt() {
        with_first_feature("roads.geojson", |feature| {
            let wkt = feature.wkt();
            let wkt_ok = format!("{}{}",
                "LINESTRING (26.1019276 44.4302748,",
                "26.1019382 44.4303191,26.1020002 44.4304202)"
                ).to_string();
            assert_eq!(wkt, wkt_ok);
        });
    }

    #[test]
    fn test_json() {
        with_first_feature("roads.geojson", |feature| {
            let json = feature.json();
            let json_ok = format!("{}{}{}{}",
                "{ \"type\": \"LineString\", \"coordinates\": [ ",
                "[ 26.1019276, 44.4302748 ], ",
                "[ 26.1019382, 44.4303191 ], ",
                "[ 26.1020002, 44.4304202 ] ] }"
                ).to_string();
            assert_eq!(json, json_ok);
        });
    }

    #[test]
    fn test_schema() {
        let ds = open(&fixtures().join("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let name_list: Vec<String> = layer
            .fields()
            .map(|f| f.name())
            .collect();
        let ok_names: Vec<String> = vec!(
            "kind", "sort_key", "is_link", "is_tunnel",
            "is_bridge", "railway", "highway")
            .iter().map(|s| s.to_string()).collect();
        assert_eq!(name_list, ok_names);
    }
}
<commit_msg>create geometry as bounding box<commit_after>use std::ptr::null;
use libc::{c_int, c_char, c_double};
use std::ffi::CString;
use std::sync::{StaticMutex, MUTEX_INIT};
use utils::_string;

#[link(name="gdal")]
extern {
    fn OGRRegisterAll();
    fn OGROpen(pszName: *const c_char, bUpdate: c_int, pahDriverList: *const ()) -> *const ();
    fn OGR_DS_GetLayerCount(hDS: *const ()) -> c_int;
    fn OGR_DS_Destroy(hDataSource: *const ());
    fn OGR_DS_GetLayer(hDS: *const (), iLayer: c_int) -> *const ();
    fn OGR_L_GetLayerDefn(hLayer: *const ()) -> *const ();
    fn OGR_L_GetNextFeature(hLayer: *const ()) -> *const ();
    fn OGR_FD_GetFieldCount(hDefn: *const ()) -> c_int;
    fn OGR_FD_GetFieldDefn(hDefn: *const (), iField: c_int) -> *const ();
    fn OGR_F_GetFieldIndex(hFeat: *const (), pszName: *const c_char) -> c_int;
    fn OGR_F_GetFieldDefnRef(hFeat: *const (), i: c_int) -> *const ();
    fn OGR_F_GetFieldAsString(hFeat: *const (), iField: c_int) -> *const c_char;
    fn OGR_F_GetFieldAsDouble(hFeat: *const (), iField: c_int) -> c_double;
    fn OGR_F_GetGeometryRef(hFeat: *const ()) -> *const ();
    fn OGR_F_Destroy(hFeat: *const ());
    fn OGR_G_CreateFromWkt(ppszData: &mut *const c_char, hSRS: *const (), phGeometry: &mut *const ()) -> c_int;
    fn OGR_G_ExportToWkt(hGeom: *const (), ppszSrcText: &mut *const c_char) -> c_int;
    fn OGR_G_ExportToJson(hGeometry: *const ()) -> *const c_char;
    fn OGR_G_DestroyGeometry(hGeom: *mut ());
    fn OGR_Fld_GetNameRef(hDefn: *const ()) -> *const c_char;
    fn OGR_Fld_GetType(hDefn: *const ()) -> c_int;
    fn OGRFree(ptr: *mut ());
    fn VSIFree(ptr: *mut ());
}

const OGRERR_NONE:          c_int = 0;

const OFT_REAL:             c_int = 2;
const OFT_STRING:           c_int = 4;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            OGRRegisterAll();
            registered_drivers = true;
        }
    }
}

pub struct VectorDataset {
    c_dataset: *const (),
}

impl VectorDataset {
    pub fn count(&self) -> isize {
        return unsafe { OGR_DS_GetLayerCount(self.c_dataset) } as isize;
    }

    pub fn layer<'a>(&'a self, idx: isize) -> Option<Layer<'a>> {
        let c_layer = unsafe { OGR_DS_GetLayer(self.c_dataset, idx as c_int) };
        return match c_layer.is_null() {
            true  => None,
            false => Some(Layer{_vector_dataset: self, c_layer: c_layer}),
        };
    }
}

impl Drop for VectorDataset {
    fn drop(&mut self) {
        unsafe { OGR_DS_Destroy(self.c_dataset); }
    }
}

pub struct Layer<'a> {
    _vector_dataset: &'a VectorDataset,
    c_layer: *const (),
}

impl<'a> Layer<'a> {
    pub fn fields(&'a self) -> FieldIterator<'a> {
        let c_feature_defn = unsafe { OGR_L_GetLayerDefn(self.c_layer) };
        let total = unsafe { OGR_FD_GetFieldCount(c_feature_defn) } as isize;
        return FieldIterator{
            layer: self,
            c_feature_defn: c_feature_defn,
            next_id: 0,
            total: total
        };
    }

    pub fn features(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator{layer: self};
    }
}

pub struct FieldIterator<'a> {
    layer: &'a Layer<'a>,
    c_feature_defn: *const (),
    next_id: isize,
    total: isize,
}

impl<'a> Iterator for FieldIterator<'a> {
    type Item = Field<'a>;

    #[inline]
    fn next(&mut self) -> Option<Field<'a>> {
        if self.next_id == self.total {
            return None;
        }
        let field = Field{
            _layer: self.layer,
            c_field_defn: unsafe { OGR_FD_GetFieldDefn(
                self.c_feature_defn,
                self.next_id as c_int
            ) }
        };
        self.next_id += 1;
        return Some(field);
    }
}

pub struct Field<'a> {
    _layer: &'a Layer<'a>,
    c_field_defn: *const (),
}

impl<'a> Field<'a> {
    pub fn name(&'a self) -> String {
        let rv = unsafe { OGR_Fld_GetNameRef(self.c_field_defn) };
        return _string(rv);
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator for FeatureIterator<'a> {
    type Item = Feature<'a>;

    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(Feature{_layer: self.layer, c_feature: c_feature}),
        };
    }
}

pub struct Feature<'a> {
    _layer: &'a Layer<'a>,
    c_feature: *const (),
}

impl<'a> Feature<'a> {
    pub fn field(&self, name: &str) -> Option<FieldValue> {
        let c_name = CString::from_slice(name.as_bytes());
        let field_id = unsafe { OGR_F_GetFieldIndex(self.c_feature, c_name.as_ptr()) };
        if field_id == -1 {
            return None;
        }
        let field_defn = unsafe { OGR_F_GetFieldDefnRef(self.c_feature, field_id) };
        let field_type = unsafe { OGR_Fld_GetType(field_defn) };
        return match field_type {
            OFT_STRING => {
                let rv = unsafe { OGR_F_GetFieldAsString(self.c_feature, field_id) };
                return Some(FieldValue::StringValue(_string(rv)));
            },
            OFT_REAL => {
                let rv = unsafe { OGR_F_GetFieldAsDouble(self.c_feature, field_id) };
                return Some(FieldValue::RealValue(rv as f64));
            },
            _ => panic!("Unknown field type {}", field_type)
        }
    }

    pub fn wkt(&self) -> String {
        let c_geom = unsafe { OGR_F_GetGeometryRef(self.c_feature) };
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { OGR_G_ExportToWkt(c_geom, &mut c_wkt) };
        assert_eq!(_err, OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub fn json(&self) -> String {
        let c_geom = unsafe { OGR_F_GetGeometryRef(self.c_feature) };
        let c_json = unsafe { OGR_G_ExportToJson(c_geom) };
        let json = _string(c_json);
        unsafe { VSIFree(c_json as *mut ()) };
        return json;
    }
}

#[unsafe_destructor]
impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { OGR_F_Destroy(self.c_feature); }
    }
}

pub struct Geometry {
    c_geometry: *const (),
}

impl Geometry {
    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        let wkt = format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        );
        let c_wkt = CString::from_slice(wkt.as_bytes());
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, OGRERR_NONE);
        return Geometry{c_geometry: c_geom};
    }

    pub fn json(&self) -> String {
        let c_json = unsafe { OGR_G_ExportToJson(self.c_geometry) };
        let rv = _string(c_json);
        unsafe { VSIFree(c_json as *mut ()) };
        return rv;
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        unsafe { OGR_G_DestroyGeometry(self.c_geometry as *mut ()) };
    }
}

pub fn open(path: &Path) -> Option<VectorDataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_filename = CString::from_slice(filename.as_bytes());
    let c_dataset = unsafe { OGROpen(c_filename.as_ptr(), 0, null()) };
    return match c_dataset.is_null() {
        true  => None,
        false => Some(VectorDataset{c_dataset: c_dataset}),
    };
}

pub enum FieldValue {
    StringValue(String),
    RealValue(f64),
}

impl FieldValue {
    pub fn as_string(self) -> String {
        match self {
            FieldValue::StringValue(rv) => rv,
            _ => panic!("not a StringValue")
        }
    }

    pub fn as_real(self) -> f64 {
        match self {
            FieldValue::RealValue(rv) => rv,
            _ => panic!("not a RealValue")
        }
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use super::{Feature, FeatureIterator, open, Geometry};

    fn fixtures() -> Path {
        return Path::new(file!()).dir_path().dir_path().join("fixtures");
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_layer_count() {
        let ds = open(&fixtures().join("roads.geojson")).unwrap();
        assert_eq!(ds.count(), 1);
    }

    fn with_features<F>(fixture: &str, f: F) where F: Fn(FeatureIterator) {
        let ds = open(&fixtures().join(fixture)).unwrap();
        let layer = ds.layer(0).unwrap();
        f(layer.features());
    }

    fn with_first_feature<F>(fixture: &str, f: F) where F: Fn(Feature) {
        with_features(fixture, |mut features| f(features.next().unwrap()));
    }

    #[test]
    fn test_iterate_features() {
        with_features("roads.geojson", |features| {
            let feature_vec: Vec<Feature> = features.collect();
            assert_eq!(feature_vec.len(), 21);
        });
    }

    #[test]
    fn test_string_field() {
        with_features("roads.geojson", |mut features| {
            let feature = features.next().unwrap();
            assert_eq!(feature.field("highway")
                              .unwrap()
                              .as_string(),
                       "footway".to_string());
            assert_eq!(
                features.filter(|field| {
                    let highway = field.field("highway")
                                       .unwrap()
                                       .as_string();
                    highway == "residential".to_string() })
                    .count(),
                2);
        });
    }

    #[test]
    fn test_float_field() {
        with_first_feature("roads.geojson", |feature| {
            assert_almost_eq(
                feature.field("sort_key")
                       .unwrap()
                       .as_real(),
                -9.0
            );
        });
    }

    #[test]
    fn test_missing_field() {
        with_first_feature("roads.geojson", |feature| {
            assert!(feature.field("no such field").is_none());
        });
    }

    #[test]
    fn test_wkt() {
        with_first_feature("roads.geojson", |feature| {
            let wkt = feature.wkt();
            let wkt_ok = format!("{}{}",
                "LINESTRING (26.1019276 44.4302748,",
                "26.1019382 44.4303191,26.1020002 44.4304202)"
                ).to_string();
            assert_eq!(wkt, wkt_ok);
        });
    }

    #[test]
    fn test_json() {
        with_first_feature("roads.geojson", |feature| {
            let json = feature.json();
            let json_ok = format!("{}{}{}{}",
                "{ \"type\": \"LineString\", \"coordinates\": [ ",
                "[ 26.1019276, 44.4302748 ], ",
                "[ 26.1019382, 44.4303191 ], ",
                "[ 26.1020002, 44.4304202 ] ] }"
                ).to_string();
            assert_eq!(json, json_ok);
        });
    }

    #[test]
    fn test_schema() {
        let ds = open(&fixtures().join("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let name_list: Vec<String> = layer
            .fields()
            .map(|f| f.name())
            .collect();
        let ok_names: Vec<String> = vec!(
            "kind", "sort_key", "is_link", "is_tunnel",
            "is_bridge", "railway", "highway")
            .iter().map(|s| s.to_string()).collect();
        assert_eq!(name_list, ok_names);
    }

    #[test]
    fn test_create_bbox() {
        let bbox = Geometry::bbox(-27., 33., 52., 85.);
        assert_eq!(bbox.json(), "{ \"type\": \"Polygon\", \"coordinates\": [ [ [ -27.0, 85.0 ], [ 52.0, 85.0 ], [ 52.0, 33.0 ], [ -27.0, 33.0 ], [ -27.0, 85.0 ] ] ] }");
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
use std::str;
use std::process::Command;
use rand::{random};

pub trait Worker {
  // fn work(&self, &Message) -> Option<Message>;
  fn convert(&self, &Path) -> Option<File>;
  fn message_size(&self) -> usize;
  fn service(&self) -> String;
  fn source(&self) -> String;
  fn sink(&self) -> String;

  fn start(&self, limit : Option<i32>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let mut context_sink = Context::new();
    let mut sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Prepare a File for the input
      println!("--- Create a file ");
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid ;
      let mut file = File::create(input_filepath.clone()).unwrap();
      println!("--- Receive content. ");
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }
      println!("--- Data received at {:?} ", input_filepath);

      file.seek(SeekFrom::Start(0)).unwrap();
      println!("--- Starting worker convert. ");
      let file_opt = self.convert(Path::new(&input_filepath));
      println!("--- Ending worker convert. ");
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep_ms(60000);
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep_ms(500);
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
pub struct EchoWorker {
  pub service : String,
  pub version : f32,
  pub message_size : usize,
  pub source : String,
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}

pub struct TexToHtmlWorker {
  pub service : String,
  pub version : f32,
  pub message_size : usize,
  pub source : String,
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";

    let output = Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--css")
      .arg("http://latexml.mathweb.org/css/external/LaTeXML.css")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg(name.to_string() + ".log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    println!("Dest: {:?}", destination_path);
    println!("Log: {:?}", str::from_utf8(&output.stderr));
    Some(File::open(destination_path.clone()).unwrap())
  }
}
<commit_msg>Revert "temporary debug prints"<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
// use std::str;
use std::process::Command;
use rand::{random};

pub trait Worker {
  // fn work(&self, &Message) -> Option<Message>;
  fn convert(&self, &Path) -> Option<File>;
  fn message_size(&self) -> usize;
  fn service(&self) -> String;
  fn source(&self) -> String;
  fn sink(&self) -> String;

  fn start(&self, limit : Option<i32>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let mut context_sink = Context::new();
    let mut sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Prepare a File for the input
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid ;
      let mut file = File::create(input_filepath.clone()).unwrap();
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }

      file.seek(SeekFrom::Start(0)).unwrap();
      let file_opt = self.convert(Path::new(&input_filepath));
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep_ms(60000);
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep_ms(500);
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
pub struct EchoWorker {
  pub service : String,
  pub version : f32,
  pub message_size : usize,
  pub source : String,
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}

pub struct TexToHtmlWorker {
  pub service : String,
  pub version : f32,
  pub message_size : usize,
  pub source : String,
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";

    Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--css")
      .arg("http://latexml.mathweb.org/css/external/LaTeXML.css")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg(name.to_string() + ".log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    // println!("Dest: {:?}", destination_path);
    // println!("Log: {:?}", str::from_utf8(&output.stderr));
    Some(File::open(destination_path.clone()).unwrap())
  }
}
<|endoftext|>