<commit_before>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use time;
use std::time::Duration;
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> (u64, bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn get_time() -> u64 {
    let timespec = time::get_time();
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0 );
    mills as u64
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub enum Membership {
    LEADER,
    FOLLOWER,
    CANDIDATE,
    OFFLINE,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    leader_meta: Option<LeaderMeta>,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    leader_meta: None,
                    membership: Membership::FOLLOWER,
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    match meta.membership {
                        Membership::LEADER => {
                            let send_heartbeat = if let Some(ref leader_meta) = meta.leader_meta {
                                get_time() > (leader_meta.last_updated + CHECKER_MS)
                            } else {false};
                            if send_heartbeat {
                                server.send_heartbeat(&mut meta, None);
                            }
                        },
                        Membership::FOLLOWER | Membership::CANDIDATE => {
                            if get_time() > (meta.timeout + meta.last_checked) {
                                //Timeout, require election
                                server.become_candidate(&mut meta);
                            }
                        },
                        Membership::OFFLINE => {
                            break;
                        }
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn become_candidate(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(self.id);
        meta.membership = Membership::CANDIDATE;

    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.membership = Membership::FOLLOWER;
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.membership = Membership::LEADER;
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leaderId: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<(u64, bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term);
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term_ok {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok((meta.term, vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }
}
<commit_msg>move membership props into enum<commit_after>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use time;
use std::time::Duration;
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> (u64, bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn get_time() -> u64 {
    let timespec = time::get_time();
    let mills: f64 = timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0 );
    mills as u64
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

impl LeaderMeta {
    fn new() -> LeaderMeta {
        LeaderMeta{
            last_updated: get_time(),
            next_index: HashMap::new(),
            match_index: HashMap::new(),
        }
    }
}

pub struct FollowerMeta {
    leader_id: u64,
}

impl FollowerMeta {
    fn new() -> FollowerMeta {
        FollowerMeta{
            leader_id: 0
        }
    }
    fn with_leader(id: u64) -> FollowerMeta {
        FollowerMeta{
            leader_id: id
        }
    }
}

pub struct CandidateMeta {

}

impl CandidateMeta {
    fn  new() -> CandidateMeta {
        CandidateMeta{

        }
    }
}

pub enum Membership {
    LEADER(LeaderMeta),
    FOLLOWER(FollowerMeta),
    CANDIDATE(CandidateMeta),
    OFFLINE,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

enum CheckerAction {
    SEND_HEARTBEAT,
    BECOME_CANDIDATE,
    EXIT_LOOP,
    NONE
}
impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    membership: Membership::FOLLOWER(FollowerMeta::new()),
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    let action = match meta.membership {
                        Membership::LEADER(ref leader_meta) => {
                            if get_time() > (leader_meta.last_updated + CHECKER_MS) {
                                CheckerAction::SEND_HEARTBEAT
                            } else {
                                CheckerAction::NONE
                            }
                        },
                        Membership::FOLLOWER(_) | Membership::CANDIDATE(_) => {
                            if get_time() > (meta.timeout + meta.last_checked) {
                                //Timeout, require election
                                CheckerAction::BECOME_CANDIDATE
                            } else {
                                CheckerAction::NONE
                            }
                        },
                        Membership::OFFLINE => {
                            CheckerAction::EXIT_LOOP
                        }
                    };
                    match action {
                        CheckerAction::SEND_HEARTBEAT => {
                            server.send_heartbeat(&mut meta, None);
                        },
                        CheckerAction::BECOME_CANDIDATE => {
                            server.become_candidate(&mut meta);
                        },
                        CheckerAction::EXIT_LOOP => {
                            break;
                        },
                        CheckerAction::NONE => {}
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn become_candidate(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(self.id);
        meta.membership = Membership::CANDIDATE(CandidateMeta::new());

    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>, leader_id: u64) {
        meta.membership = Membership::FOLLOWER(FollowerMeta::with_leader(leader_id));
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.membership = Membership::LEADER(LeaderMeta::new());
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64, leader_id: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta, leader_id)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leader_id: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<(u64, bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term >= meta.term {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok((meta.term, vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::borrow::Cow;
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::path::Path;
use serialize::Encodable;
use hyper::status::StatusCode;
use hyper::server::Response as HyperResponse;
use hyper::header::{
    Headers, Date, HttpDate, Server, ContentType, ContentLength, Header, HeaderFormat
};
use hyper::net::{Fresh, Streaming};
use time;
use mimes::MediaType;
use mustache;
use mustache::Template;
use std::io::{self, Read, Write, copy};
use std::fs::File;
use std::any::Any;
use {NickelError, Halt, MiddlewareResult, Responder};
use modifier::Modifier;
use plugin::{Extensible, Pluggable};
use typemap::TypeMap;

pub type TemplateCache = RwLock<HashMap<String, Template>>;

///A container for the response
pub struct Response<'a, D: 'a = (), T: 'static + Any = Fresh> {
    ///the original `hyper::server::Response`
    origin: HyperResponse<'a, T>,
    templates: &'a TemplateCache,
    data: &'a D,
    map: TypeMap,
    // This should be FnBox, but that's currently unstable
    on_send: Vec<Box<FnMut(&mut Response<'a, D, Fresh>)>>
}

impl<'a, D> Response<'a, D, Fresh> {
    pub fn from_internal<'c, 'd>(response: HyperResponse<'c, Fresh>,
                                 templates: &'c TemplateCache,
                                 data: &'c D)
                                -> Response<'c, D, Fresh> {
        Response {
            origin: response,
            templates: templates,
            data: data,
            map: TypeMap::new(),
            on_send: vec![]
        }
    }

    /// Get a mutable reference to the status.
    pub fn status_mut(&mut self) -> &mut StatusCode {
        self.origin.status_mut()
    }

    /// Get a mutable reference to the Headers.
    pub fn headers_mut(&mut self) -> &mut Headers {
        self.origin.headers_mut()
    }

    /// Modify the response with the provided data.
    ///
    /// # Examples
    /// ```{rust}
    /// extern crate hyper;
    /// #[macro_use] extern crate nickel;
    ///
    /// use nickel::{Nickel, HttpRouter, MediaType};
    /// use nickel::status::StatusCode;
    /// use hyper::header::Location;
    ///
    /// fn main() {
    ///     let mut server = Nickel::new();
    ///     server.get("/a", middleware! { |_, mut res|
    ///             // set the Status
    ///         res.set(StatusCode::PermanentRedirect)
    ///             // update a Header value
    ///            .set(Location("http://nickel.rs".into()));
    ///
    ///         ""
    ///     });
    ///
    ///     server.get("/b", middleware! { |_, mut res|
    ///             // setting the content type
    ///         res.set(MediaType::Json);
    ///
    ///         "{'foo': 'bar'}"
    ///     });
    ///
    ///     // ...
    /// }
    /// ```
    pub fn set<T: Modifier<Response<'a, D>>>(&mut self, attribute: T) -> &mut Response<'a, D> {
        attribute.modify(self);
        self
    }

    /// Writes a response
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult};
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     res.send("hello world")
    /// }
    /// ```
    #[inline]
    pub fn send<T: Responder<D>>(self, data: T) -> MiddlewareResult<'a, D> {
        data.respond(self)
    }

    /// Writes a file to the output.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult};
    /// use std::path::Path;
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     let favicon = Path::new("/assets/favicon.ico");
    ///     res.send_file(favicon)
    /// }
    /// ```
    pub fn send_file<P:AsRef<Path>>(mut self, path: P) -> MiddlewareResult<'a, D> {
        let path = path.as_ref();
        // Chunk the response
        self.origin.headers_mut().remove::<ContentLength>();
        // Determine content type by file extension or default to binary
        let mime = mime_from_filename(path).unwrap_or(MediaType::Bin);
        self.set(mime);

        let mut file = try_with!(self, {
            File::open(path).map_err(|e| format!("Failed to send file '{:?}': {}",
                                                 path, e))
        });

        let mut stream = try!(self.start());
        match copy(&mut file, &mut stream) {
            Ok(_) => Ok(Halt(stream)),
            Err(e) => stream.bail(format!("Failed to send file: {}", e))
        }
    }

    // TODO: This needs to be more sophisticated to return the correct headers
    // not just "some headers" :)
    //
    // Also, it should only set them if not already set.
    fn set_fallback_headers(&mut self) {
        self.set_header_fallback(|| Date(HttpDate(time::now_utc())));
        self.set_header_fallback(|| Server("Nickel".to_string()));
        self.set_header_fallback(|| ContentType(MediaType::Html.into()));
    }

    /// Return an error with the appropriate status code for error handlers to
    /// provide output for.
    pub fn error<T>(self, status: StatusCode, message: T) -> MiddlewareResult<'a, D>
            where T: Into<Cow<'static, str>> {
        Err(NickelError::new(self, message, status))
    }

    /// Sets the header if not already set.
    ///
    /// If the header is not set then `f` will be called.
    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// #[macro_use] extern crate nickel;
    /// extern crate hyper;
    ///
    /// use nickel::{Nickel, HttpRouter, MediaType};
    /// use hyper::header::ContentType;
    ///
    /// # #[allow(unreachable_code)]
    /// fn main() {
    ///     let mut server = Nickel::new();
    ///     server.get("/", middleware! { |_, mut res|
    ///         res.set(MediaType::Html);
    ///         res.set_header_fallback(|| {
    ///             panic!("Should not get called");
    ///             ContentType(MediaType::Txt.into())
    ///         });
    ///
    ///         "<h1>Hello World</h1>"
    ///     });
    ///
    ///     // ...
    /// }
    /// ```
    pub fn set_header_fallback<F, H>(&mut self, f: F)
            where H: Header + HeaderFormat, F: FnOnce() -> H {
        let headers = self.origin.headers_mut();
        if !headers.has::<H>() { headers.set(f()) }
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// use std::collections::HashMap;
    /// use nickel::{Request, Response, MiddlewareResult};
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     let mut data = HashMap::new();
    ///     data.insert("name", "user");
    ///     res.render("examples/assets/template.tpl", &data)
    /// }
    /// ```
    pub fn render<T, P>(self, path: P, data: &T) -> MiddlewareResult<'a, D>
            where T: Encodable, P: AsRef<str> + Into<String> {
        fn render<'a, D, T>(res: Response<'a, D>, template: &Template, data: &T)
                -> MiddlewareResult<'a, D> where T: Encodable {
            let mut stream = try!(res.start());
            match template.render(&mut stream, data) {
                Ok(()) => Ok(Halt(stream)),
                Err(e) => stream.bail(format!("Problem rendering template: {:?}", e))
            }
        }

        // Fast path doesn't need writer lock
        if let Some(t) = self.templates.read().unwrap().get(path.as_ref()) {
            return render(self, t, data);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.templates.write().unwrap();

        // Additional clone required for now as the entry api doesn't give us a key ref
        let path = path.into();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.clone()) {
            Vacant(entry) => {
                let template = try_with!(self, {
                    mustache::compile_path(&path)
                             .map_err(|e| format!("Failed to compile template '{}': {:?}",
                                            path, e))
                });
                entry.insert(template)
            },
            Occupied(entry) => entry.into_mut()
        };

        render(self, template, data)
    }

    pub fn start(mut self) -> Result<Response<'a, D, Streaming>, NickelError<'a, D>> {
        let on_send = mem::replace(&mut self.on_send, vec![]);
        for mut f in on_send.into_iter().rev() {
            // TODO: Ensure `f` doesn't call on_send again
            f(&mut self)
        }

        // Set fallback headers last after everything runs, if we did this before as an
        // on_send then it would possibly set redundant things.
        self.set_fallback_headers();

        let Response { origin, templates, data, map, on_send } = self;
        match origin.start() {
            Ok(origin) => {
                Ok(Response {
                    origin: origin,
                    templates: templates,
                    data: data,
                    map: map,
                    on_send: on_send
                })
            },
            Err(e) =>
                unsafe {
                    Err(NickelError::without_response(format!("Failed to start response: {}", e)))
                }
        }
    }

    pub fn server_data(&self) -> &'a D {
        &self.data
    }

    pub fn on_send<F>(&mut self, f: F)
            where F: FnMut(&mut Response<'a, D, Fresh>) + 'static {
        self.on_send.push(Box::new(f))
    }
}

impl<'a, 'b, D> Write for Response<'a, D, Streaming> {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.origin.write(buf)
    }

    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.origin.flush()
    }
}

impl<'a, 'b, D> Response<'a, D, Streaming> {
    /// In the case of an unrecoverable error while a stream is already in
    /// progress, there is no standard way to signal to the client that an
    /// error has occurred. `bail` will drop the connection and log an error
    /// message.
    pub fn bail<T>(self, message: T) -> MiddlewareResult<'a, D>
            where T: Into<Cow<'static, str>> {
        let _ = self.end();
        unsafe { Err(NickelError::without_response(message)) }
    }

    /// Flushes all writing of a response to the client.
    pub fn end(self) -> io::Result<()> {
        self.origin.end()
    }
}

impl <'a, D, T: 'static + Any> Response<'a, D, T> {
    /// The status of this response.
    pub fn status(&self) -> StatusCode {
        self.origin.status()
    }

    /// The headers of this response.
    pub fn headers(&self) -> &Headers {
        self.origin.headers()
    }

    pub fn data(&self) -> &'a D {
        &self.data
    }
}

