<commit_before>use handlebars::Handlebars;

use hyper::{Control, Decoder, Encoder, Next};
use hyper::HttpVersion::{Http09, Http10, Http11};

use hyper::error::Error as HyperError;
use hyper::header::{ContentLength, Encoding, TransferEncoding};
use hyper::method::Method::{Connect, Delete, Get, Head, Trace};
use hyper::net::HttpStream;
use hyper::server::{Handler, Request as HttpRequest, Response as HttpResponse};
use hyper::status::StatusCode as Status;

use scoped_pool::Scope;

use url::Url;

use buffer::Buffer;
use request::{self, Request};
use response::ResponseHolder;
use router::{Callback, RouterAny};

/// a handler that lasts only the time of a request
/// scope outlives handler
pub struct EdgeHandler<'handler, 'scope: 'handler> {
    scope: &'handler Scope<'scope>,
    base_url: &'handler Url,
    routers: &'scope [RouterAny],
    request: Option<Request>,
    is_head_request: bool,
    buffer: Option<Buffer>,
    holder: ResponseHolder<'scope>
}

impl<'handler, 'scope> EdgeHandler<'handler, 'scope> {
    pub fn new(scope: &'handler Scope<'scope>, base_url: &'handler Url, routers: &'scope [RouterAny], handlebars: &'scope Handlebars, control: Control) -> EdgeHandler<'handler, 'scope> {
        EdgeHandler {
            scope: scope,
            base_url: base_url,
            routers: routers,
            request: None,
            is_head_request: false,
            buffer: None,
            holder: ResponseHolder::new(handlebars, control)
        }
    }

    fn callback(&mut self) -> Next {
        let mut req = self.request.take().unwrap();

        let result = self.routers.iter().filter_map(|router|
            if let Some(callback) = router.find_callback(&mut req) {
                Some((router, callback))
            } else {
                None
            }
        ).next();

        if let Some((router, callback)) = result {
            let mut boxed_app = router.new_instance();
            let response = self.holder.new_response();

            // add job to scoped pool
            self.scope.execute(move || {
                router.run_middleware(boxed_app.as_mut(), &mut req);

                match *callback {
                    Callback::Instance(ref f) => f(boxed_app.as_mut(), &req, response),
                    Callback::Static(ref f) => f(&req, response)
                }
            });

            // and wait for it to notify us
            Next::wait()
        } else {
            //warn!("route not found for path {:?}", req.path());
            let mut res = self.holder.new_response();
            res.status(Status::NotFound);
            res.content_type("text/plain");
            //res.send(format!("not found: {:?}", req.path()));
            Next::write()
        }
    }

    fn bad_request(&mut self, message: &str) -> Next {
        error!("Bad Request: {}", message);

        let mut res = self.holder.new_response();
        res.status(Status::BadRequest).content_type("text/plain; charset=UTF-8");
        res.send(message);
        Next::write()
    }

}

/// Implements Handler for our EdgeHandler.
impl<'handler, 'scope> Handler<HttpStream> for EdgeHandler<'handler, 'scope> {
    fn on_request(&mut self, req: HttpRequest) -> Next {
        debug!("on_request");

        match request::new(&self.base_url, req) {
            Ok(req) => {
                let result = check_request(&req, &mut self.buffer);
                self.is_head_request = *req.method() == Head;
                self.request = Some(req);

                match result {
                    Err(msg) => self.bad_request(msg),
                    Ok(false) => self.callback(),
                    Ok(true) => Next::read()
                }
            }
            Err(error) => {
                self.bad_request(&error.to_string())
            }
        }
    }

    fn on_request_readable(&mut self, transport: &mut Decoder<HttpStream>) -> Next {
        debug!("on_request_readable");

        // we can only get here if self.buffer = Some(...), or there is a bug
        {
            let body = self.buffer.as_mut().unwrap();
            if let Ok(keep_reading) = body.read_from(transport) {
                if keep_reading {
                    return Next::read();
                }
            }
        }

        // move body to the request
        request::set_body(self.request.as_mut(), self.buffer.take());
        self.callback()
    }

    fn on_response(&mut self, res: &mut HttpResponse) -> Next {
        debug!("on_response");

        // we got here from callback directly or Resp notified the Control
        let status = self.holder.get_status();

        // set status and headers
        res.set_status(status);
        self.holder.set_headers(res.headers_mut());

        // 3.3.2 Content-Length
        // http://httpwg.org/specs/rfc7230.html#header.content-length
        //
        // A server MUST NOT send a Content-Length header field in any response
        // with a status code of 1xx (Informational) or 204 (No Content).
        //
        // A server MAY send a Content-Length header field in a response to a HEAD request
        // A server MAY send a Content-Length header field in a 304 (Not Modified) response
        if status.is_informational() ||
            status == Status::NoContent || status == Status::NotModified ||
            self.is_head_request {
            // we remove any ContentLength header in those cases
            // even in 304 and response to HEAD
            // because we cannot guarantee that the length is the same
            res.headers_mut().remove::<ContentLength>();
            return Next::end();
        }

        if !self.holder.body().is_empty() {
            debug!("has body");
            Next::write()
        } else if self.holder.is_streaming() {
            debug!("streaming mode, waiting");
            Next::wait()
        } else {
            debug!("has no body, ending");
            Next::end()
        }
    }

    fn on_response_writable(&mut self, transport: &mut Encoder<HttpStream>) -> Next {
        debug!("on_response_writable");

        if self.holder.is_streaming() {
            if self.buffer.is_none() {
                self.buffer = self.holder.pop();
            }

            if self.buffer.is_none() {
                // no buffer available yet
                Next::wait()
            } else {
                let empty = self.buffer.as_mut().unwrap().is_empty();
                if empty {
                    // an empty body means no more data to write
                    debug!("done writing");
                    Next::end()
                } else {
                    let result = self.buffer.as_mut().unwrap().write_to(transport);
                    if let Ok(keep_writing) = result {
                        if keep_writing {
                            Next::write()
                        } else {
                            // done writing this buffer, try to get another one
                            self.buffer = None;
                            Next::write()
                        }
                    } else {
                        Next::remove()
                    }
                }
            }
        } else {
            if let Ok(keep_writing) = self.holder.body().write_to(transport) {
                if keep_writing {
                    Next::write()
                } else {
                    Next::end()
                }
            } else {
                Next::remove()
            }
        }
    }

    fn on_error(&mut self, err: HyperError) -> Next {
        debug!("on_error {:?}", err);
        Next::remove()
    }

    fn on_remove(self, _transport: HttpStream) {
        debug!("on_remove");
    }
}

fn check_request(req: &Request, buffer: &mut Option<Buffer>) -> ::std::result::Result<bool, &'static str> {
    let headers = req.headers();
    let http1x = { let version = req.version(); *version == Http09 || *version == Http10 || *version == Http11 };

    // RFC 7230 Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
    // 3.3.3 Message Body Length
    // http://httpwg.org/specs/rfc7230.html#message.body.length
    //
    let len =
        if let Some(&TransferEncoding(ref codings)) = headers.get() {
            if codings.last() != Some(&Encoding::Chunked) {
                // 3. If a Transfer-Encoding header field is present in a request and
                // the chunked transfer coding is not the final encoding,
                // the message body length cannot be determined reliably;
                // the server MUST respond with the 400 (Bad Request) status code
                // and then close the connection.
                return Err("Last encoding of Transfer-Encoding must be chunked")
            }

            // Transfer-Encoding is correct, we have a payload
            None
        } else if let Some(&ContentLength(len)) = headers.get() {
            // 5. If a valid Content-Length header field is present without Transfer-Encoding,
            // its decimal value defines the expected message body length in octets.
            if len == 0 {
                info!("Request with empty payload Content-Length: 0");
                return Ok(false);
            }

            Some(len as usize)
        } else if headers.has::<ContentLength>() {
            // 4. If a message is received without Transfer-Encoding
            // and with either multiple Content-Length header fields having
            // differing field-values or a single Content-Length header field
            // having an invalid value, then the message framing is invalid
            // and the recipient MUST treat it as an unrecoverable error.
            // If this is a request message, the server MUST respond with
            // a 400 (Bad Request) status code and then close the connection.
            return Err("Invalid Content-Length header");
        } else if http1x {
            // If this is a request message and none of the above are true,
            // then the message body length is zero (no message body is present).
            return Ok(false);
        } else {
            // in HTTP/2 a request message can have a body even if
            // no Transfer-Encoding or Content-Length headers are present
            None
        };

    // RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
    // 4.3 Method Definitions
    // http://httpwg.org/specs/rfc7231.html#method.definitions
    //
    // A payload within a GET/HEAD/DELETE/CONNECT request message has no defined
    // semantics; sending a payload body on a GET/HEAD/DELETE/CONNECT request
    // might cause some existing implementations to reject the request.
    let method = req.method();
    if *method == Get || *method == Head || *method == Delete || *method == Connect {
        // payload in these methods has no defined semantics
        if http1x {
            // warns only for HTTP/1.x-compatible
            // because we cannot know for sure whether there is a payload in HTTP/2
            warn!("Ignoring payload for {} request", *method);
        }

        Ok(false)
    } else if *method == Trace {
        Err("A client MUST NOT send a message body in a TRACE request.")
    } else {
        // payload is allowed
        // if Content-Length is known create buffer with fixed size, otherwise allocate growable buffer
        *buffer = Some(len.map_or(Buffer::new(), |len| Buffer::new_fixed(len)));
        Ok(true)
    }
}
<commit_msg>run middleware on callback only, not on static resources<commit_after>use handlebars::Handlebars;

