<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
#[feature(globs)];
extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;

use std::io::stdin;

use extra::getopts;
use std::path::*;
use std::libc;

struct Shell {
    pipeflag: bool,
    ioflag: bool,
    flag: bool,
    history: ~[~str],
    cmd_prompt: ~str,

}

impl Shell {
    fn new(prompt_str: &str, zerohis: &[~str]) -> Shell {
        Shell {
            pipeflag: false,
            ioflag: false,
            flag: false,
            history: zerohis.to_owned(),
            cmd_prompt: prompt_str.to_owned(),

        }
    }

    fn run(&mut self) {

        let mut stdin = BufferedReader::new(stdin());

        let mut in_chan = libc::STDIN_FILENO;
        let mut out_chan = libc::STDOUT_FILENO;

       loop {
            self.pipeflag = false;
            self.flag = false;
            self.ioflag = false;
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            //println!("{:s}", cmd_line)   command_line is owned and trimmed of leading/lagging white space
            //println!("{:s}", line)        line is the arguement passed in as is
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            //println!("{:s}", program)     program is just the command without arguements
            if cmd_line.ends_with("&")
            {
                self.flag = true;

            }

            let cmd_line1 = cmd_line.clone();

            let cmd_line2 = cmd_line1.to_owned();

            let cmd_line3 = cmd_line2.slice_to(cmd_line2.len()-2);
            let mut argvAnd: ~[~str] =
            cmd_line3.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            argvAnd.remove(0);

            //let mut argvPipe: ~[&str];

            let mut cmd_array: ~[&str];

            if self.flag == true
            {
                cmd_array = cmd_line3.split_str(" ").collect();
                //argvPipe = cmd_line3.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }
            else
            {
                cmd_array = cmd_line1.split_str(" ").collect();
                //argvPipe = cmd_line1.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }

            let mut cmd_ac: ~[&str] = cmd_array.clone().to_owned();

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    //print(cmd_ac[i+1]);
                    out_chan = self.get_fd(cmd_ac.remove(i+1), "w");
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    //print(cmd_ac[i+1]);
                    in_chan = self.get_fd(cmd_ac.remove(i+1), "r");
                }

            }

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    cmd_ac.remove(i);
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    cmd_ac.remove(i);
                }

            }

            /*for i in range(0, cmd_ac.len()-1)
            {
                println(format!(" print if you are working: {:s}", cmd_ac[i]));
            }*/

            //println(format!("{:s}", program));

            //println("{:s}",cmd_line3);

            match program {
                ""      =>  { continue; },
                "exit"  =>  { return; },
                _       =>  {
                            if self.cmd_exists(program)
                            {
                            if self.flag == true
                            {
                                self.flag = false;

                                if self.ioflag == true
                                {
                                    self.ioflag = false;

                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: Some(in_chan),
                                            out_fd: Some(out_chan),
                                            err_fd: Some(libc::STDERR_FILENO)

                                    });

                            //let i = myproc.clone().unwrap().get_id();
                            //println(format!("{}", i));
                                self.run();
                                myproc.unwrap().finish();
                                }

                                else
                                {
                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: None,
                                            out_fd: None,
                                            err_fd: None

                                    });
                                    self.run();
                                    myproc.unwrap().finish();
                                }

                            }

                            else
                            {
                            self.run_cmdline(cmd_line2);

                            }

                            }

                            else
                            {
                                println!("{:s}: command not found", program);
                            }

                                //self.run_cmdline(port.recv());
                                //self.run_cmdline(port1.recv());
                            }

                        };

        }

    }

    fn get_fd(&mut self, filepth: &str, mode: &str)-> libc::c_int
    {
        unsafe
        {
            let filename = filepth.to_c_str().unwrap();
            let filemode = mode.to_c_str().unwrap();
            return libc::fileno(libc::fopen(filename, filemode));
        }
    }

    fn cd(&mut self, new_path:&Path) // the change directory method
    {

        if new_path.exists() && new_path.is_dir()
        {
            os::change_dir(new_path);

        }
        else if !new_path.is_dir()
        {
            println(format!("cd: {}: is not a Directory", new_path.display()));

        }
        else
        {
            println(format!("cd: {}: is not a File", new_path.display()));
        }

    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            //argv is owned pointer to a vector of owned strings - each word gets its own place in the vector
        if argv.len() > 0 {
            self.history.push(cmd_line.to_owned());
            let program: ~str = argv.remove(0); //removes and returns the elements, shift vector left
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {

        let mut args: ~[~str] = argv.to_owned();
        match program
        {
            "cd"        =>  {
                                if !argv.is_empty()
                                {
                                    let mut my_str: ~str;
                                    my_str = args.remove(0);
                                    let file = Path::new(my_str);
                                    self.cd(&file);
                                }
                                else
                                {
                                    self.cd(&os::getcwd());
                                }
                            },

           "history"   =>  {
                                println("History:");
                                let mut i = 1;
                                for x in self.history.rev_iter()
                                {
                                    println(format!("{:d}:  {:s}", i, x.to_owned()));
                                    i = i + 1;

                                }
                           },

            _           =>

                           {
                                if self.cmd_exists(program)
                                {

                                    run::process_status(program, argv); //spawns new process, waits for completion - must take vector string args for program

                                }
                                else
                                {
                                    println!("{:s}: command not found", program);
                                }
                            }
        }
        let cwd = os::getcwd();
        print(format!("{}: ", cwd.display()));

    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]); //
        //print(ret);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();
    let newhis = ~[];
    match opt_cmd_line {
        Some(cmd_line) => Shell::new("", newhis).run_cmdline(cmd_line),
        None           => Shell::new("gash > ", newhis).run()
    }
}
<commit_msg>Preliminary Final Commit<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
#[feature(globs)];
extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::signal::{Listener, Interrupt};
use std::io::stdin;

use extra::getopts;
use std::path::*;
use std::libc;

struct Shell {
    pipeflag: bool,
    ioflag: bool,
    flag: bool,
    history: ~[~str],
    cmd_prompt: ~str,

}