impl<'a, D, T: 'static + Any> Extensible for Response<'a, D, T> {
    fn extensions(&self) -> &TypeMap {
        &self.map
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.map
    }
}

impl<'a, D, T: 'static + Any> Pluggable for Response<'a, D, T> {}

fn mime_from_filename<P: AsRef<Path>>(path: P) -> Option<MediaType> {
    path.as_ref()
        .extension()
        .and_then(|os| os.to_str())
        // Lookup mime from file extension
        .and_then(|s| s.parse().ok())
}

#[test]
fn matches_content_type () {
    assert_eq!(Some(MediaType::Txt), mime_from_filename("test.txt"));
    assert_eq!(Some(MediaType::Json), mime_from_filename("test.json"));
    assert_eq!(Some(MediaType::Bin), mime_from_filename("test.bin"));
}

mod modifier_impls {
    use hyper::header::*;
    use hyper::status::StatusCode;
    use modifier::Modifier;
    use {Response, MediaType};

    impl<'a, D> Modifier<Response<'a, D>> for StatusCode {
        fn modify(self, res: &mut Response<'a, D>) {
            *res.status_mut() = self
        }
    }

    impl<'a, D> Modifier<Response<'a, D>> for MediaType {
        fn modify(self, res: &mut Response<'a, D>) {
            ContentType(self.into()).modify(res)
        }
    }