use hyper::{Control, Decoder, Encoder, Next};
use hyper::HttpVersion::{Http09, Http10, Http11};

use hyper::error::Error as HyperError;
use hyper::header::{ContentLength, Encoding, TransferEncoding};
use hyper::method::Method::{Connect, Delete, Get, Head, Trace};
use hyper::net::HttpStream;
use hyper::server::{Handler, Request as HttpRequest, Response as HttpResponse};
use hyper::status::StatusCode as Status;

use scoped_pool::Scope;

use url::Url;

use buffer::Buffer;
use request::{self, Request};
use response::ResponseHolder;
use router::{Callback, RouterAny};

/// a handler that lasts only the time of a request
/// scope outlives handler
pub struct EdgeHandler<'handler, 'scope: 'handler> {
    scope: &'handler Scope<'scope>,
    base_url: &'handler Url,
    routers: &'scope [RouterAny],
    request: Option<Request>,
    is_head_request: bool,
    buffer: Option<Buffer>,
    holder: ResponseHolder<'scope>
}

impl<'handler, 'scope> EdgeHandler<'handler, 'scope> {
    pub fn new(scope: &'handler Scope<'scope>, base_url: &'handler Url, routers: &'scope [RouterAny], handlebars: &'scope Handlebars, control: Control) -> EdgeHandler<'handler, 'scope> {
        EdgeHandler {
            scope: scope,
            base_url: base_url,
            routers: routers,
            request: None,
            is_head_request: false,
            buffer: None,
            holder: ResponseHolder::new(handlebars, control)
        }
    }

    fn callback(&mut self) -> Next {
        let mut req = self.request.take().unwrap();

        let result = self.routers.iter().filter_map(|router|
            if let Some(callback) = router.find_callback(&mut req) {
                Some((router, callback))
            } else {
                None
            }
        ).next();

        if let Some((router, callback)) = result {
            let mut boxed_app = router.new_instance();
            let response = self.holder.new_response();

            // add job to scoped pool
            self.scope.execute(move || {
                match *callback {
                    Callback::Instance(ref f) => {
                        router.run_middleware(boxed_app.as_mut(), &mut req);
                        f(boxed_app.as_mut(), &req, response)
                    }
                    Callback::Static(ref f) => f(&req, response)
                }
            });

            // and wait for it to notify us
            Next::wait()
        } else {
            //warn!("route not found for path {:?}", req.path());
            let mut res = self.holder.new_response();
            res.status(Status::NotFound);
            res.content_type("text/plain");
            //res.send(format!("not found: {:?}", req.path()));
            Next::write()
        }
    }

    fn bad_request(&mut self, message: &str) -> Next {
        error!("Bad Request: {}", message);

        let mut res = self.holder.new_response();
        res.status(Status::BadRequest).content_type("text/plain; charset=UTF-8");
        res.send(message);
        Next::write()
    }

}

/// Implements Handler for our EdgeHandler.
impl<'handler, 'scope> Handler<HttpStream> for EdgeHandler<'handler, 'scope> {
    fn on_request(&mut self, req: HttpRequest) -> Next {
        debug!("on_request");

        match request::new(&self.base_url, req) {
            Ok(req) => {
                let result = check_request(&req, &mut self.buffer);
                self.is_head_request = *req.method() == Head;
                self.request = Some(req);

                match result {
                    Err(msg) => self.bad_request(msg),
                    Ok(false) => self.callback(),
                    Ok(true) => Next::read()
                }
            }
            Err(error) => {
                self.bad_request(&error.to_string())
            }
        }
    }

    fn on_request_readable(&mut self, transport: &mut Decoder<HttpStream>) -> Next {
        debug!("on_request_readable");

        // we can only get here if self.buffer = Some(...), or there is a bug
        {
            let body = self.buffer.as_mut().unwrap();
            if let Ok(keep_reading) = body.read_from(transport) {
                if keep_reading {
                    return Next::read();
                }
            }
        }

        // move body to the request
        request::set_body(self.request.as_mut(), self.buffer.take());
        self.callback()
    }

    fn on_response(&mut self, res: &mut HttpResponse) -> Next {
        debug!("on_response");

        // we got here from callback directly or Resp notified the Control
        let status = self.holder.get_status();

        // set status and headers
        res.set_status(status);
        self.holder.set_headers(res.headers_mut());

        // 3.3.2 Content-Length
        // http://httpwg.org/specs/rfc7230.html#header.content-length
        //
        // A server MUST NOT send a Content-Length header field in any response
        // with a status code of 1xx (Informational) or 204 (No Content).
        //
        // A server MAY send a Content-Length header field in a response to a HEAD request
        // A server MAY send a Content-Length header field in a 304 (Not Modified) response
        if status.is_informational() ||
            status == Status::NoContent || status == Status::NotModified ||
            self.is_head_request {
            // we remove any ContentLength header in those cases
            // even in 304 and response to HEAD
            // because we cannot guarantee that the length is the same
            res.headers_mut().remove::<ContentLength>();
            return Next::end();
        }

        if !self.holder.body().is_empty() {
            debug!("has body");
            Next::write()
        } else if self.holder.is_streaming() {
            debug!("streaming mode, waiting");
            Next::wait()
        } else {
            debug!("has no body, ending");
            Next::end()
        }
    }

    fn on_response_writable(&mut self, transport: &mut Encoder<HttpStream>) -> Next {
        debug!("on_response_writable");

        if self.holder.is_streaming() {
            if self.buffer.is_none() {
                self.buffer = self.holder.pop();
            }

            if self.buffer.is_none() {
                // no buffer available yet
                Next::wait()
            } else {
                let empty = self.buffer.as_mut().unwrap().is_empty();
                if empty {
                    // an empty body means no more data to write
                    debug!("done writing");
                    Next::end()
                } else {
                    let result = self.buffer.as_mut().unwrap().write_to(transport);
                    if let Ok(keep_writing) = result {
                        if keep_writing {
                            Next::write()
                        } else {
                            // done writing this buffer, try to get another one
                            self.buffer = None;
                            Next::write()
                        }
                    } else {
                        Next::remove()
                    }
                }
            }
        } else {
            if let Ok(keep_writing) = self.holder.body().write_to(transport) {
                if keep_writing {
                    Next::write()
                } else {
                    Next::end()
                }
            } else {
                Next::remove()
            }
        }
    }

    fn on_error(&mut self, err: HyperError) -> Next {
        debug!("on_error {:?}", err);
        Next::remove()
    }

    fn on_remove(self, _transport: HttpStream) {
        debug!("on_remove");
    }
}