impl Shell {
    fn new(prompt_str: &str, zerohis: &[~str]) -> Shell {
        Shell {
            pipeflag: false,
            ioflag: false,
            flag: false,
            history: zerohis.to_owned(),
            cmd_prompt: prompt_str.to_owned(),

        }
    }

    fn run(&mut self) {

        let mut stdin = BufferedReader::new(stdin());

        let mut in_chan = libc::STDIN_FILENO;
        let mut out_chan = libc::STDOUT_FILENO;

        let mut listener = Listener::new();
        listener.register(Interrupt);

       loop {

            self.pipeflag = false;
            self.flag = false;
            self.ioflag = false;
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            //println!("{:s}", cmd_line)   command_line is owned and trimmed of leading/lagging white space
            //println!("{:s}", line)        line is the arguement passed in as is
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            //println!("{:s}", program)     program is just the command without arguements
            if cmd_line.ends_with("&")
            {
                self.flag = true;

            }

            let cmd_line1 = cmd_line.clone();

            let cmd_line2 = cmd_line1.to_owned();

            let cmd_line3 = cmd_line2.slice_to(cmd_line2.len()-2);
            let mut argvAnd: ~[~str] =
            cmd_line3.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            if argvAnd.len() > 0
            {
            argvAnd.remove(0);
            }

            let mut argvPipe: ~[~str];

            let mut cmd_array: ~[&str];

            if self.flag == true
            {
                cmd_array = cmd_line3.split_str(" ").collect();
                argvPipe = cmd_line3.split('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            }
            else
            {
                cmd_array = cmd_line1.split_str(" ").collect();
                argvPipe = cmd_line1.split('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            }

            let mut pipeArray: ~[os::Pipe] = ~[];

            if(argvPipe.len() > 1)
            {
                self.pipeflag = true;
                for _ in range(0, argvPipe.len()-1)
                {
                pipeArray.push(os::pipe());
                }
            }

            for i in range(0, argvPipe.len()-1)
            {
                if i == 0
                {
                    out_chan = pipeArray[i].out;

                }
                if i > 0
                {
                    in_chan = pipeArray[i-1].input;
                    out_chan = pipeArray[i].out;
                }
                if i == argvPipe.len() -1
                {
                    out_chan = libc::STDOUT_FILENO
                }
            }

            let mut cmd_ac: ~[&str] = cmd_array.clone().to_owned();

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    //print(cmd_ac[i+1]);
                    out_chan = self.get_fd(cmd_ac.remove(i+1), "w");
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    //print(cmd_ac[i+1]);
                    in_chan = self.get_fd(cmd_ac.remove(i+1), "r");
                }

            }

            /*for i in range(0, cmd_ac.len()-1)
            {
                println(format!(" print if you are working: {:s}", cmd_ac[i]));
            }*/

            //println(format!("{:s}", program));

            //println("{:s}",cmd_line3);
            if self.pipeflag == false && self.ioflag == false & self.flag == false
            {
                match program {
                ""      =>  { continue; },
                "exit"  =>  { return; },
                _       =>  { self.run_cmdline(cmd_line2);}
            }
        }
            else{
            match program {
                ""      =>  { continue; },
                "exit"  =>  { return; },
                _       =>  {

                            if self.flag == true
                            {
                                self.flag = false;

                                if self.ioflag == true || self.pipeflag == true
                                {
                                    self.ioflag = false;
                                    self.pipeflag = false;

                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: Some(in_chan),
                                            out_fd: Some(out_chan),
                                            err_fd: Some(libc::STDERR_FILENO)

                                    });

                            //let i = myproc.clone().unwrap().get_id();
                            //println(format!("{}", i));
                                self.run();
                                myproc.unwrap().finish();
                                }

                                else
                                {
                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: None,
                                            out_fd: None,
                                            err_fd: None

                                    });
                                    self.run();
                                    myproc.unwrap().finish();
                                }

                            }

                            else if self.ioflag == true || self.pipeflag == true
                                {
                                    self.ioflag = false;
                                    self.pipeflag = false;

                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: Some(in_chan),
                                            out_fd: Some(out_chan),
                                            err_fd: Some(libc::STDERR_FILENO)

                                    });

                            //let i = myproc.clone().unwrap().get_id();
                            //println(format!("{}", i));
                                self.run();
                                myproc.unwrap().finish();
                                }

                            else
                            {
                            self.run_cmdline(cmd_line2);

                            }

                            }