    macro_rules! header_modifiers {
        ($($t:ty),+) => (
            $(
                impl<'a, D> Modifier<Response<'a, D>> for $t {
                    fn modify(self, res: &mut Response<'a, D>) {
                        res.headers_mut().set(self)
                    }
                }
            )+
        )
    }

    header_modifiers! {
        Accept,
        AccessControlAllowHeaders,
        AccessControlAllowMethods,
        AccessControlAllowOrigin,
        AccessControlMaxAge,
        AccessControlRequestHeaders,
        AccessControlRequestMethod,
        AcceptCharset,
        AcceptEncoding,
        AcceptLanguage,
        AcceptRanges,
        Allow,
        Authorization<Basic>,
        Authorization<String>,
        CacheControl,
        Cookie,
        Connection,
        ContentEncoding,
        ContentLanguage,
        ContentLength,
        ContentType,
        Date,
        ETag,
        Expect,
        Expires,
        From,
        Host,
        IfMatch,
        IfModifiedSince,
        IfNoneMatch,
        IfRange,
        IfUnmodifiedSince,
        LastModified,
        Location,
        Pragma,
        Referer,
        Server,
        SetCookie,
        TransferEncoding,
        Upgrade,
        UserAgent,
        Vary
    }
}
<commit_msg>fix(send_file): don't overwrite the ContentType header if it exists<commit_after>use std::mem;
use std::borrow::Cow;
use std::sync::RwLock;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::path::Path;
use serialize::Encodable;
use hyper::status::StatusCode;
use hyper::server::Response as HyperResponse;
use hyper::header::{
    Headers, Date, HttpDate, Server, ContentType, ContentLength, Header, HeaderFormat
};
use hyper::net::{Fresh, Streaming};
use time;
use mimes::MediaType;
use mustache;
use mustache::Template;
use std::io::{self, Read, Write, copy};
use std::fs::File;
use std::any::Any;
use {NickelError, Halt, MiddlewareResult, Responder};
use modifier::Modifier;
use plugin::{Extensible, Pluggable};
use typemap::TypeMap;

pub type TemplateCache = RwLock<HashMap<String, Template>>;

///A container for the response
pub struct Response<'a, D: 'a = (), T: 'static + Any = Fresh> {
    ///the original `hyper::server::Response`
    origin: HyperResponse<'a, T>,
    templates: &'a TemplateCache,
    data: &'a D,
    map: TypeMap,
    // This should be FnBox, but that's currently unstable
    on_send: Vec<Box<FnMut(&mut Response<'a, D, Fresh>)>>
}

impl<'a, D> Response<'a, D, Fresh> {
    pub fn from_internal<'c, 'd>(response: HyperResponse<'c, Fresh>,
                                 templates: &'c TemplateCache,
                                 data: &'c D)
                                -> Response<'c, D, Fresh> {
        Response {
            origin: response,
            templates: templates,
            data: data,
            map: TypeMap::new(),
            on_send: vec![]
        }
    }

    /// Get a mutable reference to the status.
    pub fn status_mut(&mut self) -> &mut StatusCode {
        self.origin.status_mut()
    }

    /// Get a mutable reference to the Headers.
    pub fn headers_mut(&mut self) -> &mut Headers {
        self.origin.headers_mut()
    }

    /// Modify the response with the provided data.
    ///
    /// # Examples
    /// ```{rust}
    /// extern crate hyper;
    /// #[macro_use] extern crate nickel;
    ///
    /// use nickel::{Nickel, HttpRouter, MediaType};
    /// use nickel::status::StatusCode;
    /// use hyper::header::Location;
    ///
    /// fn main() {
    ///     let mut server = Nickel::new();
    ///     server.get("/a", middleware! { |_, mut res|
    ///             // set the Status
    ///         res.set(StatusCode::PermanentRedirect)
    ///             // update a Header value
    ///            .set(Location("http://nickel.rs".into()));
    ///
    ///         ""
    ///     });
    ///
    ///     server.get("/b", middleware! { |_, mut res|
    ///             // setting the content type
    ///         res.set(MediaType::Json);
    ///
    ///         "{'foo': 'bar'}"
    ///     });
    ///
    ///     // ...
    /// }
    /// ```
    pub fn set<T: Modifier<Response<'a, D>>>(&mut self, attribute: T) -> &mut Response<'a, D> {
        attribute.modify(self);
        self
    }