fn check_request(req: &Request, buffer: &mut Option<Buffer>) -> ::std::result::Result<bool, &'static str> {
    let headers = req.headers();
    let http1x = { let version = req.version(); *version == Http09 || *version == Http10 || *version == Http11 };

    // RFC 7230 Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
    // 3.3.3 Message Body Length
    // http://httpwg.org/specs/rfc7230.html#message.body.length
    //
    let len =
        if let Some(&TransferEncoding(ref codings)) = headers.get() {
            if codings.last() != Some(&Encoding::Chunked) {
                // 3. If a Transfer-Encoding header field is present in a request and
                // the chunked transfer coding is not the final encoding,
                // the message body length cannot be determined reliably;
                // the server MUST respond with the 400 (Bad Request) status code
                // and then close the connection.
                return Err("Last encoding of Transfer-Encoding must be chunked")
            }

            // Transfer-Encoding is correct, we have a payload
            None
        } else if let Some(&ContentLength(len)) = headers.get() {
            // 5. If a valid Content-Length header field is present without Transfer-Encoding,
            // its decimal value defines the expected message body length in octets.
            if len == 0 {
                info!("Request with empty payload Content-Length: 0");
                return Ok(false);
            }

            Some(len as usize)
        } else if headers.has::<ContentLength>() {
            // 4. If a message is received without Transfer-Encoding
            // and with either multiple Content-Length header fields having
            // differing field-values or a single Content-Length header field
            // having an invalid value, then the message framing is invalid
            // and the recipient MUST treat it as an unrecoverable error.
            // If this is a request message, the server MUST respond with
            // a 400 (Bad Request) status code and then close the connection.
            return Err("Invalid Content-Length header");
        } else if http1x {
            // If this is a request message and none of the above are true,
            // then the message body length is zero (no message body is present).
            return Ok(false);
        } else {
            // in HTTP/2 a request message can have a body even if
            // no Transfer-Encoding or Content-Length headers are present
            None
        };

    // RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
    // 4.3 Method Definitions
    // http://httpwg.org/specs/rfc7231.html#method.definitions
    //
    // A payload within a GET/HEAD/DELETE/CONNECT request message has no defined
    // semantics; sending a payload body on a GET/HEAD/DELETE/CONNECT request
    // might cause some existing implementations to reject the request.
    let method = req.method();
    if *method == Get || *method == Head || *method == Delete || *method == Connect {
        // payload in these methods has no defined semantics
        if http1x {
            // warns only for HTTP/1.x-compatible
            // because we cannot know for sure whether there is a payload in HTTP/2
            warn!("Ignoring payload for {} request", *method);
        }

        Ok(false)
    } else if *method == Trace {
        Err("A client MUST NOT send a message body in a TRACE request.")
    } else {
        // payload is allowed
        // if Content-Length is known create buffer with fixed size, otherwise allocate growable buffer
        *buffer = Some(len.map_or(Buffer::new(), |len| Buffer::new_fixed(len)));
        Ok(true)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! High level Hat API

use process::{Process};

use blob_index::{BlobIndex, BlobIndexProcess};
use blob_store::{BlobStore, BlobStoreBackend};

use hash_index::{HashIndex, HashIndexProcess};
use hash_store::{HashStore};
use hash_tree;

use key_index::{KeyIndex, KeyEntry};

use key_store::{KeyStore, KeyStoreProcess};
use key_store;

use listdir;

use std::io;
use std::io::{Reader, IoResult, UserDir,
              TypeDirectory, TypeSymlink, TypeFile, FileStat};
use std::io::fs::{lstat, File, mkdir_recursive};
use std::sync;

use time;

pub struct Hat<'db, B> {
  repository_root: Path,
  blob_index: BlobIndexProcess,
  hash_index: HashIndexProcess<'db>,

  backend: B,
  max_blob_size: uint,
}

fn concat_filename(a: &Path, b: String) -> String {
  let mut result = a.clone();
  result.push(Path::new(b));
  result.as_str().expect("Unable to decode repository_root.").to_string()
}

fn blob_index_name(root: &Path) -> String {
  concat_filename(root, "blob_index.sqlite3".to_string())
}

fn hash_index_name(root: &Path) -> String {
  concat_filename(root, "hash_index.sqlite3".to_string())
}

impl <'db, B: BlobStoreBackend + Clone + Send> Hat<'db, B> {
  pub fn open_repository(repository_root: &Path, backend: B, max_blob_size: uint)
                        -> Option<Hat<'db, B>> {
    repository_root.as_str().map(|_| {
      let blob_index_path = blob_index_name(repository_root);
      let hash_index_path = hash_index_name(repository_root);
      let biP = Process::new(proc() { BlobIndex::new(blob_index_path) });
      let hiP = Process::new(proc() { HashIndex::new(hash_index_path) });
      Hat{repository_root: repository_root.clone(),
                hash_index: hiP,
                blob_index: biP,
                backend: backend.clone(),
                max_blob_size: max_blob_size,
      }
    })
  }

  pub fn open_family(&self, name: String) -> Option<Family<'db, B>> {
    // We setup a standard pipeline of processes:
    // KeyStore -> KeyIndex
    //          -> HashStore -> HashIndex
    //                       -> BlobStore -> BlobIndex

    let local_blob_index = self.blob_index.clone();
    let local_backend = self.backend.clone();
    let local_max_blob_size = self.max_blob_size;
    let bsP = Process::new(proc() {
      BlobStore::new(local_blob_index, local_backend, local_max_blob_size) });

    let local_hash_index = self.hash_index.clone();
    let hsP = Process::new(proc() { HashStore::new(local_hash_index, bsP) });

    let key_index_path = concat_filename(&self.repository_root, name.clone());
    let kiP = Process::new(proc() { KeyIndex::new(key_index_path) });
    let ksP = Process::new(proc() { KeyStore::new(kiP, hsP) });

    Some(Family{name: name,
                key_store: ksP})
  }
}

struct FileEntry {
  name: Vec<u8>,

  parent_id: Option<Vec<u8>>,

  stat: FileStat,
  full_path: Path,
}

impl FileEntry {
  fn new(full_path: Path,
         parent: Option<Vec<u8>>) -> Result<FileEntry, io::IoError> {
    let filename_opt = full_path.filename();
    if filename_opt.is_some() {
      lstat(&full_path).map(|st| {
        FileEntry{
          name: filename_opt.unwrap().into_owned(),
          parent_id: parent.clone(),
          stat: st,
          full_path: full_path.clone()}
      })
    }
    else { Err(io::IoError{kind: io::OtherIoError,
                           desc: "Could not parse filename.",
                           detail: None }) }
  }

  fn file_iterator(&self) -> IoResult<FileIterator> {
    FileIterator::new(&self.full_path)
  }

  fn is_directory(&self) -> bool { self.stat.kind == TypeDirectory }
  fn is_symlink(&self) -> bool { self.stat.kind == TypeSymlink }
  fn is_file(&self) -> bool { self.stat.kind == TypeFile }
}

impl Clone for FileEntry {
  fn clone(&self) -> FileEntry {
    FileEntry{
      name:self.name.clone(), parent_id:self.parent_id.clone(),
      stat: FileStat{
        size: self.stat.size,
        kind: self.stat.kind,
        perm: self.stat.perm,
        created: self.stat.created,
        modified: self.stat.modified,
        accessed: self.stat.accessed,
        unstable: self.stat.unstable,
      },
      full_path:self.full_path.clone()}
  }
}

impl KeyEntry<FileEntry> for FileEntry {
  fn name(&self) -> Vec<u8> {
    self.name.clone()
  }
  fn id(&self) -> Option<Vec<u8>> {
    Some(format!("d{:u}i{:u}",
                 self.stat.unstable.device,
                 self.stat.unstable.inode).as_bytes().into_owned())
  }
  fn parent_id(&self) -> Option<Vec<u8>> {
    self.parent_id.clone()
  }

  fn size(&self) -> Option<u64> {
    Some(self.stat.size)
  }

  fn created(&self) -> Option<u64> {
    Some(self.stat.created)
  }
  fn modified(&self) -> Option<u64> {
    Some(self.stat.modified)
  }
  fn accessed(&self) -> Option<u64> {
    Some(self.stat.accessed)
  }

  fn permissions(&self) -> Option<u64> {
    None
  }
  fn user_id(&self) -> Option<u64> {
    None
  }
  fn group_id(&self) -> Option<u64> {
    None
  }
  fn with_id(&self, id: Vec<u8>) -> FileEntry {
    assert_eq!(Some(id), self.id());
    self.clone()
  }
}

struct FileIterator {
  file: File
}

impl FileIterator {
  fn new(path: &Path) -> IoResult<FileIterator> {
    match File::open(path) {
      Ok(f) => Ok(FileIterator{file: f}),
      Err(e) => Err(e),
    }
  }
}