                                //self.run_cmdline(port.recv());
                                //self.run_cmdline(port1.recv());

                        };

        } }

    }

    fn get_fd(&mut self, filepth: &str, mode: &str)-> libc::c_int
    {
        unsafe
        {
            let filename = filepth.to_c_str().unwrap();
            let filemode = mode.to_c_str().unwrap();
            return libc::fileno(libc::fopen(filename, filemode));
        }
    }

    fn cd(&mut self, new_path:&Path) // the change directory method
    {

        if new_path.exists() && new_path.is_dir()
        {
            os::change_dir(new_path);

        }
        else if !new_path.is_dir()
        {
            println(format!("cd: {}: is not a Directory", new_path.display()));

        }
        else
        {
            println(format!("cd: {}: is not a File", new_path.display()));
        }

    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            //argv is owned pointer to a vector of owned strings - each word gets its own place in the vector
        if argv.len() > 0 {
            self.history.push(cmd_line.to_owned());
            let program: ~str = argv.remove(0); //removes and returns the elements, shift vector left
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {

        let mut args: ~[~str] = argv.to_owned();
        match program
        {
            "cd"        =>  {
                                if !argv.is_empty()
                                {
                                    let mut my_str: ~str;
                                    my_str = args.remove(0);
                                    let file = Path::new(my_str);
                                    self.cd(&file);
                                }
                                else
                                {
                                    self.cd(&os::getcwd());
                                }
                            },

           "history"   =>  {
                                println("History:");
                                let mut i = 1;
                                for x in self.history.rev_iter()
                                {
                                    println(format!("{:d}:  {:s}", i, x.to_owned()));
                                    i = i + 1;

                                }
                           },

            _           =>

                           {
                                if self.cmd_exists(program)
                                {

                                    run::process_status(program, argv); //spawns new process, waits for completion - must take vector string args for program

                                }
                                else
                                {
                                    println!("{:s}: command not found", program);
                                }
                            }
        }
        let cwd = os::getcwd();
        print(format!("{}: ", cwd.display()));

    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]); //
        //print(ret);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();
    let newhis = ~[];
    match opt_cmd_line {
        Some(cmd_line) => Shell::new("", newhis).run_cmdline(cmd_line),
        None           => Shell::new("gash > ", newhis).run()
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate hyper;
extern crate pretty_env_logger;

use hyper::{Body, Response, Server};
use hyper::service::service_fn_ok;
use hyper::rt::{self, Future};

static INDEX1: &'static [u8] = b"The 1st service!";
static INDEX2: &'static [u8] = b"The 2nd service!";

fn main() {
    pretty_env_logger::init();

    let addr1 = ([127, 0, 0, 1], 1337).into();
    let addr2 = ([127, 0, 0, 1], 1338).into();

    rt::run(rt::lazy(move || {
        let srv1 = Server::bind(&addr1)
            .serve(|| service_fn_ok(|_| Response::new(Body::from(INDEX1))))
            .map_err(|e| eprintln!("server 1 error: {}", e));

        let srv2 = Server::bind(&addr2)
            .serve(|| service_fn_ok(|_| Response::new(Body::from(INDEX2))))
            .map_err(|e| eprintln!("server 2 error: {}", e));

        println!("Listening on http://{} and http://{}", addr1, addr2);

        rt::spawn(srv1);
        rt::spawn(srv2);

        Ok(())
    }));
}
<commit_msg>docs(examples): Update multi_server example to use async await<commit_after>#![feature(async_await)]
#![deny(warnings)]
extern crate hyper;
extern crate pretty_env_logger;

use hyper::{Body, Request, Response, Server};
use hyper::service::{service_fn, make_service_fn};
use futures_util::future::join;

static INDEX1: &'static [u8] = b"The 1st service!";
static INDEX2: &'static [u8] = b"The 2nd service!";

async fn index1(_: Request<Body>) -> Result<Response<Body>, hyper::Error> {
    Ok(Response::new(Body::from(INDEX1)))
}

async fn index2(_: Request<Body>) -> Result<Response<Body>, hyper::Error> {
    Ok(Response::new(Body::from(INDEX2)))
}

#[hyper::rt::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    pretty_env_logger::init();

    let addr1 = ([127, 0, 0, 1], 1337).into();
    let addr2 = ([127, 0, 0, 1], 1338).into();

    let srv1 = Server::bind(&addr1)
        .serve(make_service_fn(|_| {
            async {
                Ok::<_, hyper::Error>(service_fn(index1))
            }
        }));

    let srv2 = Server::bind(&addr2)
        .serve(make_service_fn(|_| {
            async {
                Ok::<_, hyper::Error>(service_fn(index2))
            }
        }));

    println!("Listening on http://{} and http://{}", addr1, addr2);

    let _ret = join(srv1, srv2).await;

    Ok(())
}
<|endoftext|>


<commit_before>use std::f64;

use coords::Coord;
use lattice::{Crystal, Lattice};
use lattice::LatticeType::*;

pub struct AtomSystem {
    pub dimensions: Coord,
    pub coords: Vec<Atom>
}

/// Every atom in a system has some information connected to it
/// which is used when writing the output.
#[derive(Debug, PartialEq)]
pub struct Atom {
    pub residue_name: String, // Code for the parent residue name
    pub residue_number: u64,  // Number of residue (0-indexed)
    pub atom_name: String,    // Code for the atom name
    pub atom_number: u64,     // Number of the atom (0-indexed)
    pub position: Coord       // Atom position
}

/// Substrate types
pub enum SubstrateType {
    Graphene,
    Silica
}
use self::SubstrateType::*;

// This is a base for generating atoms belonging to a residue.
// Every residue has a name and a list of atoms that belong to it
// with their base coordinates. The names are static since these
// should all be generated only once from a single source.
struct ResidueBase {
    code: &'static str,
    atoms: Vec<ResidueAtom>
}
#[derive(Clone)]
struct ResidueAtom  {
    code: &'static str,
    position: Coord
}

/// Create a substrate of desired input size and type.
pub fn create_substrate((size_x, size_y): (f64, f64), substrate_type: SubstrateType)
        -> Result<AtomSystem, String> {
    if size_x <= 0.0 || size_y <= 0.0 {
        return Err("input sizes of the system have to be positive".to_string());
    }

    let substrate = match substrate_type {
        Graphene => create_graphene(size_x, size_y),
        Silica => create_silica(size_x, size_y),
    };

    Ok(substrate)
}

// Create a graphene layer of desired input size.
//
// The layer consists of a hexagonal grid of carbon atoms
// which is created with a bond length of 0.142 nm. To ensure
// that the system can be periodically replicated along x and y
// the dimensions are trimmed to the closest possible size
// that fits an even number of replicas.
fn create_graphene(size_x: f64, size_y: f64) -> AtomSystem {
    let bond_length = 0.142;
    let z0 = bond_length;
    let residue_base = get_graphene_base(bond_length);

    let crystal = Crystal::from_type(Hexagonal { length: bond_length });
    let lattice = Lattice::from_size(&crystal, size_x, size_y)
        .translate(&Coord { x: 0.0, y: 0.0, z: z0 });
    let atoms = gen_atom_list(&lattice.coords, residue_base);

    AtomSystem {
        dimensions: lattice.box_size.add(&Coord { x: 0.0, y: 0.0, z: 2.0*z0 }),
        coords: atoms
    }
}

fn create_silica(size_x: f64, size_y: f64) -> AtomSystem {
    let bond_length = 0.450;
    let z0 = 0.30;
    let residue_base = get_silica_base(bond_length);

    let angle = 60.0f64.to_radians();
    let crystal = Crystal::from_type(Triclinic { a: bond_length, b: bond_length, gamma: angle });
    let lattice = Lattice::from_size(&crystal, size_x, size_y)
        .translate(&Coord { x: 0.0, y: 0.0, z: z0 });
    let atoms = gen_atom_list(&lattice.coords, residue_base);

    AtomSystem {
        dimensions: lattice.box_size.add(&Coord { x: 0.0, y: 0.0, z: 2.0*z0 }),
        coords: atoms
    }
}

// Use a constructed grid and generate atoms of a residue for them
fn gen_atom_list(coords: &Vec<Coord>, residue: ResidueBase) -> Vec<Atom> {
    let mut atoms: Vec<Atom> = Vec::new();
    for (i, point) in coords.iter().enumerate() {
        for (j, atom) in residue.atoms.iter().enumerate() {
            atoms.push(get_atom(i, j, point, atom, &residue));
        }
    }

    atoms
}

fn get_atom(residue_number: usize, atom_number: usize, grid_point: &Coord,
            atom: &ResidueAtom, residue: &ResidueBase) -> Atom {
    Atom {
        residue_name: residue.code.to_string(),
        residue_number: residue_number as u64,
        atom_name: atom.code.to_string(),
        atom_number: (residue.atoms.len()*residue_number) as u64 + (atom_number as u64),
        position: grid_point.add(&atom.position)
    }
}

// A base graphene molecule is only a carbon atom.
fn get_graphene_base(bond_length: f64) -> ResidueBase {
    ResidueBase {
        code: "GRPH",
        atoms: vec![
            ResidueAtom {
                code: "C",
                position: Coord::new(bond_length/2.0, bond_length/2.0, bond_length/2.0)
            }
        ]
    }
}

// A base silica molecule consists of three atoms.
fn get_silica_base(bond_length: f64) -> ResidueBase {
    let z0 = 0.000;
    let dz = 0.151;

    let base_coord = Coord::new(bond_length/4.0, bond_length/6.0, z0);

    ResidueBase {
        code: "SIO",
        atoms: vec![
            ResidueAtom { code: "O1", position: base_coord.add_manual(0.0, 0.0,  dz)},
            ResidueAtom { code: "SI", position: base_coord },
            ResidueAtom { code: "O2", position: base_coord.add_manual(0.0, 0.0, -dz)}
        ]
    }
}

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

    #[test]
    fn gen_a_graphene_layer() {
        let desired_size = (1.0, 1.0);
        let graphene = create_graphene(desired_size.0, desired_size.1).unwrap();

        // Assert that we get the expected dimensions which create
        // perfect PBC replicability
        let bond_length = 0.142;
        let spacing = (2.0*bond_length*f64::sqrt(3.0)/2.0, 3.0*bond_length);
        let dimensions = Coord::new(
            f64::round(desired_size.0/spacing.0) * spacing.0,
            f64::round(desired_size.1/spacing.1) * spacing.1,
            0.0);

        assert_eq!(dimensions, graphene.dimensions);

        // We expect 32 atoms to exist in the grid
        assert_eq!(32, graphene.coords.len());

        // Verify the first atom
        let mut atoms = graphene.coords.iter();
        let first_atom = Atom {
            residue_name: "GRPH".to_string(),
            residue_number: 0,
            atom_name: "C".to_string(),
            atom_number: 0,
            position: Coord::new(bond_length/2.0, bond_length/2.0, bond_length/2.0)
        };
        assert_eq!(Some(&first_atom), atoms.next());
    }
}
<commit_msg>Add residue constructors to ResidueBase<commit_after>use std::f64;