    /// Writes a response
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult};
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     res.send("hello world")
    /// }
    /// ```
    #[inline]
    pub fn send<T: Responder<D>>(self, data: T) -> MiddlewareResult<'a, D> {
        data.respond(self)
    }

    /// Writes a file to the output.
    ///
    /// # Examples
    /// ```{rust}
    /// use nickel::{Request, Response, MiddlewareResult};
    /// use std::path::Path;
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     let favicon = Path::new("/assets/favicon.ico");
    ///     res.send_file(favicon)
    /// }
    /// ```
    pub fn send_file<P:AsRef<Path>>(mut self, path: P) -> MiddlewareResult<'a, D> {
        let path = path.as_ref();
        // Chunk the response
        self.origin.headers_mut().remove::<ContentLength>();
        // Determine content type by file extension or default to binary
        let mime = mime_from_filename(path).unwrap_or(MediaType::Bin);
        self.set_header_fallback(|| ContentType(mime.into()));

        let mut file = try_with!(self, {
            File::open(path).map_err(|e| format!("Failed to send file '{:?}': {}",
                                                 path, e))
        });

        let mut stream = try!(self.start());
        match copy(&mut file, &mut stream) {
            Ok(_) => Ok(Halt(stream)),
            Err(e) => stream.bail(format!("Failed to send file: {}", e))
        }
    }

    // TODO: This needs to be more sophisticated to return the correct headers
    // not just "some headers" :)
    //
    // Also, it should only set them if not already set.
    fn set_fallback_headers(&mut self) {
        self.set_header_fallback(|| Date(HttpDate(time::now_utc())));
        self.set_header_fallback(|| Server("Nickel".to_string()));
        self.set_header_fallback(|| ContentType(MediaType::Html.into()));
    }

    /// Return an error with the appropriate status code for error handlers to
    /// provide output for.
    pub fn error<T>(self, status: StatusCode, message: T) -> MiddlewareResult<'a, D>
            where T: Into<Cow<'static, str>> {
        Err(NickelError::new(self, message, status))
    }

    /// Sets the header if not already set.
    ///
    /// If the header is not set then `f` will be called.
    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// #[macro_use] extern crate nickel;
    /// extern crate hyper;
    ///
    /// use nickel::{Nickel, HttpRouter, MediaType};
    /// use hyper::header::ContentType;
    ///
    /// # #[allow(unreachable_code)]
    /// fn main() {
    ///     let mut server = Nickel::new();
    ///     server.get("/", middleware! { |_, mut res|
    ///         res.set(MediaType::Html);
    ///         res.set_header_fallback(|| {
    ///             panic!("Should not get called");
    ///             ContentType(MediaType::Txt.into())
    ///         });
    ///
    ///         "<h1>Hello World</h1>"
    ///     });
    ///
    ///     // ...
    /// }
    /// ```
    pub fn set_header_fallback<F, H>(&mut self, f: F)
            where H: Header + HeaderFormat, F: FnOnce() -> H {
        let headers = self.origin.headers_mut();
        if !headers.has::<H>() { headers.set(f()) }
    }

    /// Renders the given template bound with the given data.
    ///
    /// # Examples
    /// ```{rust}
    /// use std::collections::HashMap;
    /// use nickel::{Request, Response, MiddlewareResult};
    ///
    /// # #[allow(dead_code)]
    /// fn handler<'a, D>(_: &mut Request<D>, res: Response<'a, D>) -> MiddlewareResult<'a, D> {
    ///     let mut data = HashMap::new();
    ///     data.insert("name", "user");
    ///     res.render("examples/assets/template.tpl", &data)
    /// }
    /// ```
    pub fn render<T, P>(self, path: P, data: &T) -> MiddlewareResult<'a, D>
            where T: Encodable, P: AsRef<str> + Into<String> {
        fn render<'a, D, T>(res: Response<'a, D>, template: &Template, data: &T)
                -> MiddlewareResult<'a, D> where T: Encodable {
            let mut stream = try!(res.start());
            match template.render(&mut stream, data) {
                Ok(()) => Ok(Halt(stream)),
                Err(e) => stream.bail(format!("Problem rendering template: {:?}", e))
            }
        }

        // Fast path doesn't need writer lock
        if let Some(t) = self.templates.read().unwrap().get(path.as_ref()) {
            return render(self, t, data);
        }

        // We didn't find the template, get writers lock
        let mut templates = self.templates.write().unwrap();

        // Additional clone required for now as the entry api doesn't give us a key ref
        let path = path.into();

        // Search again incase there was a race to compile the template
        let template = match templates.entry(path.clone()) {
            Vacant(entry) => {
                let template = try_with!(self, {
                    mustache::compile_path(&path)
                             .map_err(|e| format!("Failed to compile template '{}': {:?}",
                                            path, e))
                });
                entry.insert(template)
            },
            Occupied(entry) => entry.into_mut()
        };

        render(self, template, data)
    }

    pub fn start(mut self) -> Result<Response<'a, D, Streaming>, NickelError<'a, D>> {
        let on_send = mem::replace(&mut self.on_send, vec![]);
        for mut f in on_send.into_iter().rev() {
            // TODO: Ensure `f` doesn't call on_send again
            f(&mut self)
        }

        // Set fallback headers last after everything runs, if we did this before as an
        // on_send then it would possibly set redundant things.
        self.set_fallback_headers();

        let Response { origin, templates, data, map, on_send } = self;
        match origin.start() {
            Ok(origin) => {
                Ok(Response {
                    origin: origin,
                    templates: templates,
                    data: data,
                    map: map,
                    on_send: on_send
                })
            },
            Err(e) =>
                unsafe {
                    Err(NickelError::without_response(format!("Failed to start response: {}", e)))
                }
        }
    }

    pub fn server_data(&self) -> &'a D {
        &self.data
    }

    pub fn on_send<F>(&mut self, f: F)
            where F: FnMut(&mut Response<'a, D, Fresh>) + 'static {
        self.on_send.push(Box::new(f))
    }
}

impl<'a, 'b, D> Write for Response<'a, D, Streaming> {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.origin.write(buf)
    }

    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.origin.flush()
    }
}

impl<'a, 'b, D> Response<'a, D, Streaming> {
    /// In the case of an unrecoverable error while a stream is already in
    /// progress, there is no standard way to signal to the client that an
    /// error has occurred. `bail` will drop the connection and log an error
    /// message.
    pub fn bail<T>(self, message: T) -> MiddlewareResult<'a, D>
            where T: Into<Cow<'static, str>> {
        let _ = self.end();
        unsafe { Err(NickelError::without_response(message)) }
    }

    /// Flushes all writing of a response to the client.
    pub fn end(self) -> io::Result<()> {
        self.origin.end()
    }
}

impl <'a, D, T: 'static + Any> Response<'a, D, T> {
    /// The status of this response.
    pub fn status(&self) -> StatusCode {
        self.origin.status()
    }

    /// The headers of this response.
    pub fn headers(&self) -> &Headers {
        self.origin.headers()
    }

    pub fn data(&self) -> &'a D {
        &self.data
    }
}

impl<'a, D, T: 'static + Any> Extensible for Response<'a, D, T> {
    fn extensions(&self) -> &TypeMap {
        &self.map
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.map
    }
}

impl<'a, D, T: 'static + Any> Pluggable for Response<'a, D, T> {}

fn mime_from_filename<P: AsRef<Path>>(path: P) -> Option<MediaType> {
    path.as_ref()
        .extension()
        .and_then(|os| os.to_str())
        // Lookup mime from file extension
        .and_then(|s| s.parse().ok())
}