impl Iterator<Vec<u8>> for FileIterator {
  fn next(&mut self) -> Option<Vec<u8>> {
    let mut buf = Vec::from_elem(128*1024, 0u8);
    match self.file.read(buf.as_mut_slice()) {
      Err(_) => None,
      Ok(size) => Some(buf.slice_to(size).into_owned()),
    }
  }
}

#[deriving(Clone)]
struct InsertPathHandler<'db, B> {
  count: sync::Arc<sync::Mutex<uint>>,
  last_print: sync::Arc<sync::Mutex<time::Timespec>>,
  my_last_print: time::Timespec,

  key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>,
}

impl <'db, B> InsertPathHandler<'db, B> {
  pub fn new(key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>)
             -> InsertPathHandler<'db, B> {
    InsertPathHandler{
      count: sync::Arc::new(sync::Mutex::new(0)),
      last_print: sync::Arc::new(sync::Mutex::new(time::now().to_timespec())),
      my_last_print: time::now().to_timespec(),
      key_store: key_store,
    }
  }
}

impl <'db, B: BlobStoreBackend + Clone> listdir::PathHandler<Option<Vec<u8>>>
  for InsertPathHandler<'db, B> {
  fn handle_path(&mut self, parent: Option<Vec<u8>>, path: Path) -> Option<Option<Vec<u8>>> {
    let mut count = {
      let mut guarded_count = self.count.lock();
      *guarded_count += 1;
      *guarded_count
    };

    if self.my_last_print.sec <= time::now().to_timespec().sec - 1 {
      let mut guarded_last_print = self.last_print.lock();
      let now = time::now().to_timespec();
      if guarded_last_print.sec <= now.sec - 1 {
        println!("#{}: {}", count, path.display());
        *guarded_last_print = now;
      }
      self.my_last_print = now;
    }

    let fileEntry_opt = FileEntry::new(path.clone(), parent);
    match fileEntry_opt {
      Err(e) => {
        println!("Skipping '{}': {}", path.display(), e.to_str());
      },
      Ok(fileEntry) => {
        if fileEntry.is_symlink() {
          return None;
        }
        let is_directory = fileEntry.is_directory();
        let local_root = path;
        let local_fileEntry = fileEntry.clone();
        let create_file_it = proc() {
          match local_fileEntry.file_iterator() {
            Err(e) => {println!("Skipping '{}': {}", local_root.display(), e.to_str());
                       None},
            Ok(it) => { Some(it) }
          }
        };
        let create_file_it_opt = if is_directory { None }
                                 else { Some(create_file_it) };

        match self.key_store.send_reply(
          key_store::Insert(fileEntry, create_file_it_opt))
        {
          key_store::Id(id) => {
            if is_directory { return Some(Some(id)) }
          },
          _ => fail!("Unexpected reply from key store."),
        }
      }
    }

    return None;
  }
}

struct Family<'db, B> {
  name: String,
  key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>,
}

impl <'db, B: BlobStoreBackend + Clone> Family<'db, B> {

  pub fn snapshot_dir(&self, dir: Path) {
    let mut handler = InsertPathHandler::new(self.key_store.clone());
    listdir::iterate_recursively((Path::new(dir.clone()), None), &mut handler);
  }

  pub fn flush(&self) {
    self.key_store.send_reply(key_store::Flush);
  }

  pub fn checkout_in_dir(&self, output_dir: &mut Path, dir_id: Option<Vec<u8>>) {

    fn put_chunks<B: hash_tree::HashTreeBackend + Clone>(
      fd: &mut File, tree: hash_tree::ReaderResult<B>)
    {
      let mut it = match tree {
        hash_tree::NoData => fail!("Trying to read data where none exist."),
        hash_tree::SingleBlock(chunk) => {
          fd.write(chunk.as_slice()).unwrap();
          return;
        },
        hash_tree::Tree(it) => it,
      };
      // We have a tree
      for chunk in it {
        fd.write(chunk.as_slice()).unwrap();
      }
    }

    // create output_dir
    mkdir_recursive(output_dir, UserDir).unwrap();

    let listing = match self.key_store.send_reply(key_store::ListDir(dir_id)) {
      key_store::ListResult(ls) => ls,
      _ => fail!("Unexpected result from key store."),
    };

    for (id, name, _, _, _, hash, _, data_res) in listing.move_iter() {

      output_dir.push(name);

      if hash.len() == 0 {
        // This is a directory, recurse!
        self.checkout_in_dir(output_dir, Some(id));
      } else {
        // This is a file, write it
        let mut fd = File::create(output_dir).unwrap();
        put_chunks(&mut fd, data_res);
        fd.flush();
      }

      output_dir.pop();
    }

  }
}
<commit_msg>Kill a warning about ignored result of flush().<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! High level Hat API

use process::{Process};

use blob_index::{BlobIndex, BlobIndexProcess};
use blob_store::{BlobStore, BlobStoreBackend};

use hash_index::{HashIndex, HashIndexProcess};
use hash_store::{HashStore};
use hash_tree;

use key_index::{KeyIndex, KeyEntry};

use key_store::{KeyStore, KeyStoreProcess};
use key_store;

use listdir;

use std::io;
use std::io::{Reader, IoResult, UserDir,
              TypeDirectory, TypeSymlink, TypeFile, FileStat};
use std::io::fs::{lstat, File, mkdir_recursive};
use std::sync;

use time;

pub struct Hat<'db, B> {
  repository_root: Path,
  blob_index: BlobIndexProcess,
  hash_index: HashIndexProcess<'db>,

  backend: B,
  max_blob_size: uint,
}

fn concat_filename(a: &Path, b: String) -> String {
  let mut result = a.clone();
  result.push(Path::new(b));
  result.as_str().expect("Unable to decode repository_root.").to_string()
}

fn blob_index_name(root: &Path) -> String {
  concat_filename(root, "blob_index.sqlite3".to_string())
}

fn hash_index_name(root: &Path) -> String {
  concat_filename(root, "hash_index.sqlite3".to_string())
}

impl <'db, B: BlobStoreBackend + Clone + Send> Hat<'db, B> {
  pub fn open_repository(repository_root: &Path, backend: B, max_blob_size: uint)
                        -> Option<Hat<'db, B>> {
    repository_root.as_str().map(|_| {
      let blob_index_path = blob_index_name(repository_root);
      let hash_index_path = hash_index_name(repository_root);
      let biP = Process::new(proc() { BlobIndex::new(blob_index_path) });
      let hiP = Process::new(proc() { HashIndex::new(hash_index_path) });
      Hat{repository_root: repository_root.clone(),
                hash_index: hiP,
                blob_index: biP,
                backend: backend.clone(),
                max_blob_size: max_blob_size,
      }
    })
  }

  pub fn open_family(&self, name: String) -> Option<Family<'db, B>> {
    // We setup a standard pipeline of processes:
    // KeyStore -> KeyIndex
    //          -> HashStore -> HashIndex
    //                       -> BlobStore -> BlobIndex

    let local_blob_index = self.blob_index.clone();
    let local_backend = self.backend.clone();
    let local_max_blob_size = self.max_blob_size;
    let bsP = Process::new(proc() {
      BlobStore::new(local_blob_index, local_backend, local_max_blob_size) });

    let local_hash_index = self.hash_index.clone();
    let hsP = Process::new(proc() { HashStore::new(local_hash_index, bsP) });

    let key_index_path = concat_filename(&self.repository_root, name.clone());
    let kiP = Process::new(proc() { KeyIndex::new(key_index_path) });
    let ksP = Process::new(proc() { KeyStore::new(kiP, hsP) });

    Some(Family{name: name,
                key_store: ksP})
  }
}

struct FileEntry {
  name: Vec<u8>,

  parent_id: Option<Vec<u8>>,

  stat: FileStat,
  full_path: Path,
}

impl FileEntry {
  fn new(full_path: Path,
         parent: Option<Vec<u8>>) -> Result<FileEntry, io::IoError> {
    let filename_opt = full_path.filename();
    if filename_opt.is_some() {
      lstat(&full_path).map(|st| {
        FileEntry{
          name: filename_opt.unwrap().into_owned(),
          parent_id: parent.clone(),
          stat: st,
          full_path: full_path.clone()}
      })
    }
    else { Err(io::IoError{kind: io::OtherIoError,
                           desc: "Could not parse filename.",
                           detail: None }) }
  }