use coords::Coord;
use lattice::{Crystal, Lattice};
use lattice::LatticeType::*;

pub struct AtomSystem {
    pub dimensions: Coord,
    pub coords: Vec<Atom>
}

/// Every atom in a system has some information connected to it
/// which is used when writing the output.
#[derive(Debug, PartialEq)]
pub struct Atom {
    pub residue_name: String, // Code for the parent residue name
    pub residue_number: u64,  // Number of residue (0-indexed)
    pub atom_name: String,    // Code for the atom name
    pub atom_number: u64,     // Number of the atom (0-indexed)
    pub position: Coord       // Atom position
}

/// Substrate types
pub enum SubstrateType {
    Graphene,
    Silica
}
use self::SubstrateType::*;

/// This is a base for generating atoms belonging to a residue.
/// Every residue has a name and a list of atoms that belong to it
/// with their base coordinates. The names are static since these
/// should all be generated only once from a single source.
struct ResidueBase {
    code: &'static str,
    atoms: Vec<ResidueAtom>
}

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

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

        ResidueBase {
            code: "SIO",
            atoms: vec![
                ResidueAtom { code: "O1", position: base_coord.add_manual(0.0, 0.0,  dz)},
                ResidueAtom { code: "SI", position: base_coord },
                ResidueAtom { code: "O2", position: base_coord.add_manual(0.0, 0.0, -dz)}
            ]
        }
    }
}

/// Every atom in a residue has their own code and relative position
#[derive(Clone, Copy)]
struct ResidueAtom  {
    code: &'static str,
    position: Coord
}

/// Create a substrate of desired input size and type.
pub fn create_substrate((size_x, size_y): (f64, f64), substrate_type: SubstrateType)
        -> Result<AtomSystem, String> {
    if size_x <= 0.0 || size_y <= 0.0 {
        return Err("input sizes of the system have to be positive".to_string());
    }

    let substrate = match substrate_type {
        Graphene => create_graphene(size_x, size_y),
        Silica => create_silica(size_x, size_y),
    };

    Ok(substrate)
}