#[test]
fn matches_content_type () {
    assert_eq!(Some(MediaType::Txt), mime_from_filename("test.txt"));
    assert_eq!(Some(MediaType::Json), mime_from_filename("test.json"));
    assert_eq!(Some(MediaType::Bin), mime_from_filename("test.bin"));
}

mod modifier_impls {
    use hyper::header::*;
    use hyper::status::StatusCode;
    use modifier::Modifier;
    use {Response, MediaType};

    impl<'a, D> Modifier<Response<'a, D>> for StatusCode {
        fn modify(self, res: &mut Response<'a, D>) {
            *res.status_mut() = self
        }
    }

    impl<'a, D> Modifier<Response<'a, D>> for MediaType {
        fn modify(self, res: &mut Response<'a, D>) {
            ContentType(self.into()).modify(res)
        }
    }

    macro_rules! header_modifiers {
        ($($t:ty),+) => (
            $(
                impl<'a, D> Modifier<Response<'a, D>> for $t {
                    fn modify(self, res: &mut Response<'a, D>) {
                        res.headers_mut().set(self)
                    }
                }
            )+
        )
    }

    header_modifiers! {
        Accept,
        AccessControlAllowHeaders,
        AccessControlAllowMethods,
        AccessControlAllowOrigin,
        AccessControlMaxAge,
        AccessControlRequestHeaders,
        AccessControlRequestMethod,
        AcceptCharset,
        AcceptEncoding,
        AcceptLanguage,
        AcceptRanges,
        Allow,
        Authorization<Basic>,
        Authorization<String>,
        CacheControl,
        Cookie,
        Connection,
        ContentEncoding,
        ContentLanguage,
        ContentLength,
        ContentType,
        Date,
        ETag,
        Expect,
        Expires,
        From,
        Host,
        IfMatch,
        IfModifiedSince,
        IfNoneMatch,
        IfRange,
        IfUnmodifiedSince,
        LastModified,
        Location,
        Pragma,
        Referer,
        Server,
        SetCookie,
        TransferEncoding,
        Upgrade,
        UserAgent,
        Vary
    }
}
<|endoftext|>


<commit_before>//! The rule module provides two data structures, Rule and MultiRule, that implement the Operation trait.
//! Rule aims to be a drop-in for any algorithm in ai_kit that operates on the Operation trait.  It is useful when you have one possible result for an operation.
//! MultiRule aims to be a drop-in for any algorithm in ai_kit that operates on the Operation trait.  It is useful when you have multiple results for an operation.

use constraints::{Constraint, ConstraintValue};
use core::{Bindings, Operation, Unify};
use std;
use std::collections::HashMap;
use std::marker::PhantomData;
use utils;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Rule<T: ConstraintValue, U: Unify<T>> {
    #[serde(default)]
    pub constraints: Vec<Constraint>,
    #[serde(default = "Vec::default")]
    pub lhs: Vec<U>,
    pub rhs: U,
    #[serde(default)]
    pub _marker: PhantomData<T>,
}

impl<T, U> Operation<T, U> for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn input_patterns(&self) -> Vec<U> {
        self.lhs.clone()
    }

    fn apply_match(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        self.solve_constraints(&bindings).and_then(|bindings| {
            self.rhs
                .apply_bindings(&bindings)
                .and_then(|bound_rhs| Some(vec![bound_rhs]))
        })
    }

    fn r_apply_match(&self, fact: &U) -> Option<(Vec<U>, Bindings<T>)> {
        self.rhs
            .unify(fact, &Bindings::new())
            .and_then(|bindings| self.solve_constraints(&bindings))
            .and_then(|bindings| {
                utils::map_while_some(&mut self.lhs.iter(), &|f| {
                    f.apply_bindings(&bindings)
                }).and_then(|inputs| Some((inputs, bindings)))
            })
    }

    fn constraints<'a>(&'a self) -> Vec<&'a Constraint> {
        self.constraints.iter().collect()
    }

    /// Construct a new version of this rule but with all variables updated to be unique for this invocation
    fn snowflake(&self, suffix: String) -> Self {
        // Gather all variables
        let mut variables = self.rhs.variables();
        for lhs in self.lhs.iter() {
            variables.extend(lhs.variables());
        }
        for constraint in self.constraints.iter() {
            variables.extend(constraint.variables());
        }

        let renamed_variable: HashMap<String, String> = variables
            .into_iter()
            .map(|var| (var.clone(), format!("{}::{}", var, suffix)))
            .collect();

        let rhs = self.rhs.rename_variables(&renamed_variable);
        let lhs: Vec<U> = self.lhs
            .iter()
            .map(|lhs| lhs.rename_variables(&renamed_variable))
            .collect();
        let constraints: Vec<Constraint> = self.constraints
            .iter()
            .map(|constraint| constraint.rename_variables(&renamed_variable))
            .collect();

        Rule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }
}

impl<T, U> Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    pub fn new(lhs: Vec<U>, rhs: U, constraints: Vec<Constraint>) -> Self {
        Rule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }

    pub fn unify(&self, facts: &Vec<&U>, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        utils::fold_while_some(
            bindings.clone(),
            &mut self.lhs.iter().zip(facts.iter()),
            &|bindings, (t1, t2)| t1.unify(t2, &bindings),
        )
    }

    pub fn apply_bindings(&self, bindings: &Bindings<T>) -> Option<U> {
        self.rhs.apply_bindings(bindings)
    }

    fn solve_constraints(&self, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), bindings).ok()
    }

    pub fn pprint(&self) -> String {
        let lhs_string_vec: Vec<String> = self.lhs.iter().map(|o| format!("{}", o)).collect();
        let lhs_string = lhs_string_vec.join("\n\t\t");
        let constraints_string_vec: Vec<String> = self.constraints.iter().map(|o| format!("{}", o)).collect();
        let constraints_string = constraints_string_vec.join("\n");
        format!(
            "Rule {{\n\tlhs:\n\t\t{},\n\trhs: {},\n\tconstraints: {} }}",
            lhs_string, self.rhs, constraints_string
        )
    }
}

impl<T, U> std::fmt::Display for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

impl<T, U> Eq for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct MultiRule<T: ConstraintValue, U: Unify<T>> {
    #[serde(default)]
    pub constraints: Vec<Constraint>,
    #[serde(default = "Vec::default")]
    pub lhs: Vec<U>,
    pub rhs: Vec<U>,
    #[serde(default)]
    pub _marker: PhantomData<T>,
}