  fn file_iterator(&self) -> IoResult<FileIterator> {
    FileIterator::new(&self.full_path)
  }

  fn is_directory(&self) -> bool { self.stat.kind == TypeDirectory }
  fn is_symlink(&self) -> bool { self.stat.kind == TypeSymlink }
  fn is_file(&self) -> bool { self.stat.kind == TypeFile }
}

impl Clone for FileEntry {
  fn clone(&self) -> FileEntry {
    FileEntry{
      name:self.name.clone(), parent_id:self.parent_id.clone(),
      stat: FileStat{
        size: self.stat.size,
        kind: self.stat.kind,
        perm: self.stat.perm,
        created: self.stat.created,
        modified: self.stat.modified,
        accessed: self.stat.accessed,
        unstable: self.stat.unstable,
      },
      full_path:self.full_path.clone()}
  }
}

impl KeyEntry<FileEntry> for FileEntry {
  fn name(&self) -> Vec<u8> {
    self.name.clone()
  }
  fn id(&self) -> Option<Vec<u8>> {
    Some(format!("d{:u}i{:u}",
                 self.stat.unstable.device,
                 self.stat.unstable.inode).as_bytes().into_owned())
  }
  fn parent_id(&self) -> Option<Vec<u8>> {
    self.parent_id.clone()
  }

  fn size(&self) -> Option<u64> {
    Some(self.stat.size)
  }

  fn created(&self) -> Option<u64> {
    Some(self.stat.created)
  }
  fn modified(&self) -> Option<u64> {
    Some(self.stat.modified)
  }
  fn accessed(&self) -> Option<u64> {
    Some(self.stat.accessed)
  }

  fn permissions(&self) -> Option<u64> {
    None
  }
  fn user_id(&self) -> Option<u64> {
    None
  }
  fn group_id(&self) -> Option<u64> {
    None
  }
  fn with_id(&self, id: Vec<u8>) -> FileEntry {
    assert_eq!(Some(id), self.id());
    self.clone()
  }
}

struct FileIterator {
  file: File
}

impl FileIterator {
  fn new(path: &Path) -> IoResult<FileIterator> {
    match File::open(path) {
      Ok(f) => Ok(FileIterator{file: f}),
      Err(e) => Err(e),
    }
  }
}

impl Iterator<Vec<u8>> for FileIterator {
  fn next(&mut self) -> Option<Vec<u8>> {
    let mut buf = Vec::from_elem(128*1024, 0u8);
    match self.file.read(buf.as_mut_slice()) {
      Err(_) => None,
      Ok(size) => Some(buf.slice_to(size).into_owned()),
    }
  }
}

#[deriving(Clone)]
struct InsertPathHandler<'db, B> {
  count: sync::Arc<sync::Mutex<uint>>,
  last_print: sync::Arc<sync::Mutex<time::Timespec>>,
  my_last_print: time::Timespec,

  key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>,
}

impl <'db, B> InsertPathHandler<'db, B> {
  pub fn new(key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>)
             -> InsertPathHandler<'db, B> {
    InsertPathHandler{
      count: sync::Arc::new(sync::Mutex::new(0)),
      last_print: sync::Arc::new(sync::Mutex::new(time::now().to_timespec())),
      my_last_print: time::now().to_timespec(),
      key_store: key_store,
    }
  }
}

impl <'db, B: BlobStoreBackend + Clone> listdir::PathHandler<Option<Vec<u8>>>
  for InsertPathHandler<'db, B> {
  fn handle_path(&mut self, parent: Option<Vec<u8>>, path: Path) -> Option<Option<Vec<u8>>> {
    let count = {
      let mut guarded_count = self.count.lock();
      *guarded_count += 1;
      *guarded_count
    };

    if self.my_last_print.sec <= time::now().to_timespec().sec - 1 {
      let mut guarded_last_print = self.last_print.lock();
      let now = time::now().to_timespec();
      if guarded_last_print.sec <= now.sec - 1 {
        println!("#{}: {}", count, path.display());
        *guarded_last_print = now;
      }
      self.my_last_print = now;
    }

    let fileEntry_opt = FileEntry::new(path.clone(), parent);
    match fileEntry_opt {
      Err(e) => {
        println!("Skipping '{}': {}", path.display(), e.to_str());
      },
      Ok(fileEntry) => {
        if fileEntry.is_symlink() {
          return None;
        }
        let is_directory = fileEntry.is_directory();
        let local_root = path;
        let local_fileEntry = fileEntry.clone();
        let create_file_it = proc() {
          match local_fileEntry.file_iterator() {
            Err(e) => {println!("Skipping '{}': {}", local_root.display(), e.to_str());
                       None},
            Ok(it) => { Some(it) }
          }
        };
        let create_file_it_opt = if is_directory { None }
                                 else { Some(create_file_it) };

        match self.key_store.send_reply(
          key_store::Insert(fileEntry, create_file_it_opt))
        {
          key_store::Id(id) => {
            if is_directory { return Some(Some(id)) }
          },
          _ => fail!("Unexpected reply from key store."),
        }
      }
    }

    return None;
  }
}

fn try_a_few_times_then_fail(f: || -> bool, msg: &str) {
  for i in range(1u, 5) {
    if f() { return }
  }
  fail!(msg.to_string());
}

struct Family<'db, B> {
  name: String,
  key_store: KeyStoreProcess<'db, FileEntry, FileIterator, B>,
}

impl <'db, B: BlobStoreBackend + Clone> Family<'db, B> {

  pub fn snapshot_dir(&self, dir: Path) {
    let mut handler = InsertPathHandler::new(self.key_store.clone());
    listdir::iterate_recursively((Path::new(dir.clone()), None), &mut handler);
  }

  pub fn flush(&self) {
    self.key_store.send_reply(key_store::Flush);
  }

  pub fn checkout_in_dir(&self, output_dir: &mut Path, dir_id: Option<Vec<u8>>) {

    fn put_chunks<B: hash_tree::HashTreeBackend + Clone>(
      fd: &mut File, tree: hash_tree::ReaderResult<B>)
    {
      let mut it = match tree {
        hash_tree::NoData => fail!("Trying to read data where none exist."),
        hash_tree::SingleBlock(chunk) => {
          try_a_few_times_then_fail(|| fd.write(chunk.as_slice()).is_ok(),
                                    "Could not write chunk.");
          return;
        },
        hash_tree::Tree(it) => it,
      };
      // We have a tree
      for chunk in it {
        try_a_few_times_then_fail(|| fd.write(chunk.as_slice()).is_ok(), "Could not write chunk.");
      }
    }

    // create output_dir
    mkdir_recursive(output_dir, UserDir).unwrap();

    let listing = match self.key_store.send_reply(key_store::ListDir(dir_id)) {
      key_store::ListResult(ls) => ls,
      _ => fail!("Unexpected result from key store."),
    };

    for (id, name, _, _, _, hash, _, data_res) in listing.move_iter() {

      output_dir.push(name);

      if hash.len() == 0 {
        // This is a directory, recurse!
        self.checkout_in_dir(output_dir, Some(id));
      } else {
        // This is a file, write it
        let mut fd = File::create(output_dir).unwrap();
        put_chunks(&mut fd, data_res);
        try_a_few_times_then_fail(|| fd.flush().is_ok(), "Could not flush file.")
      }

      output_dir.pop();
    }

  }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::fmt;
use std::path::Path;

use git;

#[derive(Debug, Clone)]
pub struct Entry<'a> { name: &'a str, time: &'a str, comment: &'a str, commit: &'a str, }

impl<'a> fmt::Display for Entry<'a> {
    fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Entry: {} {} {}: {}", self.commit, self.time, self.name, self.comment)
    }
}

impl<'a> Entry<'a> {
    pub fn new(name: &'a str, time: &'a str, comment: &'a str, commit: &'a str) -> Entry<'a> {
        Entry { name:name, time: time, comment: comment, commit : commit }
    }

    pub fn name(&self) -> &str { self.name }
    pub fn time(&self) -> &str { self.time }
    pub fn comment(&self) -> &str { self.comment }
    pub fn commit(&self) -> &str { self.commit }
}

pub struct History<'a> {
    cwd: &'a Path,
}