/// Create a graphene layer of desired size.
///
/// The layer consists of a hexagonal lattice of carbon atoms
/// which is created with a bond length of 0.142 nm. To ensure
/// that the system can be periodically replicated along x and y
/// the dimensions are trimmed to the closest possible size
/// that fits an even number of replicas.
fn create_graphene(size_x: f64, size_y: f64) -> AtomSystem {
    let bond_length = 0.142;
    let z0 = bond_length;
    let residue_base = ResidueBase::graphene(bond_length);

    let crystal = Crystal::from_type(Hexagonal { length: bond_length });
    let lattice = Lattice::from_size(&crystal, size_x, size_y)
        .translate(&Coord { x: 0.0, y: 0.0, z: z0 });
    let atoms = gen_atom_list(&lattice.coords, residue_base);

    AtomSystem {
        dimensions: lattice.box_size.add(&Coord { x: 0.0, y: 0.0, z: 2.0*z0 }),
        coords: atoms
    }
}

/// Create a silica layer of desired size.
///
/// The layer consists of a triclinic lattice where the spacing
/// is 0.45 along both vectors and the angle between them
/// is 60 degrees. At each lattice point an SiO2 molecule is placed.
fn create_silica(size_x: f64, size_y: f64) -> AtomSystem {
    let bond_length = 0.450;
    let z0 = 0.30;
    let residue_base = ResidueBase::silica(bond_length);

    let angle = 60.0f64.to_radians();
    let crystal = Crystal::from_type(Triclinic { a: bond_length, b: bond_length, gamma: angle });
    let lattice = Lattice::from_size(&crystal, size_x, size_y)
        .translate(&Coord { x: 0.0, y: 0.0, z: z0 });
    let atoms = gen_atom_list(&lattice.coords, residue_base);

    AtomSystem {
        dimensions: lattice.box_size.add(&Coord { x: 0.0, y: 0.0, z: 2.0*z0 }),
        coords: atoms
    }
}

// Use a constructed grid and generate atoms of a residue for them
fn gen_atom_list(coords: &Vec<Coord>, residue: ResidueBase) -> Vec<Atom> {
    let mut atoms: Vec<Atom> = Vec::new();

    for (residue_number, lattice_point) in coords.iter().enumerate() {
        for (atom_number, residue_atom) in residue.atoms.iter().enumerate() {
            let atom = Atom {
                residue_name: residue.code.to_string(),
                residue_number: residue_number as u64,
                atom_name: residue_atom.code.to_string(),
                atom_number: (residue.atoms.len()*residue_number) as u64 + (atom_number as u64),
                position: lattice_point.add(&residue_atom.position)
            };
            atoms.push(atom);
        }
    }

    atoms
}

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

    #[test]
    fn gen_a_graphene_layer() {
        let desired_size = (1.0, 1.0);
        let graphene = create_graphene(desired_size.0, desired_size.1).unwrap();

        // Assert that we get the expected dimensions which create
        // perfect PBC replicability
        let bond_length = 0.142;
        let spacing = (2.0*bond_length*f64::sqrt(3.0)/2.0, 3.0*bond_length);
        let dimensions = Coord::new(
            f64::round(desired_size.0/spacing.0) * spacing.0,
            f64::round(desired_size.1/spacing.1) * spacing.1,
            0.0);

        assert_eq!(dimensions, graphene.dimensions);

        // We expect 32 atoms to exist in the grid
        assert_eq!(32, graphene.coords.len());

        // Verify the first atom
        let mut atoms = graphene.coords.iter();
        let first_atom = Atom {
            residue_name: "GRPH".to_string(),
            residue_number: 0,
            atom_name: "C".to_string(),
            atom_number: 0,
            position: Coord::new(bond_length/2.0, bond_length/2.0, bond_length/2.0)
        };
        assert_eq!(Some(&first_atom), atoms.next());
    }
}
<|endoftext|>


<commit_before>//! Symbol- and name-storage facilities.
//!
//! This is based on [Servo's string-cache
//! library](https://github.com/servo/string-cache); at the moment it's very
//! lifetime-unsafe for `Pooled` instances.
use std;
use std::fmt;
use std::convert::AsRef;
use std::hash::{Hash, Hasher, SipHasher};
use std::collections::BTreeMap;
use std::borrow::ToOwned;

use super::util::memcpy;
use super::util::hash::{stdhash as hash};

#[macro_use]
pub mod nameable;
pub use self::nameable::Nameable;

/// Methods required of `unpacked` types.
pub trait PackFormat {
    /// Pack an unpacked symbol in the implementing format into a generic
    /// Symbol object.
    fn pack(&self) -> Symbol;

    /// Unpack a generic Symbol into the implementing format.  This function is
    /// marked as `unsafe` because the caller must verify that the symbol is
    /// indeed packed by the receiver's implementation.
    unsafe fn unpack(sym: &Symbol) -> Self;

    /// Fetch a `&str` slice from a symbol packed in the implementing format.
    /// This function is marked as `unsafe` because the caller must verify that
    /// the symbol is indeed packed by the receiver's implementation.
    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str;
}

/* ****************************************************************
 * Pool
 */
/// A collection of symbols.
#[derive(Debug)]
pub struct Pool {
    map:  BTreeMap<u64,String>
}

impl Pool {
    /// Create a new symbol pool.
    pub fn new() -> Pool {
        Pool{map: BTreeMap::new()}
    }

    /// Fetch a symbol corresponding to the given string.
    pub fn symbol(&mut self, name: &str) -> Symbol {
        if name.len() <= INLINE_SYMBOL_MAX_LEN
        { Inline::new(name).pack() }
        else { let hsh = hash::<_, SipHasher>(&name) << 1;
               if ! self.map.contains_key(&hsh) {
                   self.map.insert(hsh, name.to_owned());
               }

               Pooled::new(hsh, self).pack()
        }
    }
}

/* ****************************************************************
 * Symbol
 */
/// An atomic `Copy`able string.  Symbol either encodes a short string
/// directly, or stores it in an external Pool.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub struct Symbol {
    value: [u64; 2]
}

impl Symbol {
    /// Convert the symbol to its unpacked representation.
    #[inline(always)]
    pub fn unpack(&self) -> Unpacked
    { unsafe { <Unpacked as PackFormat>::unpack(self) } }