impl<T, U> Operation<T, U> for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn input_patterns(&self) -> Vec<U> {
        self.lhs.clone()
    }

    fn apply_match(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        self.solve_constraints(&bindings)
            .and_then(|bindings| self.apply_bindings(&bindings))
    }

    /// Note: MultiRule's implementation of r_apply_match will only return Some result if
    /// a consistent set of bindings can be used when unifying all of the rhs elements
    fn r_apply_match(&self, fact: &U) -> Option<(Vec<U>, Bindings<T>)> {
        utils::fold_while_some(
            (Vec::new(), Bindings::new()),
            &mut self.rhs.iter(),
            &|(mut bound_rhs, bindings), rhs| {
                let results = rhs.unify(fact, &bindings)
                    .and_then(|bindings| self.solve_constraints(&bindings))
                    .and_then(|bindings| {
                        utils::map_while_some(&mut self.lhs.iter(), &|f| {
                            f.apply_bindings(&bindings)
                        }).and_then(|inputs| Some((inputs, bindings)))
                    });
                if let Some((inputs, new_bindings)) = results {
                    bound_rhs.extend(inputs.into_iter());
                    Some((bound_rhs, new_bindings))
                } else {
                    None
                }
            },
        )
    }

    fn constraints<'a>(&'a self) -> Vec<&'a Constraint> {
        self.constraints.iter().collect()
    }

    /// Construct a new version of this rule but with all variables updated to be unique for this invocation
    fn snowflake(&self, suffix: String) -> Self {
        // Gather all variables
        let mut variables: Vec<String> = self.rhs.iter().flat_map(|rhs| rhs.variables()).collect();

        for lhs in self.lhs.iter() {
            variables.extend(lhs.variables());
        }
        for constraint in self.constraints.iter() {
            variables.extend(constraint.variables());
        }

        let renamed_variable: HashMap<String, String> = variables
            .into_iter()
            .map(|var| (var.clone(), format!("{}::{}", var, suffix)))
            .collect();

        let rhs: Vec<U> = self.rhs
            .iter()
            .map(|rhs| rhs.rename_variables(&renamed_variable))
            .collect();
        let lhs: Vec<U> = self.lhs
            .iter()
            .map(|lhs| lhs.rename_variables(&renamed_variable))
            .collect();
        let constraints: Vec<Constraint> = self.constraints
            .iter()
            .map(|constraint| constraint.rename_variables(&renamed_variable))
            .collect();

        MultiRule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }
}

impl<T, U> MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    pub fn new(lhs: Vec<U>, rhs: Vec<U>, constraints: Vec<Constraint>) -> Self {
        MultiRule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }

    pub fn unify(&self, facts: &Vec<&U>, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        utils::fold_while_some(
            bindings.clone(),
            &mut self.lhs.iter().zip(facts.iter()),
            &|bindings, (t1, t2)| t1.unify(t2, &bindings),
        )
    }

    pub fn apply_bindings(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        utils::map_while_some(&mut self.rhs.iter(), &|rhs| {
            rhs.apply_bindings(bindings)
        })
    }

    fn solve_constraints(&self, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), bindings).ok()
    }

    pub fn pprint(&self) -> String {
        let lhs_string: String = self.lhs
            .iter()
            .map(|o| format!("{}", o))
            .collect::<Vec<String>>()
            .join("\n\t\t");
        let rhs_string: String = self.rhs
            .iter()
            .map(|o| format!("{}", o))
            .collect::<Vec<String>>()
            .join("\n\t\t");

        let constraints_string_vec: Vec<String> = self.constraints.iter().map(|o| format!("{}", o)).collect();
        let constraints_string = constraints_string_vec.join("\n");

        format!(
            "MultiRule {{\n\tlhs:\n\t\t{},\n\trhs: {},\n\tconstraints: {} }}",
            lhs_string, rhs_string, constraints_string
        )
    }
}

impl<T, U> std::fmt::Display for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

impl<T, U> Eq for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
}

#[cfg(test)]
mod tests;
<commit_msg>Better display of Rule and MultiRule<commit_after>//! The rule module provides two data structures, Rule and MultiRule, that implement the Operation trait.
//! Rule aims to be a drop-in for any algorithm in ai_kit that operates on the Operation trait.  It is useful when you have one possible result for an operation.
//! MultiRule aims to be a drop-in for any algorithm in ai_kit that operates on the Operation trait.  It is useful when you have multiple results for an operation.

use constraints::{Constraint, ConstraintValue};
use core::{Bindings, Operation, Unify};
use std;
use std::collections::HashMap;
use std::marker::PhantomData;
use utils;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Rule<T: ConstraintValue, U: Unify<T>> {
    #[serde(default)]
    pub constraints: Vec<Constraint>,
    #[serde(default = "Vec::default")]
    pub lhs: Vec<U>,
    pub rhs: U,
    #[serde(default)]
    pub _marker: PhantomData<T>,
}

impl<T, U> Operation<T, U> for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn input_patterns(&self) -> Vec<U> {
        self.lhs.clone()
    }

    fn apply_match(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        self.solve_constraints(&bindings).and_then(|bindings| {
            self.rhs
                .apply_bindings(&bindings)
                .and_then(|bound_rhs| Some(vec![bound_rhs]))
        })
    }

    fn r_apply_match(&self, fact: &U) -> Option<(Vec<U>, Bindings<T>)> {
        self.rhs
            .unify(fact, &Bindings::new())
            .and_then(|bindings| self.solve_constraints(&bindings))
            .and_then(|bindings| {
                utils::map_while_some(&mut self.lhs.iter(), &|f| {
                    f.apply_bindings(&bindings)
                }).and_then(|inputs| Some((inputs, bindings)))
            })
    }

    fn constraints<'a>(&'a self) -> Vec<&'a Constraint> {
        self.constraints.iter().collect()
    }

    /// Construct a new version of this rule but with all variables updated to be unique for this invocation
    fn snowflake(&self, suffix: String) -> Self {
        // Gather all variables
        let mut variables = self.rhs.variables();
        for lhs in self.lhs.iter() {
            variables.extend(lhs.variables());
        }
        for constraint in self.constraints.iter() {
            variables.extend(constraint.variables());
        }

        let renamed_variable: HashMap<String, String> = variables
            .into_iter()
            .map(|var| (var.clone(), format!("{}::{}", var, suffix)))
            .collect();

        let rhs = self.rhs.rename_variables(&renamed_variable);
        let lhs: Vec<U> = self.lhs
            .iter()
            .map(|lhs| lhs.rename_variables(&renamed_variable))
            .collect();
        let constraints: Vec<Constraint> = self.constraints
            .iter()
            .map(|constraint| constraint.rename_variables(&renamed_variable))
            .collect();

        Rule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }
}