const GIT_ONE_LINE_DETAILS : [&'static str;2] = ["log", "--pretty=format:'%h|%an|%cr|%s'"];

impl<'a> History<'a> {

    pub fn new(cwd: &Path) -> History { History{ cwd : cwd } }

    pub fn len(&self) -> i32 {
        let mut args: Vec<&str> = GIT_ONE_LINE_DETAILS.to_vec();
        args.push(" | wc -l");

        git::exec_git(self.cwd, &args[ .. ]);

        -1
    }
}
<commit_msg>Move log arguments to History struct, as const<commit_after>use std::fmt;
use std::path::Path;

use git;

#[derive(Debug, Clone)]
pub struct Entry<'a> { name: &'a str, time: &'a str, comment: &'a str, commit: &'a str, }

impl<'a> fmt::Display for Entry<'a> {
    fn fmt(& self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Entry: {} {} {}: {}", self.commit, self.time, self.name, self.comment)
    }
}

impl<'a> Entry<'a> {
    pub fn new(name: &'a str, time: &'a str, comment: &'a str, commit: &'a str) -> Entry<'a> {
        Entry { name:name, time: time, comment: comment, commit : commit }
    }

    pub fn name(&self) -> &str { self.name }
    pub fn time(&self) -> &str { self.time }
    pub fn comment(&self) -> &str { self.comment }
    pub fn commit(&self) -> &str { self.commit }
}

pub struct History<'a> {
    cwd: &'a Path,
}

impl<'a> History<'a> {
    const GIT_ONE_LINE_DETAILS : [&'static str;2] = ["log", "--pretty=format:'%h|%an|%cr|%s'"];

    pub fn new(cwd: &Path) -> History { History{ cwd : cwd } }

    pub fn len(&self) -> i32 {
        let mut args: Vec<&str> = History::GIT_ONE_LINE_DETAILS.to_vec();
        args.push(" | wc -l");

        git::exec_git(self.cwd, &args[ .. ]);

        -1
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Brian Langenberger
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits and implementations for reading or writing Huffman codes
//! from or to a stream.

#![warn(missing_docs)]

use super::BitQueue;
use super::Endianness;
use std::collections::BTreeMap;
use std::fmt;
use std::marker::PhantomData;

/// A compiled Huffman tree element for use with the `read_huffman` method.
/// Returned by `compile_read_tree`.
///
/// Compiled read trees are optimized for faster lookup
/// and are therefore endian-specific.
///
/// In addition, each symbol in the source tree may occur many times
/// in the compiled tree.  If symbols require a nontrivial amount of space,
/// consider using reference counting so that they may be cloned
/// more efficiently.
pub enum ReadHuffmanTree<E: Endianness, T: Clone> {
    /// The final value and new reader state
    Done(T, u8, u32, PhantomData<E>),
    /// Another byte is necessary to determine final value
    Continue(Box<[ReadHuffmanTree<E, T>]>),
    /// An invalid reader state has been used
    InvalidState,
}

/// Given a vector of symbol/code pairs, compiles a Huffman tree
/// for reading.
///
/// Code must be 0 or 1 bits and are always read from the stream
/// from least-significant in the list to most signficant
/// (which makes them easier to read for humans).
///
/// All possible codes must be assigned some symbol,
/// and it is acceptable for the same symbol to occur multiple times.
///
/// ## Examples
/// ```
/// use bitstream_io::huffman::compile_read_tree;
/// use bitstream_io::BigEndian;
/// assert!(compile_read_tree::<BigEndian,i32>(
///     vec![(1, vec![0]),
///          (2, vec![1, 0]),
///          (3, vec![1, 1])]).is_ok());
/// ```
///
/// ```
/// use std::io::{Read, Cursor};
/// use bitstream_io::{BigEndian, BitReader, HuffmanRead};
/// use bitstream_io::huffman::compile_read_tree;
/// let tree = compile_read_tree(
///     vec![('a', vec![0]),
///          ('b', vec![1, 0]),
///          ('c', vec![1, 1, 0]),
///          ('d', vec![1, 1, 1])]).unwrap();
/// let data = [0b10110111];
/// let mut cursor = Cursor::new(&data);
/// let mut reader = BitReader::endian(&mut cursor, BigEndian);
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'b');
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'c');
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'd');
/// ```
pub fn compile_read_tree<E, T>(
    values: Vec<(T, Vec<u8>)>,
) -> Result<Box<[ReadHuffmanTree<E, T>]>, HuffmanTreeError>
where
    E: Endianness,
    T: Clone,
{
    let tree = FinalHuffmanTree::new(values)?;

    let mut result = Vec::with_capacity(256);
    result.extend((0..256).map(|_| ReadHuffmanTree::InvalidState));
    let queue = BitQueue::from_value(0, 0);
    let i = queue.to_state();
    result[i] = compile_queue(queue, &tree);
    for bits in 1..8 {
        for value in 0..(1 << bits) {
            let queue = BitQueue::from_value(value, bits);
            let i = queue.to_state();
            result[i] = compile_queue(queue, &tree);
        }
    }
    assert_eq!(result.len(), 256);
    Ok(result.into_boxed_slice())
}

fn compile_queue<E, T>(
    mut queue: BitQueue<E, u8>,
    tree: &FinalHuffmanTree<T>,
) -> ReadHuffmanTree<E, T>
where
    E: Endianness,
    T: Clone,
{
    match tree {
        FinalHuffmanTree::Leaf(ref value) => {
            let len = queue.len();
            ReadHuffmanTree::Done(value.clone(), queue.value(), len, PhantomData)
        }
        FinalHuffmanTree::Tree(ref bit0, ref bit1) => {
            if queue.is_empty() {
                ReadHuffmanTree::Continue(
                    (0..256)
                        .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), &tree))
                        .collect::<Vec<ReadHuffmanTree<E, T>>>()
                        .into_boxed_slice(),
                )
            } else if queue.pop(1) == 0 {
                compile_queue(queue, bit0)
            } else {
                compile_queue(queue, bit1)
            }
        }
    }
}

// A complete Huffman tree with no empty nodes
enum FinalHuffmanTree<T: Clone> {
    Leaf(T),
    Tree(Box<FinalHuffmanTree<T>>, Box<FinalHuffmanTree<T>>),
}

impl<T: Clone> FinalHuffmanTree<T> {
    fn new(values: Vec<(T, Vec<u8>)>) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> {
        let mut tree = WipHuffmanTree::new_empty();

        for (symbol, code) in values {
            tree.add(code.as_slice(), symbol)?;
        }

        tree.into_read_tree()
    }
}

// Work-in-progress trees may have empty nodes during construction
// but those are not allowed in a finalized tree.
// If the user wants some codes to be None or an error symbol of some sort,
// those will need to be specified explicitly.
enum WipHuffmanTree<T: Clone> {
    Empty,
    Leaf(T),
    Tree(Box<WipHuffmanTree<T>>, Box<WipHuffmanTree<T>>),
}

impl<T: Clone> WipHuffmanTree<T> {
    fn new_empty() -> WipHuffmanTree<T> {
        WipHuffmanTree::Empty
    }

    fn new_leaf(value: T) -> WipHuffmanTree<T> {
        WipHuffmanTree::Leaf(value)
    }

    fn new_tree() -> WipHuffmanTree<T> {
        WipHuffmanTree::Tree(Box::new(Self::new_empty()), Box::new(Self::new_empty()))
    }

    fn into_read_tree(self) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> {
        match self {
            WipHuffmanTree::Empty => Err(HuffmanTreeError::MissingLeaf),
            WipHuffmanTree::Leaf(v) => Ok(FinalHuffmanTree::Leaf(v)),
            WipHuffmanTree::Tree(zero, one) => {
                let zero = zero.into_read_tree()?;
                let one = one.into_read_tree()?;
                Ok(FinalHuffmanTree::Tree(Box::new(zero), Box::new(one)))
            }
        }
    }