    /// Get symbol's pack format.
    #[inline(always)]
    pub fn type_of(&self) -> Type {
        match (self.value[0] & 0x01) as u8 {
            INLINE => Type::INLINE,
            POOLED => Type::POOLED,
            _ => unreachable!()
        }
    }

}

impl AsRef<str> for Symbol {
    fn as_ref<'t>(&'t self) -> &'t str { unsafe { <Unpacked as PackFormat>::as_slice_from(self) } }
}

impl Nameable for Symbol {
    fn name(&self) -> Symbol { *self }
}

impl Hash for Symbol {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_ref().hash(state);
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

/* ****************************************************************
 * Inline
 */
// We currently get
//
//    error: array length constant evaluation error: unimplemented constant expression: calling non-local const fn [E0250]
//
// when trying to declare the data array in `struct Inline`, below, if we try to use the obvious expression here.
//const INLINE_SYMBOL_MAX_LEN: usize = std::mem::size_of::<Symbol>() - 1;
/// Maximum number of bytes in a packed (inline) symbol name.
const INLINE_SYMBOL_MAX_LEN: usize = 15;

/// Data format for symbols packed entirely into a `Symbol` instance.
#[derive(Debug)]
pub struct Inline{len: u8, data: [u8; INLINE_SYMBOL_MAX_LEN]}

impl Inline {
    /// Create a new Inline-format symbol using the given string.
    pub fn new(name: &str) -> Self {
        panic_unless!(name.len() <= INLINE_SYMBOL_MAX_LEN,
                      "Argument to Inline::new (length {}) exceeds maximum length ({}) for an inlined symbol",
                      name.len(), INLINE_SYMBOL_MAX_LEN);
        let mut buf: [u8; INLINE_SYMBOL_MAX_LEN] = [0; INLINE_SYMBOL_MAX_LEN];

        unsafe { memcpy(&mut buf[..], name.as_bytes()); }
        Inline{len: name.len() as u8, data: buf}
    }
}

impl AsRef<str> for Inline {
    fn as_ref<'t>(&'t self) -> &'t str {
        let src: &[u8] = self.data.as_ref();
        std::str::from_utf8(&src[..(self.len as usize)]).unwrap()
    }
}

impl PackFormat for Inline {
    // Convert the Inline symbol into a generic packed representation.
    fn pack(&self) -> Symbol {
        unsafe {
            let mut out = Symbol{ value: [0; 2] };
            let mut dest: &mut [u8; 16] = std::mem::transmute(&mut out.value);
            dest[0] = (self.len << 1) | INLINE;
            memcpy(&mut dest[1..], &self.data);
            out
        }
    }
    unsafe fn unpack(sym: &Symbol) -> Self {
        let mut out = Inline{len: 0, data: [0; INLINE_SYMBOL_MAX_LEN]};
        let src: &[u8;16] =
            std::mem::transmute(&sym.value);

        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        out.len = src[0] >> 1;
        panic_unless!(out.len <= INLINE_SYMBOL_MAX_LEN as u8,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      out.len, INLINE_SYMBOL_MAX_LEN);
        memcpy(&mut out.data[..], &src[1..(out.len as usize + 1)]);

        out
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        let src: &[u8; 16] = std::mem::transmute(&sym.value);
        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        let len: usize = (src[0] >> 1) as usize;
        panic_unless!(len <= INLINE_SYMBOL_MAX_LEN,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      len, INLINE_SYMBOL_MAX_LEN);

        std::str::from_utf8(&src[1..(len + 1)]).unwrap()
    }
}

impl std::cmp::Eq for Inline {}
impl std::cmp::PartialEq for Inline {
    fn eq(&self, other: &Self) -> bool {
        self.len == other.len && self.data == other.data
    }
}

/* ****************************************************************
 * Pooled
 */
/// Data format for symbols stored as references to a symbol pool.
#[derive(Debug)]
pub struct Pooled{key: u64, pool: *const Pool}

impl Pooled {
    #[inline(always)]
    pub fn new(key: u64, pool: *const Pool) -> Self {
        Pooled{key: key, pool: pool}
    }

}

impl AsRef<str> for Pooled {
    fn as_ref<'u>(&'u self) -> &'u str {
        unsafe { (*self.pool).map[&self.key].as_ref() }
    }
}

impl PackFormat for Pooled {
    fn pack(&self) -> Symbol {
        let mut val: [u64; 2] = [0; 2];
        val[0] = self.key  | POOLED as u64;
        val[1] = self.pool as u64;
        Symbol{value: val}
    }
    unsafe fn unpack(sym: &Symbol) -> Self {
        Pooled{key: sym.value[0],
               pool: std::mem::transmute(sym.value[1] as *const Pool)}
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        panic_unless!(sym.value[0] & TAG_MASK as u64 == POOLED as u64,
                      "Invalid flag bit for pooled symbol");
        std::mem::transmute::<_,&'t Pool>(sym.value[1] as *const Pool).
            map[&sym.value[0]].as_ref()
    }
}

impl std::cmp::Eq for Pooled {}
impl std::cmp::PartialEq for Pooled {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key && self.pool as u64 == other.pool as u64
    }
}

/* ****************************************************************
 * Types
 */
const TAG_MASK: u8 = 0x01;
const POOLED: u8 = 0;
const INLINE: u8 = 1;

/// Storage type for a symbol instance.
pub enum Type {
    /// Symbol data packed into the structure itself
    INLINE = 0,
    /// Reference to a value in a Pool
    POOLED = 1 }

impl std::cmp::Eq for Type {}
impl std::cmp::PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        match *self { Type::INLINE => match *other { Type::INLINE => true, _ => false },
                      Type::POOLED => match *other { Type::POOLED => true, _ => false } }
    }
}

impl std::fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Type::INLINE => write!(f, "inline"),
                      Type::POOLED => write!(f, "pooled") }
    }
}

/* ****************************************************************
 * Unpacked
 */