impl<T, U> Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    pub fn new(lhs: Vec<U>, rhs: U, constraints: Vec<Constraint>) -> Self {
        Rule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }

    pub fn unify(&self, facts: &Vec<&U>, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        utils::fold_while_some(
            bindings.clone(),
            &mut self.lhs.iter().zip(facts.iter()),
            &|bindings, (t1, t2)| t1.unify(t2, &bindings),
        )
    }

    pub fn apply_bindings(&self, bindings: &Bindings<T>) -> Option<U> {
        self.rhs.apply_bindings(bindings)
    }

    fn solve_constraints(&self, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), bindings).ok()
    }

    pub fn pprint(&self) -> String {
        let lhs_string_vec: Vec<String> = self.lhs.iter().map(|o| format!("{}", o)).collect();
        let lhs_string = lhs_string_vec.join("\n\t\t");
        let constraints_string_vec: Vec<String> = self.constraints.iter().map(|o| format!("{}", o)).collect();
        let constraints_string = constraints_string_vec.join("\n");
        format!(
            "Rule {{\n\tlhs:\n\t\t{},\n\trhs:\n\t\t{},\n\tconstraints:\n\t\t{} }}",
            lhs_string, self.rhs, constraints_string
        )
    }
}

impl<T, U> std::fmt::Display for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

impl<T, U> Eq for Rule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct MultiRule<T: ConstraintValue, U: Unify<T>> {
    #[serde(default)]
    pub constraints: Vec<Constraint>,
    #[serde(default = "Vec::default")]
    pub lhs: Vec<U>,
    pub rhs: Vec<U>,
    #[serde(default)]
    pub _marker: PhantomData<T>,
}

impl<T, U> Operation<T, U> for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn input_patterns(&self) -> Vec<U> {
        self.lhs.clone()
    }

    fn apply_match(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        self.solve_constraints(&bindings)
            .and_then(|bindings| self.apply_bindings(&bindings))
    }

    /// Note: MultiRule's implementation of r_apply_match will only return Some result if
    /// a consistent set of bindings can be used when unifying all of the rhs elements
    fn r_apply_match(&self, fact: &U) -> Option<(Vec<U>, Bindings<T>)> {
        utils::fold_while_some(
            (Vec::new(), Bindings::new()),
            &mut self.rhs.iter(),
            &|(mut bound_rhs, bindings), rhs| {
                let results = rhs.unify(fact, &bindings)
                    .and_then(|bindings| self.solve_constraints(&bindings))
                    .and_then(|bindings| {
                        utils::map_while_some(&mut self.lhs.iter(), &|f| {
                            f.apply_bindings(&bindings)
                        }).and_then(|inputs| Some((inputs, bindings)))
                    });
                if let Some((inputs, new_bindings)) = results {
                    bound_rhs.extend(inputs.into_iter());
                    Some((bound_rhs, new_bindings))
                } else {
                    None
                }
            },
        )
    }

    fn constraints<'a>(&'a self) -> Vec<&'a Constraint> {
        self.constraints.iter().collect()
    }

    /// Construct a new version of this rule but with all variables updated to be unique for this invocation
    fn snowflake(&self, suffix: String) -> Self {
        // Gather all variables
        let mut variables: Vec<String> = self.rhs.iter().flat_map(|rhs| rhs.variables()).collect();

        for lhs in self.lhs.iter() {
            variables.extend(lhs.variables());
        }
        for constraint in self.constraints.iter() {
            variables.extend(constraint.variables());
        }

        let renamed_variable: HashMap<String, String> = variables
            .into_iter()
            .map(|var| (var.clone(), format!("{}::{}", var, suffix)))
            .collect();

        let rhs: Vec<U> = self.rhs
            .iter()
            .map(|rhs| rhs.rename_variables(&renamed_variable))
            .collect();
        let lhs: Vec<U> = self.lhs
            .iter()
            .map(|lhs| lhs.rename_variables(&renamed_variable))
            .collect();
        let constraints: Vec<Constraint> = self.constraints
            .iter()
            .map(|constraint| constraint.rename_variables(&renamed_variable))
            .collect();

        MultiRule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }
}

impl<T, U> MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    pub fn new(lhs: Vec<U>, rhs: Vec<U>, constraints: Vec<Constraint>) -> Self {
        MultiRule {
            constraints: constraints,
            lhs: lhs,
            rhs: rhs,
            _marker: PhantomData,
        }
    }

    pub fn unify(&self, facts: &Vec<&U>, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        utils::fold_while_some(
            bindings.clone(),
            &mut self.lhs.iter().zip(facts.iter()),
            &|bindings, (t1, t2)| t1.unify(t2, &bindings),
        )
    }

    pub fn apply_bindings(&self, bindings: &Bindings<T>) -> Option<Vec<U>> {
        utils::map_while_some(&mut self.rhs.iter(), &|rhs| {
            rhs.apply_bindings(bindings)
        })
    }

    fn solve_constraints(&self, bindings: &Bindings<T>) -> Option<Bindings<T>> {
        Constraint::solve_many(self.constraints.iter().collect(), bindings).ok()
    }

    pub fn pprint(&self) -> String {
        let lhs_string: String = self.lhs
            .iter()
            .map(|o| format!("{}", o))
            .collect::<Vec<String>>()
            .join("\n\t\t");
        let rhs_string: String = self.rhs
            .iter()
            .map(|o| format!("{}", o))
            .collect::<Vec<String>>()
            .join("\n\t\t");

        let constraints_string_vec: Vec<String> = self.constraints.iter().map(|o| format!("{}", o)).collect();
        let constraints_string = constraints_string_vec.join("\n");

        format!(
            "MultiRule {{\n\tlhs:\n\t\t{},\n\trhs:\n\t\t{},\n\tconstraints:\n\t\t{} }}",
            lhs_string, rhs_string, constraints_string
        )
    }
}

impl<T, U> std::fmt::Display for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.pprint())
    }
}