    fn add(&mut self, code: &[u8], symbol: T) -> Result<(), HuffmanTreeError> {
        match self {
            WipHuffmanTree::Empty => {
                if code.is_empty() {
                    *self = WipHuffmanTree::new_leaf(symbol);
                    Ok(())
                } else {
                    *self = WipHuffmanTree::new_tree();
                    self.add(code, symbol)
                }
            }
            WipHuffmanTree::Leaf(_) => Err(if code.is_empty() {
                HuffmanTreeError::DuplicateLeaf
            } else {
                HuffmanTreeError::OrphanedLeaf
            }),
            WipHuffmanTree::Tree(ref mut zero, ref mut one) => {
                if code.is_empty() {
                    Err(HuffmanTreeError::DuplicateLeaf)
                } else {
                    match code[0] {
                        0 => zero.add(&code[1..], symbol),
                        1 => one.add(&code[1..], symbol),
                        _ => Err(HuffmanTreeError::InvalidBit),
                    }
                }
            }
        }
    }
}

/// An error type during Huffman tree compilation.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum HuffmanTreeError {
    /// One of the bits in a Huffman code is not 0 or 1
    InvalidBit,
    /// A Huffman code in the specification has no defined symbol
    MissingLeaf,
    /// The same Huffman code specifies multiple symbols
    DuplicateLeaf,
    /// A Huffman code is the prefix of some longer code
    OrphanedLeaf,
}

impl fmt::Display for HuffmanTreeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HuffmanTreeError::InvalidBit => write!(f, "invalid bit in code"),
            HuffmanTreeError::MissingLeaf => write!(f, "missing leaf node in specification"),
            HuffmanTreeError::DuplicateLeaf => write!(f, "duplicate leaf node in specification"),
            HuffmanTreeError::OrphanedLeaf => write!(f, "orphaned leaf node in specification"),
        }
    }
}

/// Given a vector of symbol/code pairs, compiles a Huffman tree
/// for writing.
///
/// Code must be 0 or 1 bits and are always written to the stream
/// from least-significant in the list to most signficant
/// (which makes them easier to read for humans).
///
/// If the same symbol occurs multiple times, the first code is used.
/// Unlike in read trees, not all possible codes need to be
/// assigned a symbol.
///
/// ## Examples
/// ```
/// use bitstream_io::huffman::compile_write_tree;
/// use bitstream_io::BigEndian;
/// assert!(compile_write_tree::<BigEndian,i32>(
///     vec![(1, vec![0]),
///          (2, vec![1, 0]),
///          (3, vec![1, 1])]).is_ok());
/// ```
///
/// ```
/// use std::io::Write;
/// use bitstream_io::{BigEndian, BitWriter, HuffmanWrite};
/// use bitstream_io::huffman::compile_write_tree;
/// let tree = compile_write_tree(
///     vec![('a', vec![0]),
///          ('b', vec![1, 0]),
///          ('c', vec![1, 1, 0]),
///          ('d', vec![1, 1, 1])]).unwrap();
/// let mut data = Vec::new();
/// {
///     let mut writer = BitWriter::endian(&mut data, BigEndian);
///     writer.write_huffman(&tree, 'b').unwrap();
///     writer.write_huffman(&tree, 'c').unwrap();
///     writer.write_huffman(&tree, 'd').unwrap();
/// }
/// assert_eq!(data, [0b10110111]);
/// ```
pub fn compile_write_tree<E, T>(
    values: Vec<(T, Vec<u8>)>,
) -> Result<WriteHuffmanTree<E, T>, HuffmanTreeError>
where
    E: Endianness,
    T: Ord + Clone,
{
    let mut map = BTreeMap::new();

    for (symbol, code) in values {
        let mut encoded = Vec::new();
        for bits in code.chunks(32) {
            let mut acc = BitQueue::<E, u32>::new();
            for bit in bits {
                match *bit {
                    0 => acc.push(1, 0),
                    1 => acc.push(1, 1),
                    _ => return Err(HuffmanTreeError::InvalidBit),
                }
            }
            let len = acc.len();
            encoded.push((len, acc.value()))
        }
        map.entry(symbol)
            .or_insert_with(|| encoded.into_boxed_slice());
    }

    Ok(WriteHuffmanTree {
        map,
        phantom: PhantomData,
    })
}

/// A compiled Huffman tree for use with the `write_huffman` method.
/// Returned by `compiled_write_tree`.
pub struct WriteHuffmanTree<E: Endianness, T: Ord> {
    map: BTreeMap<T, Box<[(u32, u32)]>>,
    phantom: PhantomData<E>,
}

impl<E: Endianness, T: Ord + Clone> WriteHuffmanTree<E, T> {
    /// Returns true if symbol is in tree.
    #[inline]
    pub fn has_symbol(&self, symbol: &T) -> bool {
        self.map.contains_key(symbol)
    }

    /// Given symbol, returns iterator of
    /// (bits, value) pairs for writing code.
    /// Panics if symbol is not found.
    #[inline]
    pub fn get(&self, symbol: &T) -> impl Iterator<Item = &(u32, u32)> {
        self.map[symbol].iter()
    }
}
<commit_msg>Minor formatting fix<commit_after>// Copyright 2017 Brian Langenberger
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits and implementations for reading or writing Huffman codes
//! from or to a stream.

#![warn(missing_docs)]

use super::BitQueue;
use super::Endianness;
use std::collections::BTreeMap;
use std::fmt;
use std::marker::PhantomData;

/// A compiled Huffman tree element for use with the `read_huffman` method.
/// Returned by `compile_read_tree`.
///
/// Compiled read trees are optimized for faster lookup
/// and are therefore endian-specific.
///
/// In addition, each symbol in the source tree may occur many times
/// in the compiled tree.  If symbols require a nontrivial amount of space,
/// consider using reference counting so that they may be cloned
/// more efficiently.
pub enum ReadHuffmanTree<E: Endianness, T: Clone> {
    /// The final value and new reader state
    Done(T, u8, u32, PhantomData<E>),
    /// Another byte is necessary to determine final value
    Continue(Box<[ReadHuffmanTree<E, T>]>),
    /// An invalid reader state has been used
    InvalidState,
}

/// Given a vector of symbol/code pairs, compiles a Huffman tree
/// for reading.
///
/// Code must be 0 or 1 bits and are always read from the stream
/// from least-significant in the list to most signficant
/// (which makes them easier to read for humans).
///
/// All possible codes must be assigned some symbol,
/// and it is acceptable for the same symbol to occur multiple times.
///
/// ## Examples
/// ```
/// use bitstream_io::huffman::compile_read_tree;
/// use bitstream_io::BigEndian;
/// assert!(compile_read_tree::<BigEndian,i32>(
///     vec![(1, vec![0]),
///          (2, vec![1, 0]),
///          (3, vec![1, 1])]).is_ok());
/// ```
///
/// ```
/// use std::io::{Read, Cursor};
/// use bitstream_io::{BigEndian, BitReader, HuffmanRead};
/// use bitstream_io::huffman::compile_read_tree;
/// let tree = compile_read_tree(
///     vec![('a', vec![0]),
///          ('b', vec![1, 0]),
///          ('c', vec![1, 1, 0]),
///          ('d', vec![1, 1, 1])]).unwrap();
/// let data = [0b10110111];
/// let mut cursor = Cursor::new(&data);
/// let mut reader = BitReader::endian(&mut cursor, BigEndian);
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'b');
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'c');
/// assert_eq!(reader.read_huffman(&tree).unwrap(), 'd');
/// ```
pub fn compile_read_tree<E, T>(
    values: Vec<(T, Vec<u8>)>,
) -> Result<Box<[ReadHuffmanTree<E, T>]>, HuffmanTreeError>
where
    E: Endianness,
    T: Clone,
{
    let tree = FinalHuffmanTree::new(values)?;

    let mut result = Vec::with_capacity(256);
    result.extend((0..256).map(|_| ReadHuffmanTree::InvalidState));
    let queue = BitQueue::from_value(0, 0);
    let i = queue.to_state();
    result[i] = compile_queue(queue, &tree);
    for bits in 1..8 {
        for value in 0..(1 << bits) {
            let queue = BitQueue::from_value(value, bits);
            let i = queue.to_state();
            result[i] = compile_queue(queue, &tree);
        }
    }
    assert_eq!(result.len(), 256);
    Ok(result.into_boxed_slice())
}