/// A differentiated `Symbol`.
#[derive(Debug)]
pub enum Unpacked {
    /// Symbol stored inline in `Symbol`'s data fields.
    Inline(Inline),

    /// Symbol stored in a Pool
    Pooled(Pooled)
}

impl PackFormat for Unpacked {
    fn pack(&self) -> Symbol {
        match *self {
            Unpacked::Inline(ref x) => x.pack(),
            Unpacked::Pooled(ref x) => x.pack()
        }
    }

    unsafe fn unpack(sym: &Symbol) -> Unpacked {
        match sym.type_of() {
            Type::POOLED => Unpacked::Pooled(<Pooled as PackFormat>::unpack(sym)),
            Type::INLINE => Unpacked::Inline(<Inline as PackFormat>::unpack(sym)),
        }
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        match sym.type_of() {
            Type::INLINE => <Inline as PackFormat>::as_slice_from(sym),
            Type::POOLED => <Pooled as PackFormat>::as_slice_from(sym)
        }
    }
}

impl AsRef<str> for Unpacked {
    fn as_ref<'t>(&'t self) -> &'t str {
        match *self {
            Unpacked::Inline(ref x) => x.as_ref(),
            Unpacked::Pooled(ref x) => x.as_ref()
        }
    }
}

impl std::cmp::Eq for Unpacked {}
impl std::cmp::PartialEq for Unpacked {
    fn eq(&self, other: &Self) -> bool {
        match *self {
            Unpacked::Inline(ref si) =>
                match *other { Unpacked::Inline(ref oi) => si == oi, _ => false },
            Unpacked::Pooled(ref sp) =>
                match *other { Unpacked::Pooled(ref op) => sp == op, _ => false }
        }
    }
}

impl Unpacked {
}
<commit_msg>symbol/mod.rs: don't export `Pooled::new` unnecessarily<commit_after>//! Symbol- and name-storage facilities.
//!
//! This is based on [Servo's string-cache
//! library](https://github.com/servo/string-cache); at the moment it's very
//! lifetime-unsafe for `Pooled` instances.
use std;
use std::fmt;
use std::convert::AsRef;
use std::hash::{Hash, Hasher, SipHasher};
use std::collections::BTreeMap;
use std::borrow::ToOwned;

use super::util::memcpy;
use super::util::hash::{stdhash as hash};

#[macro_use]
pub mod nameable;
pub use self::nameable::Nameable;

/// Methods required of `unpacked` types.
pub trait PackFormat {
    /// Pack an unpacked symbol in the implementing format into a generic
    /// Symbol object.
    fn pack(&self) -> Symbol;

    /// Unpack a generic Symbol into the implementing format.  This function is
    /// marked as `unsafe` because the caller must verify that the symbol is
    /// indeed packed by the receiver's implementation.
    unsafe fn unpack(sym: &Symbol) -> Self;

    /// Fetch a `&str` slice from a symbol packed in the implementing format.
    /// This function is marked as `unsafe` because the caller must verify that
    /// the symbol is indeed packed by the receiver's implementation.
    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str;
}

/* ****************************************************************
 * Pool
 */
/// A collection of symbols.
#[derive(Debug)]
pub struct Pool {
    map:  BTreeMap<u64,String>
}

impl Pool {
    /// Create a new symbol pool.
    pub fn new() -> Pool {
        Pool{map: BTreeMap::new()}
    }

    /// Fetch a symbol corresponding to the given string.
    pub fn symbol(&mut self, name: &str) -> Symbol {
        if name.len() <= INLINE_SYMBOL_MAX_LEN
        { Inline::new(name).pack() }
        else { let hsh = hash::<_, SipHasher>(&name) << 1;
               if ! self.map.contains_key(&hsh) {
                   self.map.insert(hsh, name.to_owned());
               }

               Pooled::new(hsh, self).pack()
        }
    }
}

/* ****************************************************************
 * Symbol
 */
/// An atomic `Copy`able string.  Symbol either encodes a short string
/// directly, or stores it in an external Pool.
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub struct Symbol {
    value: [u64; 2]
}

impl Symbol {
    /// Convert the symbol to its unpacked representation.
    #[inline(always)]
    pub fn unpack(&self) -> Unpacked
    { unsafe { <Unpacked as PackFormat>::unpack(self) } }

    /// Get symbol's pack format.
    #[inline(always)]
    pub fn type_of(&self) -> Type {
        match (self.value[0] & 0x01) as u8 {
            INLINE => Type::INLINE,
            POOLED => Type::POOLED,
            _ => unreachable!()
        }
    }

}

impl AsRef<str> for Symbol {
    fn as_ref<'t>(&'t self) -> &'t str { unsafe { <Unpacked as PackFormat>::as_slice_from(self) } }
}

impl Nameable for Symbol {
    fn name(&self) -> Symbol { *self }
}

impl Hash for Symbol {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_ref().hash(state);
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

/* ****************************************************************
 * Inline
 */
// We currently get
//
//    error: array length constant evaluation error: unimplemented constant expression: calling non-local const fn [E0250]
//
// when trying to declare the data array in `struct Inline`, below, if we try to use the obvious expression here.
//const INLINE_SYMBOL_MAX_LEN: usize = std::mem::size_of::<Symbol>() - 1;
/// Maximum number of bytes in a packed (inline) symbol name.
const INLINE_SYMBOL_MAX_LEN: usize = 15;

/// Data format for symbols packed entirely into a `Symbol` instance.
#[derive(Debug)]
pub struct Inline{len: u8, data: [u8; INLINE_SYMBOL_MAX_LEN]}

impl Inline {
    /// Create a new Inline-format symbol using the given string.
    pub fn new(name: &str) -> Self {
        panic_unless!(name.len() <= INLINE_SYMBOL_MAX_LEN,
                      "Argument to Inline::new (length {}) exceeds maximum length ({}) for an inlined symbol",
                      name.len(), INLINE_SYMBOL_MAX_LEN);
        let mut buf: [u8; INLINE_SYMBOL_MAX_LEN] = [0; INLINE_SYMBOL_MAX_LEN];

        unsafe { memcpy(&mut buf[..], name.as_bytes()); }
        Inline{len: name.len() as u8, data: buf}
    }
}

impl AsRef<str> for Inline {
    fn as_ref<'t>(&'t self) -> &'t str {
        let src: &[u8] = self.data.as_ref();
        std::str::from_utf8(&src[..(self.len as usize)]).unwrap()
    }
}