impl<T, U> Eq for MultiRule<T, U>
where
    T: ConstraintValue,
    U: Unify<T>,
{
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! Sink points into a las file.

use std::collections::HashMap;
use std::path::Path;

use las;

use Result;
use error::Error;
use point::{Point, ScanDirection};
use sink::{FileSink, Sink};

impl<P: AsRef<Path>> Sink for las::Writer<P> {
    fn sink(&mut self, point: Point) -> Result<()> {
        self.write_point(try!(from_point(point)));
        Ok(())
    }
}

fn from_point(point: Point) -> Result<las::Point> {
    Ok(las::Point {
        x: point.x,
        y: point.y,
        z: point.z,
        intensity: point.intensity.as_u16(),
        return_number: try!(las::point::ReturnNumber::from_u8(point.return_number.unwrap_or(0) as u8)),
        number_of_returns: try!(las::point::NumberOfReturns::from_u8(point.number_of_returns.unwrap_or(0) as u8)),
        scan_direction: match point.scan_direction {
            ScanDirection::Forward | ScanDirection::Unknown => las::point::ScanDirection::Forward,
            ScanDirection::Backward => las::point::ScanDirection::Backward
        },
        edge_of_flight_line: point.edge_of_flight_line,
        classification: try!(las::point::Classification::from_u8(point.classification)),
        synthetic: point.synthetic,
        key_point: point.key_point,
        withheld: point.withheld,
        scan_angle_rank: point.scan_angle.unwrap_or(0.0) as i8,
        user_data: point.user_data.unwrap_or(0),
        point_source_id: point.point_source_id.unwrap_or(0),
        gps_time: point.gps_time,
        // FIXME these should be properties too
        red: None,
        green: None,
        blue: None,
        extra_bytes: None,
    })
}

impl<P: 'static + AsRef<Path>> FileSink<P> for las::Writer<P> {
    fn open_file_sink(path: P, options: HashMap<String, String>) -> Result<Box<FileSink<P>>> {
        let mut writer = las::Writer::from_path(path);
        for (key, val) in options.iter() {
            match key.to_lowercase().as_ref() {
                "scale-factors" | "scaling" => {
                    let factors: Vec<_> = val.split(|c| c == ' ' || c == ',').collect();
                    if factors.len() != 3 {
                        return Err(Error::InvalidOption(format!("Incorrect number of scale \
                                                                 factors provided, wanted 3 \
                                                                 but got {}",
                                                                factors.len())));
                    }
                    writer = writer.scale_factors(try!(factors[0].parse()),
                                                  try!(factors[1].parse()),
                                                  try!(factors[2].parse()));
                }
                _ => {
                    return Err(Error::InvalidOption(format!("The las sink does not know how to \
                                                             handle this option: {}",
                                                            key)))
                }
            }
        }

        Ok(Box::new(writer))
    }

    fn close_file_sink(&mut self) -> Result<()> {
        self.close().map_err(|e| Error::from(e))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::fs::remove_file;

    use las;

    use sink::{open_file_sink, FileSink, Sink};
    use source::{open_file_source, Source};

    #[test]
    fn read_write_las() {
        let mut source = las::Stream::from_path("data/1.0_0.las").unwrap();
        let mut sink = las::Writer::from_path("read_write_las.las");
        for point in source.source_to_end(100).unwrap() {
            sink.sink(point).unwrap()
        }
        sink.close().unwrap();

        let mut source = las::Stream::from_path("read_write_las.las").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("read_write_las.las").unwrap();
    }

    #[test]
    fn source_and_sink() {
        let mut source = open_file_source("data/1.0_0.las", HashMap::new()).unwrap();
        let mut sink = open_file_sink("source_and_sink.las", HashMap::new()).unwrap();
        for point in source.source_to_end(100).unwrap() {
            sink.sink(point).unwrap();
        }
        sink.close_file_sink().unwrap();

        let mut source = las::Stream::from_path("source_and_sink.las").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("source_and_sink.las").unwrap();
    }
}
<commit_msg>Add auto offsets option to las sink<commit_after>//! Sink points into a las file.

use std::collections::HashMap;
use std::path::Path;

use las;

use Result;
use error::Error;
use point::{Point, ScanDirection};
use sink::{FileSink, Sink};

impl<P: AsRef<Path>> Sink for las::Writer<P> {
    fn sink(&mut self, point: Point) -> Result<()> {
        self.write_point(try!(from_point(point)));
        Ok(())
    }
}

fn from_point(point: Point) -> Result<las::Point> {
    Ok(las::Point {
        x: point.x,
        y: point.y,
        z: point.z,
        intensity: point.intensity.as_u16(),
        return_number: try!(las::point::ReturnNumber::from_u8(point.return_number.unwrap_or(0) as u8)),
        number_of_returns: try!(las::point::NumberOfReturns::from_u8(point.number_of_returns.unwrap_or(0) as u8)),
        scan_direction: match point.scan_direction {
            ScanDirection::Forward | ScanDirection::Unknown => las::point::ScanDirection::Forward,
            ScanDirection::Backward => las::point::ScanDirection::Backward
        },
        edge_of_flight_line: point.edge_of_flight_line,
        classification: try!(las::point::Classification::from_u8(point.classification)),
        synthetic: point.synthetic,
        key_point: point.key_point,
        withheld: point.withheld,
        scan_angle_rank: point.scan_angle.unwrap_or(0.0) as i8,
        user_data: point.user_data.unwrap_or(0),
        point_source_id: point.point_source_id.unwrap_or(0),
        gps_time: point.gps_time,
        // FIXME these should be properties too
        red: None,
        green: None,
        blue: None,
        extra_bytes: None,
    })
}

impl<P: 'static + AsRef<Path>> FileSink<P> for las::Writer<P> {
    fn open_file_sink(path: P, options: HashMap<String, String>) -> Result<Box<FileSink<P>>> {
        let mut writer = las::Writer::from_path(path);
        for (key, val) in options.iter() {
            match key.to_lowercase().as_ref() {
                "scale-factors" | "scaling" => {
                    let factors: Vec<_> = val.split(|c| c == ' ' || c == ',').collect();
                    if factors.len() != 3 {
                        return Err(Error::InvalidOption(format!("Incorrect number of scale \
                                                                 factors provided, wanted 3 \
                                                                 but got {}",
                                                                factors.len())));
                    }
                    writer = writer.scale_factors(try!(factors[0].parse()),
                                                  try!(factors[1].parse()),
                                                  try!(factors[2].parse()));
                }
                "auto-offset" | "auto-offsets" => writer = writer.auto_offsets(try!(val.parse())),
                _ => {
                    return Err(Error::InvalidOption(format!("The las sink does not know how to \
                                                             handle this option: {}",
                                                            key)))
                }
            }
        }

        Ok(Box::new(writer))
    }

    fn close_file_sink(&mut self) -> Result<()> {
        self.close().map_err(|e| Error::from(e))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::fs::remove_file;

    use las;

    use sink::{open_file_sink, FileSink, Sink};
    use source::{open_file_source, Source};

    #[test]
    fn read_write_las() {
        let mut source = las::Stream::from_path("data/1.0_0.las").unwrap();
        let mut sink = las::Writer::from_path("read_write_las.las");
        for point in source.source_to_end(100).unwrap() {
            sink.sink(point).unwrap()
        }
        sink.close().unwrap();

        let mut source = las::Stream::from_path("read_write_las.las").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("read_write_las.las").unwrap();
    }

    #[test]
    fn source_and_sink() {
        let mut source = open_file_source("data/1.0_0.las", HashMap::new()).unwrap();
        let mut sink = open_file_sink("source_and_sink.las", HashMap::new()).unwrap();
        for point in source.source_to_end(100).unwrap() {
            sink.sink(point).unwrap();
        }
        sink.close_file_sink().unwrap();

        let mut source = las::Stream::from_path("source_and_sink.las").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("source_and_sink.las").unwrap();
    }
}
<|endoftext|>