fn compile_queue<E, T>(
    mut queue: BitQueue<E, u8>,
    tree: &FinalHuffmanTree<T>,
) -> ReadHuffmanTree<E, T>
where
    E: Endianness,
    T: Clone,
{
    match tree {
        FinalHuffmanTree::Leaf(ref value) => {
            let len = queue.len();
            ReadHuffmanTree::Done(value.clone(), queue.value(), len, PhantomData)
        }
        FinalHuffmanTree::Tree(ref bit0, ref bit1) => {
            if queue.is_empty() {
                ReadHuffmanTree::Continue(
                    (0..256)
                        .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree))
                        .collect::<Vec<ReadHuffmanTree<E, T>>>()
                        .into_boxed_slice(),
                )
            } else if queue.pop(1) == 0 {
                compile_queue(queue, bit0)
            } else {
                compile_queue(queue, bit1)
            }
        }
    }
}

// A complete Huffman tree with no empty nodes
enum FinalHuffmanTree<T: Clone> {
    Leaf(T),
    Tree(Box<FinalHuffmanTree<T>>, Box<FinalHuffmanTree<T>>),
}

impl<T: Clone> FinalHuffmanTree<T> {
    fn new(values: Vec<(T, Vec<u8>)>) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> {
        let mut tree = WipHuffmanTree::new_empty();

        for (symbol, code) in values {
            tree.add(code.as_slice(), symbol)?;
        }

        tree.into_read_tree()
    }
}

// Work-in-progress trees may have empty nodes during construction
// but those are not allowed in a finalized tree.
// If the user wants some codes to be None or an error symbol of some sort,
// those will need to be specified explicitly.
enum WipHuffmanTree<T: Clone> {
    Empty,
    Leaf(T),
    Tree(Box<WipHuffmanTree<T>>, Box<WipHuffmanTree<T>>),
}

impl<T: Clone> WipHuffmanTree<T> {
    fn new_empty() -> WipHuffmanTree<T> {
        WipHuffmanTree::Empty
    }

    fn new_leaf(value: T) -> WipHuffmanTree<T> {
        WipHuffmanTree::Leaf(value)
    }

    fn new_tree() -> WipHuffmanTree<T> {
        WipHuffmanTree::Tree(Box::new(Self::new_empty()), Box::new(Self::new_empty()))
    }

    fn into_read_tree(self) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> {
        match self {
            WipHuffmanTree::Empty => Err(HuffmanTreeError::MissingLeaf),
            WipHuffmanTree::Leaf(v) => Ok(FinalHuffmanTree::Leaf(v)),
            WipHuffmanTree::Tree(zero, one) => {
                let zero = zero.into_read_tree()?;
                let one = one.into_read_tree()?;
                Ok(FinalHuffmanTree::Tree(Box::new(zero), Box::new(one)))
            }
        }
    }

    fn add(&mut self, code: &[u8], symbol: T) -> Result<(), HuffmanTreeError> {
        match self {
            WipHuffmanTree::Empty => {
                if code.is_empty() {
                    *self = WipHuffmanTree::new_leaf(symbol);
                    Ok(())
                } else {
                    *self = WipHuffmanTree::new_tree();
                    self.add(code, symbol)
                }
            }
            WipHuffmanTree::Leaf(_) => Err(if code.is_empty() {
                HuffmanTreeError::DuplicateLeaf
            } else {
                HuffmanTreeError::OrphanedLeaf
            }),
            WipHuffmanTree::Tree(ref mut zero, ref mut one) => {
                if code.is_empty() {
                    Err(HuffmanTreeError::DuplicateLeaf)
                } else {
                    match code[0] {
                        0 => zero.add(&code[1..], symbol),
                        1 => one.add(&code[1..], symbol),
                        _ => Err(HuffmanTreeError::InvalidBit),
                    }
                }
            }
        }
    }
}

/// An error type during Huffman tree compilation.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum HuffmanTreeError {
    /// One of the bits in a Huffman code is not 0 or 1
    InvalidBit,
    /// A Huffman code in the specification has no defined symbol
    MissingLeaf,
    /// The same Huffman code specifies multiple symbols
    DuplicateLeaf,
    /// A Huffman code is the prefix of some longer code
    OrphanedLeaf,
}

impl fmt::Display for HuffmanTreeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HuffmanTreeError::InvalidBit => write!(f, "invalid bit in code"),
            HuffmanTreeError::MissingLeaf => write!(f, "missing leaf node in specification"),
            HuffmanTreeError::DuplicateLeaf => write!(f, "duplicate leaf node in specification"),
            HuffmanTreeError::OrphanedLeaf => write!(f, "orphaned leaf node in specification"),
        }
    }
}

/// Given a vector of symbol/code pairs, compiles a Huffman tree
/// for writing.
///
/// Code must be 0 or 1 bits and are always written to the stream
/// from least-significant in the list to most signficant
/// (which makes them easier to read for humans).
///
/// If the same symbol occurs multiple times, the first code is used.
/// Unlike in read trees, not all possible codes need to be
/// assigned a symbol.
///
/// ## Examples
/// ```
/// use bitstream_io::huffman::compile_write_tree;
/// use bitstream_io::BigEndian;
/// assert!(compile_write_tree::<BigEndian,i32>(
///     vec![(1, vec![0]),
///          (2, vec![1, 0]),
///          (3, vec![1, 1])]).is_ok());
/// ```
///
/// ```
/// use std::io::Write;
/// use bitstream_io::{BigEndian, BitWriter, HuffmanWrite};
/// use bitstream_io::huffman::compile_write_tree;
/// let tree = compile_write_tree(
///     vec![('a', vec![0]),
///          ('b', vec![1, 0]),
///          ('c', vec![1, 1, 0]),
///          ('d', vec![1, 1, 1])]).unwrap();
/// let mut data = Vec::new();
/// {
///     let mut writer = BitWriter::endian(&mut data, BigEndian);
///     writer.write_huffman(&tree, 'b').unwrap();
///     writer.write_huffman(&tree, 'c').unwrap();
///     writer.write_huffman(&tree, 'd').unwrap();
/// }
/// assert_eq!(data, [0b10110111]);
/// ```
pub fn compile_write_tree<E, T>(
    values: Vec<(T, Vec<u8>)>,
) -> Result<WriteHuffmanTree<E, T>, HuffmanTreeError>
where
    E: Endianness,
    T: Ord + Clone,
{
    let mut map = BTreeMap::new();

    for (symbol, code) in values {
        let mut encoded = Vec::new();
        for bits in code.chunks(32) {
            let mut acc = BitQueue::<E, u32>::new();
            for bit in bits {
                match *bit {
                    0 => acc.push(1, 0),
                    1 => acc.push(1, 1),
                    _ => return Err(HuffmanTreeError::InvalidBit),
                }
            }
            let len = acc.len();
            encoded.push((len, acc.value()))
        }
        map.entry(symbol)
            .or_insert_with(|| encoded.into_boxed_slice());
    }

    Ok(WriteHuffmanTree {
        map,
        phantom: PhantomData,
    })
}

/// A compiled Huffman tree for use with the `write_huffman` method.
/// Returned by `compiled_write_tree`.
pub struct WriteHuffmanTree<E: Endianness, T: Ord> {
    map: BTreeMap<T, Box<[(u32, u32)]>>,
    phantom: PhantomData<E>,
}

impl<E: Endianness, T: Ord + Clone> WriteHuffmanTree<E, T> {
    /// Returns true if symbol is in tree.
    #[inline]
    pub fn has_symbol(&self, symbol: &T) -> bool {
        self.map.contains_key(symbol)
    }

    /// Given symbol, returns iterator of
    /// (bits, value) pairs for writing code.
    /// Panics if symbol is not found.
    #[inline]
    pub fn get(&self, symbol: &T) -> impl Iterator<Item = &(u32, u32)> {
        self.map[symbol].iter()
    }
}
<|endoftext|>


<commit_before>use crate::core::instruction::Instruction;

#[allow(non_snake_case)]
pub fn decode_MOVT_t1(_opcode: u32) -> Instruction {
    unimplemented!()
}
<commit_msg>MOVT: return UDF for now<commit_after>use crate::core::instruction::Instruction;
use crate::core::ThumbCode;

#[allow(non_snake_case)]
pub fn decode_MOVT_t1(opcode: u32) -> Instruction {
    Instruction::UDF {
        imm32: 0,
        opcode: ThumbCode::from(opcode),
    }
}
<|endoftext|>


<commit_before>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<commit_msg>Add Math.min(a, b, ...c)<commit_after>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Get the minimum of several numbers
pub fn min(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.min(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"min", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(min, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<|endoftext|>