impl PackFormat for Inline {
    // Convert the Inline symbol into a generic packed representation.
    fn pack(&self) -> Symbol {
        unsafe {
            let mut out = Symbol{ value: [0; 2] };
            let mut dest: &mut [u8; 16] = std::mem::transmute(&mut out.value);
            dest[0] = (self.len << 1) | INLINE;
            memcpy(&mut dest[1..], &self.data);
            out
        }
    }
    unsafe fn unpack(sym: &Symbol) -> Self {
        let mut out = Inline{len: 0, data: [0; INLINE_SYMBOL_MAX_LEN]};
        let src: &[u8;16] =
            std::mem::transmute(&sym.value);

        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        out.len = src[0] >> 1;
        panic_unless!(out.len <= INLINE_SYMBOL_MAX_LEN as u8,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      out.len, INLINE_SYMBOL_MAX_LEN);
        memcpy(&mut out.data[..], &src[1..(out.len as usize + 1)]);

        out
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        let src: &[u8; 16] = std::mem::transmute(&sym.value);
        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        let len: usize = (src[0] >> 1) as usize;
        panic_unless!(len <= INLINE_SYMBOL_MAX_LEN,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      len, INLINE_SYMBOL_MAX_LEN);

        std::str::from_utf8(&src[1..(len + 1)]).unwrap()
    }
}

impl std::cmp::Eq for Inline {}
impl std::cmp::PartialEq for Inline {
    fn eq(&self, other: &Self) -> bool {
        self.len == other.len && self.data == other.data
    }
}

/* ****************************************************************
 * Pooled
 */
/// Data format for symbols stored as references to a symbol pool.
#[derive(Debug)]
pub struct Pooled{key: u64, pool: *const Pool}

impl Pooled {
    #[inline(always)]
    fn new(key: u64, pool: *const Pool) -> Self {
        Pooled{key: key, pool: pool}
    }

}

impl AsRef<str> for Pooled {
    fn as_ref<'u>(&'u self) -> &'u str {
        unsafe { (*self.pool).map[&self.key].as_ref() }
    }
}

impl PackFormat for Pooled {
    fn pack(&self) -> Symbol {
        let mut val: [u64; 2] = [0; 2];
        val[0] = self.key  | POOLED as u64;
        val[1] = self.pool as u64;
        Symbol{value: val}
    }
    unsafe fn unpack(sym: &Symbol) -> Self {
        Pooled{key: sym.value[0],
               pool: std::mem::transmute(sym.value[1] as *const Pool)}
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        panic_unless!(sym.value[0] & TAG_MASK as u64 == POOLED as u64,
                      "Invalid flag bit for pooled symbol");
        std::mem::transmute::<_,&'t Pool>(sym.value[1] as *const Pool).
            map[&sym.value[0]].as_ref()
    }
}

impl std::cmp::Eq for Pooled {}
impl std::cmp::PartialEq for Pooled {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key && self.pool as u64 == other.pool as u64
    }
}

/* ****************************************************************
 * Types
 */
const TAG_MASK: u8 = 0x01;
const POOLED: u8 = 0;
const INLINE: u8 = 1;

/// Storage type for a symbol instance.
pub enum Type {
    /// Symbol data packed into the structure itself
    INLINE = 0,
    /// Reference to a value in a Pool
    POOLED = 1 }

impl std::cmp::Eq for Type {}
impl std::cmp::PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        match *self { Type::INLINE => match *other { Type::INLINE => true, _ => false },
                      Type::POOLED => match *other { Type::POOLED => true, _ => false } }
    }
}

impl std::fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Type::INLINE => write!(f, "inline"),
                      Type::POOLED => write!(f, "pooled") }
    }
}

/* ****************************************************************
 * Unpacked
 */

/// A differentiated `Symbol`.
#[derive(Debug)]
pub enum Unpacked {
    /// Symbol stored inline in `Symbol`'s data fields.
    Inline(Inline),

    /// Symbol stored in a Pool
    Pooled(Pooled)
}

impl PackFormat for Unpacked {
    fn pack(&self) -> Symbol {
        match *self {
            Unpacked::Inline(ref x) => x.pack(),
            Unpacked::Pooled(ref x) => x.pack()
        }
    }

    unsafe fn unpack(sym: &Symbol) -> Unpacked {
        match sym.type_of() {
            Type::POOLED => Unpacked::Pooled(<Pooled as PackFormat>::unpack(sym)),
            Type::INLINE => Unpacked::Inline(<Inline as PackFormat>::unpack(sym)),
        }
    }

    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        match sym.type_of() {
            Type::INLINE => <Inline as PackFormat>::as_slice_from(sym),
            Type::POOLED => <Pooled as PackFormat>::as_slice_from(sym)
        }
    }
}

impl AsRef<str> for Unpacked {
    fn as_ref<'t>(&'t self) -> &'t str {
        match *self {
            Unpacked::Inline(ref x) => x.as_ref(),
            Unpacked::Pooled(ref x) => x.as_ref()
        }
    }
}

impl std::cmp::Eq for Unpacked {}
impl std::cmp::PartialEq for Unpacked {
    fn eq(&self, other: &Self) -> bool {
        match *self {
            Unpacked::Inline(ref si) =>
                match *other { Unpacked::Inline(ref oi) => si == oi, _ => false },
            Unpacked::Pooled(ref sp) =>
                match *other { Unpacked::Pooled(ref op) => sp == op, _ => false }
        }
    }
}

impl Unpacked {
}
<|endoftext|>