<commit_before>// Copyright ⓒ 2015-2018 Kevin B. Knapp
//
// `clap_generate` is distributed under the terms of both the MIT license and the Apache License
// (Version 2.0).
// See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files in this repository
// for more information.

//! Generates completions (and other things) for [`clap`](https://github.com/clap-rs/clap) based CLIs
//!
//! - For generating at compile-time, see [`generate_to`]
//! - For generating at runtime, see [`generate`]

#![doc(html_logo_url = "https://clap.rs/images/media/clap.png")]
#![doc(html_root_url = "https://docs.rs/clap_generate/3.0.0-beta.4")]
#![deny(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![allow(clippy::needless_doctest_main)]

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";

#[macro_use]
#[allow(missing_docs)]
mod macros;

/// Contains some popular generators
pub mod generators;
/// Contains supported shells for auto-completion scripts
mod shell;

use std::ffi::OsString;
use std::fs::File;
use std::io::Error;
use std::io::Write;
use std::path::PathBuf;

#[doc(inline)]
pub use generators::Generator;
#[doc(inline)]
pub use shell::Shell;

/// Generate a completions file for a specified shell at compile-time.
///
/// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script" or a
/// [`cargo-xtask`]](https://github.com/matklad/cargo-xtask)
///
/// # Examples
///
/// The following example generates a bash completion script via a `build.rs` script. In this
/// simple example, we'll demo a very small application with only a single subcommand and two
/// args. Real applications could be many multiple levels deep in subcommands, and have tens or
/// potentially hundreds of arguments.
///
/// First, it helps if we separate out our `App` definition into a separate file. Whether you
/// do this as a function, or bare App definition is a matter of personal preference.
///
/// ```
/// // src/cli.rs
///
/// use clap::{App, Arg};
///
/// pub fn build_cli() -> App<'static> {
///     App::new("compl")
///         .about("Tests completions")
///         .arg(Arg::new("file")
///             .about("some input file"))
///         .subcommand(App::new("test")
///             .about("tests things")
///             .arg(Arg::new("case")
///                 .long("case")
///                 .takes_value(true)
///                 .about("the case to test")))
/// }
/// ```
///
/// In our regular code, we can simply call this `build_cli()` function, then call
/// `get_matches()`, or any of the other normal methods directly after. For example:
///
/// ```ignore
/// // src/main.rs
///
/// mod cli;
///
/// fn main() {
///     let _m = cli::build_cli().get_matches();
///
///     // normal logic continues...
/// }
/// ```
///
/// Next, we set up our `Cargo.toml` to use a `build.rs` build script.
///
/// ```toml
/// # Cargo.toml
/// build = "build.rs"
///
/// [dependencies]
/// clap = "*"
///
/// [build-dependencies]
/// clap = "*"
/// clap_generate = "*"
/// ```
///
/// Next, we place a `build.rs` in our project root.
///
/// ```ignore
/// use clap_generate::{generate_to, generators::Bash};
/// use std::env;
/// use std::io::Error;
///
/// include!("src/cli.rs");
///
/// fn main() -> Result<(), Error> {
///     let outdir = match env::var_os("OUT_DIR") {
///         None => return Ok(()),
///         Some(outdir) => outdir,
///     };
///
///     let mut app = build_cli();
///     let path = generate_to::<Bash, _, _>(
///         &mut app, // We need to specify what generator to use
///         "myapp",  // We need to specify the bin name manually
///         outdir,   // We need to specify where to write to
///     )?;
///
///     println!("cargo:warning=completion file is generated: {:?}", path);
///
///     Ok(())
/// }
/// ```
///
/// Now, once we compile there will be a `{bin_name}.bash` file in the directory.
/// Assuming we compiled with debug mode, it would be somewhere similar to
/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash`.
///
/// **NOTE:** Please look at the individual [generators]
/// to see the name of the files generated.
pub fn generate_to<G, S, T>(app: &mut clap::App, bin_name: S, out_dir: T) -> Result<PathBuf, Error>
where
    G: Generator,
    S: Into<String>,
    T: Into<OsString>,
{
    app.set_bin_name(bin_name);

    let out_dir = PathBuf::from(out_dir.into());
    let file_name = G::file_name(app.get_bin_name().unwrap());

    let path = out_dir.join(file_name);
    let mut file = File::create(&path)?;

    _generate::<G, S>(app, &mut file);
    Ok(path)
}

/// Generate a completions file for a specified shell at runtime.
///
/// Until `cargo install` can install extra files like a completion script, this may be
/// used e.g. in a command that outputs the contents of the completion script, to be
/// redirected into a file by the user.
///
/// # Examples
///
/// Assuming a separate `cli.rs` like the [example above](generate_to()),
/// we can let users generate a completion script using a command:
///
/// ```ignore
/// // src/main.rs
///
/// mod cli;
/// use std::io;
/// use clap_generate::{generate, generators::Bash};
///
/// fn main() {
///     let matches = cli::build_cli().get_matches();
///
///     if matches.is_present("generate-bash-completions") {
///         generate::<Bash, _>(&mut cli::build_cli(), "myapp", &mut io::stdout());
///     }
///
///     // normal logic continues...
/// }
///
/// ```
///
/// Usage:
///
/// ```shell
/// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash
/// ```
pub fn generate<G, S>(app: &mut clap::App, bin_name: S, buf: &mut dyn Write)
where
    G: Generator,
    S: Into<String>,
{
    app.set_bin_name(bin_name);
    _generate::<G, S>(app, buf)
}

fn _generate<G, S>(app: &mut clap::App, buf: &mut dyn Write)
where
    G: Generator,
    S: Into<String>,
{
    // TODO: All the subcommands need to be built instead of just the top one
    app._build();
    app._build_bin_names();

    G::generate(app, buf)
}
<commit_msg>doc(generate) fix link in `generate_to`<commit_after>// Copyright ⓒ 2015-2018 Kevin B. Knapp
//
// `clap_generate` is distributed under the terms of both the MIT license and the Apache License
// (Version 2.0).
// See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files in this repository
// for more information.

//! Generates completions (and other things) for [`clap`](https://github.com/clap-rs/clap) based CLIs
//!
//! - For generating at compile-time, see [`generate_to`]
//! - For generating at runtime, see [`generate`]

#![doc(html_logo_url = "https://clap.rs/images/media/clap.png")]
#![doc(html_root_url = "https://docs.rs/clap_generate/3.0.0-beta.4")]
#![deny(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![allow(clippy::needless_doctest_main)]

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";

#[macro_use]
#[allow(missing_docs)]
mod macros;

/// Contains some popular generators
pub mod generators;
/// Contains supported shells for auto-completion scripts
mod shell;

use std::ffi::OsString;
use std::fs::File;
use std::io::Error;
use std::io::Write;
use std::path::PathBuf;

#[doc(inline)]
pub use generators::Generator;
#[doc(inline)]
pub use shell::Shell;

/// Generate a completions file for a specified shell at compile-time.
///
/// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script" or a
/// [`cargo-xtask`](https://github.com/matklad/cargo-xtask)
///
/// # Examples
///
/// The following example generates a bash completion script via a `build.rs` script. In this
/// simple example, we'll demo a very small application with only a single subcommand and two
/// args. Real applications could be many multiple levels deep in subcommands, and have tens or
/// potentially hundreds of arguments.
///
/// First, it helps if we separate out our `App` definition into a separate file. Whether you
/// do this as a function, or bare App definition is a matter of personal preference.
///
/// ```
/// // src/cli.rs
///
/// use clap::{App, Arg};
///
/// pub fn build_cli() -> App<'static> {
///     App::new("compl")
///         .about("Tests completions")
///         .arg(Arg::new("file")
///             .about("some input file"))
///         .subcommand(App::new("test")
///             .about("tests things")
///             .arg(Arg::new("case")
///                 .long("case")
///                 .takes_value(true)
///                 .about("the case to test")))
/// }
/// ```
///
/// In our regular code, we can simply call this `build_cli()` function, then call
/// `get_matches()`, or any of the other normal methods directly after. For example:
///
/// ```ignore
/// // src/main.rs
///
/// mod cli;
///
/// fn main() {
///     let _m = cli::build_cli().get_matches();
///
///     // normal logic continues...
/// }
/// ```
///
/// Next, we set up our `Cargo.toml` to use a `build.rs` build script.
///
/// ```toml
/// # Cargo.toml
/// build = "build.rs"
///
/// [dependencies]
/// clap = "*"
///
/// [build-dependencies]
/// clap = "*"
/// clap_generate = "*"
/// ```
///
/// Next, we place a `build.rs` in our project root.
///
/// ```ignore
/// use clap_generate::{generate_to, generators::Bash};
/// use std::env;
/// use std::io::Error;
///
/// include!("src/cli.rs");
///
/// fn main() -> Result<(), Error> {
///     let outdir = match env::var_os("OUT_DIR") {
///         None => return Ok(()),
///         Some(outdir) => outdir,
///     };
///
///     let mut app = build_cli();
///     let path = generate_to::<Bash, _, _>(
///         &mut app, // We need to specify what generator to use
///         "myapp",  // We need to specify the bin name manually
///         outdir,   // We need to specify where to write to
///     )?;
///
///     println!("cargo:warning=completion file is generated: {:?}", path);
///
///     Ok(())
/// }
/// ```
///
/// Now, once we compile there will be a `{bin_name}.bash` file in the directory.
/// Assuming we compiled with debug mode, it would be somewhere similar to
/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash`.
///
/// **NOTE:** Please look at the individual [generators]
/// to see the name of the files generated.
pub fn generate_to<G, S, T>(app: &mut clap::App, bin_name: S, out_dir: T) -> Result<PathBuf, Error>
where
    G: Generator,
    S: Into<String>,
    T: Into<OsString>,
{
    app.set_bin_name(bin_name);

    let out_dir = PathBuf::from(out_dir.into());
    let file_name = G::file_name(app.get_bin_name().unwrap());

    let path = out_dir.join(file_name);
    let mut file = File::create(&path)?;

    _generate::<G, S>(app, &mut file);
    Ok(path)
}

/// Generate a completions file for a specified shell at runtime.
///
/// Until `cargo install` can install extra files like a completion script, this may be
/// used e.g. in a command that outputs the contents of the completion script, to be
/// redirected into a file by the user.
///
/// # Examples
///
/// Assuming a separate `cli.rs` like the [example above](generate_to()),
/// we can let users generate a completion script using a command:
///
/// ```ignore
/// // src/main.rs
///
/// mod cli;
/// use std::io;
/// use clap_generate::{generate, generators::Bash};
///
/// fn main() {
///     let matches = cli::build_cli().get_matches();
///
///     if matches.is_present("generate-bash-completions") {
///         generate::<Bash, _>(&mut cli::build_cli(), "myapp", &mut io::stdout());
///     }
///
///     // normal logic continues...
/// }
///
/// ```
///
/// Usage:
///
/// ```shell
/// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash
/// ```
pub fn generate<G, S>(app: &mut clap::App, bin_name: S, buf: &mut dyn Write)
where
    G: Generator,
    S: Into<String>,
{
    app.set_bin_name(bin_name);
    _generate::<G, S>(app, buf)
}

fn _generate<G, S>(app: &mut clap::App, buf: &mut dyn Write)
where
    G: Generator,
    S: Into<String>,
{
    // TODO: All the subcommands need to be built instead of just the top one
    app._build();
    app._build_bin_names();

    G::generate(app, buf)
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        let value = CString::new(value);
        value.ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}
<commit_msg>Add helper for checking for executable presense in the PATH<commit_after>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        let value = CString::new(value);
        value.ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

pub fn found_in_path(exec: &str) -> bool {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            if path.join(exec).exists() {
                return true;
            }
        }
    }
    false
}

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

    #[test]
    fn ls_found_in_path() {
        assert!(found_in_path("ls"))
    }

    #[test]
    fn ls123_not_found_in_path() {
        assert!(!found_in_path("ls123"))
    }
}
<|endoftext|>


<commit_before>//! This modules provides an implementation of the Lempel–Ziv–Welch Compression Algorithm

use std::io;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Vacant, Occupied};

use super::bits::BitReader;

const MAX_CODESIZE: u8 = 12;

/// LZW decoder
pub struct LZWReader<R: Reader> {
    r: BitReader<R>,
    table: HashMap<u16, Vec<u8>>,
    code_size: u8,
    next_code: u16,
    prev_code: Option<u16>,
    minimal_size: u8,
    clear_code: u16,
    end_code: u16,

}

impl<R: Reader> LZWReader<R> {
    /// Creates a new LZW reader with a minimum code size of `size`
    pub fn new(reader: R, size: u8) -> LZWReader<R> {
        let clear_code = 1 << size as uint;
        let end_code = clear_code + 1;
        LZWReader {
            r: BitReader::new(reader),
            table: HashMap::new(),
            code_size: size + 1,
            next_code: end_code + 1,
            prev_code: None,
            minimal_size: size,
            clear_code: clear_code,
            end_code: end_code,
        }
    }

    /// Resets the code table
    fn reset(&mut self) {
        self.table.clear();
        self.code_size = self.minimal_size + 1;
        self.next_code = self.end_code + 1;
        self.prev_code = None;
        for i in range(0, (1 << self.minimal_size as uint)) {
            self.table.insert(i, vec![i as u8]);
        }
    }

    /// Decodes the data into a `Writer`
    pub fn decode<W: Writer>(&mut self, stream: &mut W) -> io::IoResult<()> {
        //let code = try!(self.r.read_bits(self.code_size)) as u16;
        //let mut prev = Some(if code == self.clear_code {
        //    self.reset();
        //    (try!(self.r.read_bits(self.code_size)) as u8)
        //} else {
        //    code as u8
        //} as u16);
        //if let Some(prev) = prev {
        //    try!(stream.write_u8(prev as u8));
        //}
        loop {
            let code = try!(self.r.read_bits(self.code_size)) as u16;
            //println!("code {} ({} bits), prev {}", code, self.code_size, self.prev_code);
            if code == self.clear_code {
                self.reset();
                //println!("reset");
            } else if code == self.end_code {
                return Ok(())
            } else {
                self.prev_code = if let Some(prev) = self.prev_code {
                    let mut prefix = self.table[prev].clone();
                    let k = match self.table.entry(code) {
                        Occupied(entry) => {
                            try!(stream.write(entry.get().as_slice()));
                            entry.get()[0]
                        },
                        Vacant(_) => {
                            try!(stream.write(prefix.as_slice()));
                            try!(stream.write(prefix.slice_to(1)));
                            prefix[0]
                        },
                    };
                    prefix.push(k);
                    self.table.insert(self.next_code, prefix);
                    if self.next_code == (1 << self.code_size as uint) - 1
                       && self.code_size < MAX_CODESIZE {
                        self.code_size += 1;
                    }
                    self.next_code += 1;
                    Some(code)
                } else {
                    try!(stream.write_u8(code as u8));
                    Some(code)
                }
            }
        }
    }
}<commit_msg>replace hash map with optimized data structure to avoid excessice allocations<commit_after>//! This modules provides an implementation of the Lempel–Ziv–Welch Compression Algorithm

use std::io;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Vacant, Occupied};

use super::bits::BitReader;

const MAX_CODESIZE: u8 = 12;

/// Alias for a LZW code point
type Code = u16;

/// Decoding dictionary
/// It is not generic due to current limitations of Rust
/// Inspired by http://www.cplusplus.com/articles/iL18T05o/
struct DecodingDict {
    min_size: u8,
    table: Vec<(Option<Code>, u8)>,
    buffer: Vec<u8>,
}

impl DecodingDict {
    /// Creates a new dict
    fn new(min_size: u8) -> DecodingDict {
        DecodingDict {
            min_size: min_size,
            table: Vec::with_capacity(512),
            buffer: Vec::with_capacity((1 << MAX_CODESIZE as uint) - 1)
        }
    }

    /// Resets the dictionary
    fn reset(&mut self) {
        self.table.clear();
        for i in range(0, (1u16 << self.min_size as uint)) {
            self.table.push((None, i as u8));
        }
    }

    /// Inserts a value into the dict
    fn push(&mut self, key: Option<Code>, value: u8) {
        self.table.push((key, value))
    }

    /// Reconstructs the data for the corresponding code
    fn reconstruct(&mut self, code: Option<Code>) -> &[u8] {
        self.buffer.clear();
        let mut code = code;
        let mut cha;
        while let Some(k) = code {
            //(code, cha) = self.table[k as uint];
            let entry = self.table[k as uint]; code = entry.0; cha = entry.1;
            self.buffer.push(cha);
        }
        self.buffer.reverse();
        self.buffer.as_slice()
    }

    /// Returns the buffer constructed by the last reconstruction
    fn buffer(&self) -> &[u8] {
        self.buffer.as_slice()
    }

    /// Number of entries in the dictionary
    fn next_code(&self) -> u16 {
        self.table.len() as u16
    }
}

/// LZW decoder
pub struct LZWReader<R: Reader> {
    r: BitReader<R>,
    table: DecodingDict,
    code_size: u8,
    minimal_size: u8,
    clear_code: u16,
    end_code: u16,

}

impl<R: Reader> LZWReader<R> {
    /// Creates a new LZW reader with a minimum code size of `size`
    pub fn new(reader: R, size: u8) -> LZWReader<R> {
        let clear_code = 1 << size as uint;
        let end_code = clear_code + 1;
        LZWReader {
            r: BitReader::new(reader),
            table: DecodingDict::new(size),
            code_size: size + 1,
            minimal_size: size,
            clear_code: clear_code,
            end_code: end_code,
        }
    }

    /// Resets the code table
    fn reset(&mut self) {
        self.table.reset();
        self.table.push(None, 0); // clear code
        self.table.push(None, 0); // end code
        self.code_size = self.minimal_size + 1;
    }

    /// Decodes the data into a `Writer`
    pub fn decode<W: Writer>(&mut self, stream: &mut W) -> io::IoResult<()> {
        let mut prev = None;
        loop {
            let code = try!(self.r.read_bits(self.code_size)) as u16;
            if code == self.clear_code {
                self.reset();
                prev = None;
            } else if code == self.end_code {
                return Ok(())
            } else {
                let next_code = self.table.next_code();
                let data = if code == next_code {
                    let cha = self.table.reconstruct(prev)[0];
                    self.table.push(prev, cha);
                    self.table.reconstruct(Some(code))
                } else if code > next_code {
                    return Err(io::IoError {
                        kind: io::InvalidInput,
                        desc: "Invalid code",
                        detail: None
                    })
                } else {
                    let cha = self.table.reconstruct(Some(code))[0];
                    self.table.push(prev, cha);
                    self.table.buffer()
                };
                try!(stream.write(data));
                if next_code == (1 << self.code_size as uint)
                   && self.code_size < MAX_CODESIZE {
                    self.code_size += 1;
                }
                prev = Some(code);
            }
        }
    }
}<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::collections::{HashMap};
use cgmath::{Vector2};
use common::types::{PlayerId, UnitId, MapPos, Size2, ZInt};
use core::{CoreEvent};
use unit::{Unit};
use object::{ObjectTypes};
use map::{Map, Terrain};
use fov;

pub struct GameState {
    // TODO: remove 'pub'?
    pub units: HashMap<UnitId, Unit>,
    pub map: Map<Terrain>,
    pub fow: Map<bool>, // Fog of War map
    pub player_id: Option<PlayerId>,
}

impl<'a> GameState {
    // TODO: Remove 'player_id'
    pub fn new(map_size: &Size2<ZInt>, player_id: Option<&PlayerId>) -> GameState {
        let mut map = Map::new(map_size, Terrain::Plain);
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 3}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 4}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 5}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 5, y: 5}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 6, y: 4}}) = Terrain::Trees;
        GameState {
            units: HashMap::new(),
            map: map,
            fow: Map::new(map_size, false),
            player_id: if let Some(player_id) = player_id {
                Some(player_id.clone())
            } else {
                None
            },
        }
    }

    pub fn units_at(&'a self, pos: &MapPos) -> Vec<&'a Unit> {
        let mut units = Vec::new();
        for (_, unit) in self.units.iter() {
            if unit.pos == *pos {
                units.push(unit);
            }
        }
        units
    }

    pub fn is_tile_occupied(&self, pos: &MapPos) -> bool {
        self.units_at(pos).len() > 0
    }

    fn refresh_units(&mut self, object_types: &ObjectTypes, player_id: &PlayerId) {
        for (_, unit) in self.units.iter_mut() {
            if unit.player_id == *player_id {
                let unit_type = object_types.get_unit_type(&unit.type_id);
                unit.move_points = unit_type.move_points;
                unit.attack_points = unit_type.attack_points;
            }
        }
    }

    /*
    fn add_passive_ap(&mut self, player_id: &PlayerId) {
        for (_, unit) in self.units.iter_mut() {
            if unit.player_id == *player_id {
                unit.attack_points += 1;
            }
        }
    }
    */

    pub fn clear_fow(&mut self) {
        for pos in self.fow.get_iter() {
            *self.fow.tile_mut(&pos) = false;
        }
    }

    fn update_fow(&mut self) {
        let player_id = self.player_id.as_ref().unwrap();
        for (_, unit) in self.units.iter() {
            if unit.player_id == *player_id {
                *self.fow.tile_mut(&unit.pos) = true;
                fov::fov(&self.map, &mut self.fow, &unit.pos);
            }
        }
    }

    pub fn apply_event(&mut self, object_types: &ObjectTypes, event: &CoreEvent) {
        match event {
            &CoreEvent::Move{ref unit_id, ref path} => {
                let pos = path.destination().clone();
                let unit = self.units.get_mut(unit_id)
                    .expect("BAD MOVE UNIT ID");
                unit.pos = pos;
                assert!(unit.move_points > 0);
                unit.move_points -= path.total_cost().n;
                assert!(unit.move_points >= 0);
                if let Some(player_id) = self.player_id.clone() {
                    if unit.player_id == player_id {
                        for &(_, ref pos) in path.nodes() {
                            fov::fov(&self.map, &mut self.fow, pos);
                        }
                    }
                }
            },
            &CoreEvent::EndTurn{ref new_id, old_id: _} => {
                // TODO: remove ugly '.clone()'?
                if let Some(player_id) = self.player_id.clone() {
                    if player_id == *new_id {
                        self.clear_fow();
                    }
                }
                self.refresh_units(object_types, new_id);
                // self.add_passive_ap(old_id);
            },
            &CoreEvent::CreateUnit {
                ref unit_id,
                ref pos,
                ref type_id,
                ref player_id,
            } => {
                assert!(self.units.get(unit_id).is_none());
                let unit_type = object_types.get_unit_type(type_id);
                let move_points = unit_type.move_points;
                let attack_points = unit_type.attack_points;
                self.units.insert(unit_id.clone(), Unit {
                    id: unit_id.clone(),
                    pos: pos.clone(),
                    player_id: player_id.clone(),
                    type_id: type_id.clone(),
                    move_points: move_points,
                    attack_points: attack_points,
                });
            },
            &CoreEvent::AttackUnit {
                ref attacker_id,
                ref defender_id,
                ref killed,
                ..
            } => {
                if *killed {
                    assert!(self.units.get(defender_id).is_some());
                    self.units.remove(defender_id);
                }
                if let Some(unit) = self.units.get_mut(attacker_id) {
                    assert!(unit.attack_points >= 1);
                    unit.attack_points -= 1;
                }
            },
        }
        if self.player_id.is_some() {
            self.update_fow();
        }
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>game_state.rs: 'old_id: _' -> '..'<commit_after>// See LICENSE file for copyright and license details.

use std::collections::{HashMap};
use cgmath::{Vector2};
use common::types::{PlayerId, UnitId, MapPos, Size2, ZInt};
use core::{CoreEvent};
use unit::{Unit};
use object::{ObjectTypes};
use map::{Map, Terrain};
use fov;

pub struct GameState {
    // TODO: remove 'pub'?
    pub units: HashMap<UnitId, Unit>,
    pub map: Map<Terrain>,
    pub fow: Map<bool>, // Fog of War map
    pub player_id: Option<PlayerId>,
}

impl<'a> GameState {
    // TODO: Remove 'player_id'
    pub fn new(map_size: &Size2<ZInt>, player_id: Option<&PlayerId>) -> GameState {
        let mut map = Map::new(map_size, Terrain::Plain);
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 3}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 4}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 4, y: 5}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 5, y: 5}}) = Terrain::Trees;
        *map.tile_mut(&MapPos{v: Vector2{x: 6, y: 4}}) = Terrain::Trees;
        GameState {
            units: HashMap::new(),
            map: map,
            fow: Map::new(map_size, false),
            player_id: if let Some(player_id) = player_id {
                Some(player_id.clone())
            } else {
                None
            },
        }
    }

    pub fn units_at(&'a self, pos: &MapPos) -> Vec<&'a Unit> {
        let mut units = Vec::new();
        for (_, unit) in self.units.iter() {
            if unit.pos == *pos {
                units.push(unit);
            }
        }
        units
    }

    pub fn is_tile_occupied(&self, pos: &MapPos) -> bool {
        self.units_at(pos).len() > 0
    }

    fn refresh_units(&mut self, object_types: &ObjectTypes, player_id: &PlayerId) {
        for (_, unit) in self.units.iter_mut() {
            if unit.player_id == *player_id {
                let unit_type = object_types.get_unit_type(&unit.type_id);
                unit.move_points = unit_type.move_points;
                unit.attack_points = unit_type.attack_points;
            }
        }
    }

    /*
    fn add_passive_ap(&mut self, player_id: &PlayerId) {
        for (_, unit) in self.units.iter_mut() {
            if unit.player_id == *player_id {
                unit.attack_points += 1;
            }
        }
    }
    */

    pub fn clear_fow(&mut self) {
        for pos in self.fow.get_iter() {
            *self.fow.tile_mut(&pos) = false;
        }
    }

    fn update_fow(&mut self) {
        let player_id = self.player_id.as_ref().unwrap();
        for (_, unit) in self.units.iter() {
            if unit.player_id == *player_id {
                *self.fow.tile_mut(&unit.pos) = true;
                fov::fov(&self.map, &mut self.fow, &unit.pos);
            }
        }
    }

    pub fn apply_event(&mut self, object_types: &ObjectTypes, event: &CoreEvent) {
        match event {
            &CoreEvent::Move{ref unit_id, ref path} => {
                let pos = path.destination().clone();
                let unit = self.units.get_mut(unit_id)
                    .expect("BAD MOVE UNIT ID");
                unit.pos = pos;
                assert!(unit.move_points > 0);
                unit.move_points -= path.total_cost().n;
                assert!(unit.move_points >= 0);
                if let Some(player_id) = self.player_id.clone() {
                    if unit.player_id == player_id {
                        for &(_, ref pos) in path.nodes() {
                            fov::fov(&self.map, &mut self.fow, pos);
                        }
                    }
                }
            },
            &CoreEvent::EndTurn{ref new_id, ..} => {
                // TODO: remove ugly '.clone()'?
                if let Some(player_id) = self.player_id.clone() {
                    if player_id == *new_id {
                        self.clear_fow();
                    }
                }
                self.refresh_units(object_types, new_id);
                // self.add_passive_ap(old_id);
            },
            &CoreEvent::CreateUnit {
                ref unit_id,
                ref pos,
                ref type_id,
                ref player_id,
            } => {
                assert!(self.units.get(unit_id).is_none());
                let unit_type = object_types.get_unit_type(type_id);
                let move_points = unit_type.move_points;
                let attack_points = unit_type.attack_points;
                self.units.insert(unit_id.clone(), Unit {
                    id: unit_id.clone(),
                    pos: pos.clone(),
                    player_id: player_id.clone(),
                    type_id: type_id.clone(),
                    move_points: move_points,
                    attack_points: attack_points,
                });
            },
            &CoreEvent::AttackUnit {
                ref attacker_id,
                ref defender_id,
                ref killed,
                ..
            } => {
                if *killed {
                    assert!(self.units.get(defender_id).is_some());
                    self.units.remove(defender_id);
                }
                if let Some(unit) = self.units.get_mut(attacker_id) {
                    assert!(unit.attack_points >= 1);
                    unit.attack_points -= 1;
                }
            },
        }
        if self.player_id.is_some() {
            self.update_fow();
        }
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>#![crate_name="initdb"]
#![crate_type = "bin"]

extern crate sqlite3;

mod init {
    use sqlite3::{open, SqliteResult};

    pub fn main() -> SqliteResult<()> {
        let args = ::std::os::args();

        let mut db = try!(open(args[1].as_slice()));

        try!(db.exec("CREATE TABLE Words(Word TEXT);"));
        try!(db.exec("CREATE TABLE Definitions(Definee TEXT, Idx INTEGER, Definer TEXT);"));
        try!(db.exec("CREATE TABLE Log(Word TEXT, Timestamp INTEGER);"));

        let mut input = ::std::io::stdin();
        for line in input.lines() {
            let word = line.unwrap().clone();
            let trimmed = word.as_slice().trim();
            assert!(trimmed.is_alphanumeric(), "not alphanumeric: {}", trimmed);
            try!(db.exec(format!("INSERT INTO Words VALUES(\"{}\");", trimmed).as_slice()));
        }
        Ok(())
    }
}

pub fn main() {
    match init::main() {
        Ok(()) => {}
        Err(e) => { println!("error: {}", e) }
    }
}
<commit_msg>error handling in initdb<commit_after>#![crate_name="initdb"]
#![crate_type = "bin"]

extern crate sqlite3;

mod init {
    use sqlite3::{open, Database, SqliteResult};

    pub fn write_db(db : &mut Database) -> SqliteResult<()> {
        try!(db.exec("CREATE TABLE Words(Word TEXT);"));
        try!(db.exec("CREATE TABLE Definitions(Definee TEXT, Idx INTEGER, Definer TEXT);"));
        try!(db.exec("CREATE TABLE Log(Word TEXT, Timestamp INTEGER);"));

        let mut input = ::std::io::stdin();
        for line in input.lines() {
            let word = line.unwrap().clone();
            let trimmed = word.as_slice().trim();
            assert!(trimmed.is_alphanumeric(), "not alphanumeric: {}", trimmed);
            try!(db.exec(format!("INSERT INTO Words VALUES(\"{}\");", trimmed).as_slice()));
        }
        Ok(())
    }

    pub fn open_db() -> SqliteResult<Database> {
        let args = ::std::os::args();
        return open(args[1].as_slice());
    }

    pub fn main() {
        match open_db() {
            Ok(mut db) => {
               match write_db(&mut db) {
                   Ok(()) => {}
                   Err(e) => { println!("error: {}, ({})", e, db.get_errmsg()) }
               }
            }
            Err(e) => {
               println!("could not open database: {}", e);
            }
        }
    }
}

pub fn main() {
    init::main();
}
<|endoftext|>


<commit_before>use linked_hash_map::LinkedHashMap;
use serde_json::{ Value, Map };

#[derive(Debug, PartialEq, Clone)]
pub enum Shape {
    Null,
    Any,
    Bottom,
    Bool,
    StringT,
    Integer,
    Floating,
    VecT { elem_type: Box<Shape> },
    Struct { fields: LinkedHashMap<String, Shape> },
    Tuple(Vec<Shape>, u64),
    Optional(Box<Shape>)
}

pub fn to_vect(shapes: Vec<Shape>) -> Shape {
    let e = shapes.into_iter().fold(Shape::Bottom, common_shape);
    Shape::VecT { elem_type: Box::new(e) }
}

fn common_shape(a: Shape, b: Shape) -> Shape {
    if a == b {
        return a;
    }
    use self::Shape::*;
    match (a, b) {
        (a, Bottom) | (Bottom, a) => a,
        (Integer, Floating) |
        (Floating, Integer) => Floating,
        (a, Null) | (Null, a) => make_optional(a),
        (a, Optional(b)) | (Optional(b), a) => make_optional(common_shape(a, *b)),
        (Tuple(shapes1, n1), Tuple(shapes2, n2)) => {
            if shapes1.len() == shapes2.len() {
                let shapes: Vec<_> =
                    shapes1.into_iter()
                        .zip(shapes2.into_iter())
                        .map(|(a, b)| common_shape(a, b))
                        .collect();
                Tuple(shapes, n1 + n2)
            } else {
                let inner1 = shapes1.into_iter().fold(Shape::Bottom, common_shape);
                let inner2 = shapes2.into_iter().fold(Shape::Bottom, common_shape);
                VecT { elem_type: Box::new(common_shape(inner1, inner2)) }
            }
        }
        (Tuple(shapes, _), VecT { elem_type: e1 }) |
        (VecT { elem_type: e1 }, Tuple(shapes, _)) => {
            let e2 = shapes.into_iter().fold(Shape::Bottom, common_shape);
            VecT { elem_type: Box::new(common_shape(*e1, e2)) }
        }
        (VecT { elem_type: e1 }, VecT { elem_type: e2 }) => {
            VecT { elem_type: Box::new(common_shape(*e1, *e2)) }
        }
        (Struct { fields: f1 }, Struct { fields: f2 }) => {
            Struct { fields: common_field_shapes(f1, f2) }
        }
        _ => Any,
    }
}

fn make_optional(a: Shape) -> Shape {
    use self::Shape::*;
    match a {
        Null | Any | Bottom | Optional(_) => a,
        non_nullable => Optional(Box::new(non_nullable)),
    }
}

fn common_field_shapes(f1: LinkedHashMap<String, Shape>,
                       mut f2: LinkedHashMap<String, Shape>)
                       -> LinkedHashMap<String, Shape> {
    if f1 == f2 {
        return f1;
    }
    let mut unified = LinkedHashMap::new();
    for (key, val) in f1.into_iter() {
        match f2.remove(&key) {
            Some(val2) => {
                unified.insert(key, common_shape(val, val2));
            },
            None => {
                unified.insert(key, make_optional(val));
            }
        }
    }
    for (key, val) in f2.into_iter() {
        unified.insert(key, make_optional(val));
    }
    unified
}

pub fn value_to_shape(value: &Value) -> Shape {
    match *value {
        Value::Null => Shape::Null,
        Value::Bool(_) => Shape::Bool,
        Value::Number(ref n) => {
            if n.is_i64() {
                Shape::Integer
            } else {
                Shape::Floating
            }
        },
        Value::String(_) => Shape::StringT,
        Value::Array(ref values) => array_to_shape(values),
        Value::Object(ref map) => object_to_shape(map),
    }
}

fn array_to_shape(values: &[Value]) -> Shape {
    if values.len() <= 12 {
        let shapes: Vec<_> = values.iter().map(value_to_shape).collect();
        return Shape::Tuple(shapes, 1);
    }
    let inner = values.iter().fold(Shape::Bottom, |shape, val| {
        let shape2 = value_to_shape(val);
        common_shape(shape, shape2)
    });
    Shape::VecT { elem_type: Box::new(inner) }
}

fn object_to_shape(map: &Map<String, Value>) -> Shape {
    let inner = map.iter()
        .map(|(name, value)| (name.clone(), value_to_shape(value)))
        .collect();
    Shape::Struct { fields: inner }
}

#[test]
fn test_unify() {
    use Shape::*;
    assert_eq!(common_shape(Bool, Bool), Bool);
    assert_eq!(common_shape(Bool, Integer), Any);
    assert_eq!(common_shape(Integer, Floating), Floating);
    assert_eq!(common_shape(Null, Any), Any);
    assert_eq!(common_shape(Null, Bool), Optional(Box::new(Bool)));
    assert_eq!(common_shape(Null, Optional(Box::new(Integer))), Optional(Box::new(Integer)));
    assert_eq!(common_shape(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(common_shape(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(common_shape(Optional(Box::new(Integer)), Optional(Box::new(Floating))),
               Optional(Box::new(Floating)));
    assert_eq!(common_shape(Optional(Box::new(StringT)), Optional(Box::new(Integer))), Any);
}

// based on hashmap! macro from maplit crate
macro_rules! string_hashmap {
    ($($key:expr => $value:expr,)+) => { string_hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let mut _map = ::linked_hash_map::LinkedHashMap::new();
            $(
                _map.insert($key.to_string(), $value);
            )*
            _map
        }
    };
}

#[test]
fn test_common_field_shapes() {
    use Shape::*;
    {
        let f1 = string_hashmap!{
            "a" => Integer,
            "b" => Bool,
            "c" => Integer,
            "d" => StringT,
        };
        let f2 = string_hashmap!{
            "a" => Integer,
            "c" => Floating,
            "d" => Null,
            "e" => Any,
        };
        assert_eq!(common_field_shapes(f1, f2), string_hashmap!{
            "a" => Integer,
            "b" => Optional(Box::new(Bool)),
            "c" => Floating,
            "d" => Optional(Box::new(StringT)),
            "e" => Any,
        });
    }
}
<commit_msg>Extract fold_shapes function<commit_after>use linked_hash_map::LinkedHashMap;
use serde_json::{ Value, Map };

#[derive(Debug, PartialEq, Clone)]
pub enum Shape {
    Null,
    Any,
    Bottom,
    Bool,
    StringT,
    Integer,
    Floating,
    VecT { elem_type: Box<Shape> },
    Struct { fields: LinkedHashMap<String, Shape> },
    Tuple(Vec<Shape>, u64),
    Optional(Box<Shape>)
}

pub fn to_vect(shapes: Vec<Shape>) -> Shape {
    Shape::VecT { elem_type: Box::new(fold_shapes(shapes)) }
}

fn fold_shapes(shapes: Vec<Shape>) -> Shape {
    shapes.into_iter().fold(Shape::Bottom, common_shape)
}

fn common_shape(a: Shape, b: Shape) -> Shape {
    if a == b {
        return a;
    }
    use self::Shape::*;
    match (a, b) {
        (a, Bottom) | (Bottom, a) => a,
        (Integer, Floating) |
        (Floating, Integer) => Floating,
        (a, Null) | (Null, a) => make_optional(a),
        (a, Optional(b)) | (Optional(b), a) => make_optional(common_shape(a, *b)),
        (Tuple(shapes1, n1), Tuple(shapes2, n2)) => {
            if shapes1.len() == shapes2.len() {
                let shapes: Vec<_> = shapes1.into_iter()
                                            .zip(shapes2.into_iter())
                                            .map(|(a, b)| common_shape(a, b))
                                            .collect();
                Tuple(shapes, n1 + n2)
            } else {
                VecT {
                    elem_type: Box::new(common_shape(fold_shapes(shapes1), fold_shapes(shapes2)))
                }
            }
        }
        (Tuple(shapes, _), VecT { elem_type: e1 }) |
        (VecT { elem_type: e1 }, Tuple(shapes, _)) => {
            VecT { elem_type: Box::new(common_shape(*e1, fold_shapes(shapes))) }
        }
        (VecT { elem_type: e1 }, VecT { elem_type: e2 }) => {
            VecT { elem_type: Box::new(common_shape(*e1, *e2)) }
        }
        (Struct { fields: f1 }, Struct { fields: f2 }) => {
            Struct { fields: common_field_shapes(f1, f2) }
        }
        _ => Any,
    }
}

fn make_optional(a: Shape) -> Shape {
    use self::Shape::*;
    match a {
        Null | Any | Bottom | Optional(_) => a,
        non_nullable => Optional(Box::new(non_nullable)),
    }
}

fn common_field_shapes(f1: LinkedHashMap<String, Shape>,
                       mut f2: LinkedHashMap<String, Shape>)
                       -> LinkedHashMap<String, Shape> {
    if f1 == f2 {
        return f1;
    }
    let mut unified = LinkedHashMap::new();
    for (key, val) in f1.into_iter() {
        match f2.remove(&key) {
            Some(val2) => {
                unified.insert(key, common_shape(val, val2));
            },
            None => {
                unified.insert(key, make_optional(val));
            }
        }
    }
    for (key, val) in f2.into_iter() {
        unified.insert(key, make_optional(val));
    }
    unified
}

pub fn value_to_shape(value: &Value) -> Shape {
    match *value {
        Value::Null => Shape::Null,
        Value::Bool(_) => Shape::Bool,
        Value::Number(ref n) => {
            if n.is_i64() {
                Shape::Integer
            } else {
                Shape::Floating
            }
        },
        Value::String(_) => Shape::StringT,
        Value::Array(ref values) => array_to_shape(values),
        Value::Object(ref map) => object_to_shape(map),
    }
}

fn array_to_shape(values: &[Value]) -> Shape {
    if values.len() <= 12 {
        let shapes: Vec<_> = values.iter().map(value_to_shape).collect();
        return Shape::Tuple(shapes, 1);
    }
    let inner = values.iter().fold(Shape::Bottom, |shape, val| {
        let shape2 = value_to_shape(val);
        common_shape(shape, shape2)
    });
    Shape::VecT { elem_type: Box::new(inner) }
}

fn object_to_shape(map: &Map<String, Value>) -> Shape {
    let inner = map.iter()
        .map(|(name, value)| (name.clone(), value_to_shape(value)))
        .collect();
    Shape::Struct { fields: inner }
}

#[test]
fn test_unify() {
    use Shape::*;
    assert_eq!(common_shape(Bool, Bool), Bool);
    assert_eq!(common_shape(Bool, Integer), Any);
    assert_eq!(common_shape(Integer, Floating), Floating);
    assert_eq!(common_shape(Null, Any), Any);
    assert_eq!(common_shape(Null, Bool), Optional(Box::new(Bool)));
    assert_eq!(common_shape(Null, Optional(Box::new(Integer))), Optional(Box::new(Integer)));
    assert_eq!(common_shape(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(common_shape(Any, Optional(Box::new(Integer))), Any);
    assert_eq!(common_shape(Optional(Box::new(Integer)), Optional(Box::new(Floating))),
               Optional(Box::new(Floating)));
    assert_eq!(common_shape(Optional(Box::new(StringT)), Optional(Box::new(Integer))), Any);
}

// based on hashmap! macro from maplit crate
macro_rules! string_hashmap {
    ($($key:expr => $value:expr,)+) => { string_hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let mut _map = ::linked_hash_map::LinkedHashMap::new();
            $(
                _map.insert($key.to_string(), $value);
            )*
            _map
        }
    };
}

#[test]
fn test_common_field_shapes() {
    use Shape::*;
    {
        let f1 = string_hashmap!{
            "a" => Integer,
            "b" => Bool,
            "c" => Integer,
            "d" => StringT,
        };
        let f2 = string_hashmap!{
            "a" => Integer,
            "c" => Floating,
            "d" => Null,
            "e" => Any,
        };
        assert_eq!(common_field_shapes(f1, f2), string_hashmap!{
            "a" => Integer,
            "b" => Optional(Box::new(Bool)),
            "c" => Floating,
            "d" => Optional(Box::new(StringT)),
            "e" => Any,
        });
    }
}
<|endoftext|>


<commit_before>///! Basic CSS block layout.

use style::{PropertyMap};
use css::{Value, Keyword, Length, Px};
use std::iter::AdditiveIterator; // for `sum`

/// Calculate the width of a block-level non-replaced element in normal flow.
pub fn calculate_block_width(specified_values: &PropertyMap, containing_block_width: f32) {
    // http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    let val = |name| specified_values.find_equiv(&name).map(|v| v.clone());

    // `width` has initial value `auto`.
    let auto = Keyword("auto".to_string());
    let mut width = val("width").unwrap_or(auto.clone());

    // margin, border, and padding have initial value 0.
    let get_length = |name, fallback| {
        val(name).unwrap_or_else(|| val(fallback).unwrap_or(Length(0.0, Px)))
    };
    let mut margin_left = get_length("margin-left", "margin");
    let mut margin_right = get_length("margin-right", "margin");

    let border_left = get_length("border-left-width", "border-width");
    let border_right = get_length("border-right-width", "border-width");

    let padding_left = get_length("padding-left", "padding");
    let padding_right = get_length("padding-right", "padding");

    let total = sum_lengths([&margin_left, &margin_right, &border_left, &border_right,
                             &padding_left, &padding_right, &width]);

    // Adjust used values so that the above sum equals containing_block_width.
    // Each arm of the `match` should increase the above sum by exactly `underflow`.
    let underflow = containing_block_width - total;
    match (width == auto, margin_left == auto, margin_right == auto) {
        // If the values are overconstrained, calculate margin_right.
        (false, false, false) => {
            margin_right = Length(px(margin_right) + underflow, Px);
        }
        // If exactly one value is `auto`, its used value follows from the equality.
        (false, false, true) => {
            margin_right = Length(underflow, Px);
        }
        (false, true, false) => {
            margin_left = Length(underflow, Px);
        }
        // If 'width' is set to 'auto', any other 'auto' values become '0'.
        (true, _, _) => {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
            width = Length(underflow, Px);
        }
        (false, true, true) => {
            // If margin-left and margin-right are both auto, their used values are equal.
            margin_left = Length(underflow / 2.0, Px);
            margin_right = Length(underflow / 2.0, Px);
        }
    }
}

/// Add together all the non-`auto` lengths.
fn sum_lengths(values: &[&Value]) -> f32 {
    values.iter().map(|value| match **value {
        Length(f, Px) => f,
        _ => 0.0 // ignore 'auto' or invalid widths
    }).sum()
}

/// Return the size of a Length in px.
fn px(value: Value) -> f32 {
    match value {
        Length(f, Px) => f,
        Keyword(_) => fail!("not a length")
    }
}
<commit_msg>Minor changes to block width calculation<commit_after>///! Basic CSS block layout.

use style::{PropertyMap};
use css::{Value, Keyword, Length, Px};
use std::iter::AdditiveIterator; // for `sum`

/// Calculate the width of a block-level non-replaced element in normal flow.
pub fn calculate_block_width(specified_values: &PropertyMap, containing_block_width: f32) {
    // http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    let val = |name| specified_values.find_equiv(&name).map(|v| v.clone());

    // `width` has initial value `auto`.
    let auto = Keyword("auto".to_string());
    let mut width = val("width").unwrap_or(auto.clone());

    // margin, border, and padding have initial value 0.
    let get_length = |name, fallback| {
        val(name).unwrap_or_else(|| val(fallback).unwrap_or(Length(0.0, Px)))
    };
    let mut margin_left = get_length("margin-left", "margin");
    let mut margin_right = get_length("margin-right", "margin");

    let border_left = get_length("border-left-width", "border-width");
    let border_right = get_length("border-right-width", "border-width");

    let padding_left = get_length("padding-left", "padding");
    let padding_right = get_length("padding-right", "padding");

    let total_width = sum_lengths([&margin_left, &margin_right, &border_left, &border_right,
                                   &padding_left, &padding_right, &width]);

    // If width is not auto and the total is wider than the container, treat auto margins as 0.
    if width != auto && total_width > containing_block_width {
        if margin_left == auto {
            margin_left = Length(0.0, Px);
        }
        if margin_right == auto {
            margin_right = Length(0.0, Px);
        }
    }

    // Adjust used values so that the above sum equals containing_block_width.
    // Each arm of the `match` should increase the total width by exactly `underflow`,
    // and afterward all values should be absolute lengths in px.
    let underflow = containing_block_width - total_width;
    match (width == auto, margin_left == auto, margin_right == auto) {
        // If the values are overconstrained, calculate margin_right.
        (false, false, false) => {
            margin_right = Length(px(margin_right) + underflow, Px);
        }
        // If exactly one value is auto, its used value follows from the equality.
        (false, false, true) => {
            margin_right = Length(underflow, Px);
        }
        (false, true, false) => {
            margin_left = Length(underflow, Px);
        }
        // If width is set to auto, any other auto values become 0.
        (true, _, _) => {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
            width = Length(underflow, Px);
        }
        (false, true, true) => {
            // If margin-left and margin-right are both auto, their used values are equal.
            margin_left = Length(underflow / 2.0, Px);
            margin_right = Length(underflow / 2.0, Px);
        }
    }
}

/// Add together all the non-`auto` lengths.
fn sum_lengths(values: &[&Value]) -> f32 {
    values.iter().map(|value| match **value {
        Length(f, Px) => f,
        _ => 0.0 // ignore 'auto' or invalid widths
    }).sum()
}

/// Return the size of a Length in px.
fn px(value: Value) -> f32 {
    match value {
        Length(f, Px) => f,
        Keyword(_) => fail!("not a length")
    }
}
<|endoftext|>


<commit_before>use core::u8;
use core::convert::{From, AsRef};

use ctx::{self, TryFromCtx};
use error;

/// A variable length integer parsing `Ctx`, compatible with the standard integer endian-aware parsing context
pub type Leb128 = ctx::DefaultCtx;

/// This context instructs the underlying `Pread` implementor to parse as a variable length integer.
///
/// It currently is just the default ctx.
pub const LEB128: Leb128 = ctx::CTX;

#[derive(Debug, PartialEq, Copy, Clone)]
/// An unsigned leb128 integer
pub struct Uleb128 {
    value: u64,
    count: usize,
}

impl Uleb128 {
    #[inline]
    pub fn size(&self) -> usize {
        self.count
    }
}

impl AsRef<u64> for Uleb128 {
    fn as_ref(&self) -> &u64 {
        &self.value
    }
}

impl From<Uleb128> for u64 {
    #[inline]
    fn from(uleb128: Uleb128) -> u64 {
        uleb128.value
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
/// An signed leb128 integer
pub struct Sleb128 {
    value: i64,
    count: usize,
}

impl Sleb128 {
    #[inline]
    pub fn size(&self) -> usize {
        self.count
    }
}

impl AsRef<i64> for Sleb128 {
    fn as_ref(&self) -> &i64 {
        &self.value
    }
}

impl From<Sleb128> for i64 {
    #[inline]
    fn from(sleb128: Sleb128) -> i64 {
        sleb128.value
    }
}

// Below implementation heavily adapted from: https://github.com/fitzgen/leb128
const CONTINUATION_BIT: u8 = 1 << 7;
const SIGN_BIT: u8 = 1 << 6;

#[inline]
fn mask_continuation(byte: u8) -> u8 {
    byte & !CONTINUATION_BIT
}

// #[inline]
// fn mask_continuation_u64(val: u64) -> u8 {
//     let byte = val & (u8::MAX as u64);
//     mask_continuation(byte as u8)
// }

impl<'a> TryFromCtx<'a, (usize, Leb128)> for Uleb128 {
    type Error = error::Error;
    #[inline]
    fn try_from_ctx(src: &'a [u8], (offset, _ctx): (usize, Leb128)) -> error::Result<Self> {
        use pread::Pread;
        let mut result = 0;
        let mut shift = 0;
        let mut count = 0;
        loop {
            let byte: u8 = src.pread(offset + count)?;

            if shift == 63 && byte != 0x00 && byte != 0x01 {
                return Err(error::Error::BadInput((offset..offset+count), src.len(), "failed to parse"))
            }

            let low_bits = mask_continuation(byte) as u64;
            result |= low_bits << shift;

            count += 1;
            shift += 7;

            if byte & CONTINUATION_BIT == 0 {
                return Ok(Uleb128 { value: result, count: count });
            }
        }
    }
}

impl<'a> TryFromCtx<'a, (usize, Leb128)> for Sleb128 {
    type Error = error::Error;
    #[inline]
    fn try_from_ctx(src: &'a [u8], (offset, _): (usize, Leb128)) -> error::Result<Self> {
        use greater::Gread;
        let o = offset;
        let offset = &mut offset.clone();
        let mut result = 0;
        let mut shift = 0;
        let size = 64;
        let mut byte: u8;
        loop {
            byte = src.gread(offset)?;

            if shift == 63 && byte != 0x00 && byte != 0x7f {
                return Err(error::Error::BadInput((o..*offset), src.len(), "failed to parse"))
            }

            let low_bits = mask_continuation(byte) as i64;
            result |= low_bits << shift;
            shift += 7;

            if byte & CONTINUATION_BIT == 0 {
                break;
            }
        }

        if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
            // Sign extend the result.
            result |= !0 << shift;
        }
        Ok(Sleb128{ value: result, count: *offset - o })
    }
}

#[cfg(test)]
mod tests {
    use super::{LEB128, Uleb128, Sleb128};
    use super::super::LE;

    #[doc(hidden)]
    const CONTINUATION_BIT: u8 = 1 << 7;
    #[doc(hidden)]
    const SIGN_BIT: u8 = 1 << 6;

    #[test]
    fn uleb_size() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT, 1];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(130u64, num.into());
        assert_eq!(num.size(), 2);

        let buf = [0x00,0x01];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(0u64, num.into());
        assert_eq!(num.size(), 1);

        let buf = [0x21];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(0x21u64, num.into());
        assert_eq!(num.size(), 1);
    }

    #[test]
    fn uleb128() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT, 1];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).expect("Should read Uleb128");
        assert_eq!(130u64, num.into());
        assert_eq!(386, bytes.pread_with::<u16>(0, LE).expect("Should read number"));
    }

    #[test]
    fn uleb128_overflow() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   1];
        let bytes = &buf[..];
        assert!(bytes.pread_with::<Uleb128>(0, LEB128).is_err());
    }

    #[test]
    fn sleb128() {
        use super::super::Pread;
        let bytes = [0x7fu8 | CONTINUATION_BIT, 0x7e];
        let num: i64 = bytes.pread::<Sleb128>(0).expect("Should read Sleb128").into();
        assert_eq!(-129, num);
    }
}
<commit_msg>leb128: add convenience read functions to Uleb128/Sleb128<commit_after>use core::u8;
use core::convert::{From, AsRef};

use ctx::{self, TryFromCtx};
use error;

/// A variable length integer parsing `Ctx`, compatible with the standard integer endian-aware parsing context
pub type Leb128 = ctx::DefaultCtx;

/// This context instructs the underlying `Pread` implementor to parse as a variable length integer.
///
/// It currently is just the default ctx.
pub const LEB128: Leb128 = ctx::CTX;

#[derive(Debug, PartialEq, Copy, Clone)]
/// An unsigned leb128 integer
pub struct Uleb128 {
    value: u64,
    count: usize,
}

impl Uleb128 {
    #[inline]
    /// Return how many bytes this Uleb128 takes up in memory
    pub fn size(&self) -> usize {
        self.count
    }
    #[inline]
    /// Read a variable length u64 from `bytes` at `offset`
    pub fn read<B: AsRef<[u8]>>(bytes: &B, offset: &mut usize) -> error::Result<u64> {
        use Pread;
        let tmp = bytes.pread::<Uleb128>(*offset)?;
        *offset = *offset + tmp.size();
        Ok(tmp.into())
    }
}

impl AsRef<u64> for Uleb128 {
    fn as_ref(&self) -> &u64 {
        &self.value
    }
}

impl From<Uleb128> for u64 {
    #[inline]
    fn from(uleb128: Uleb128) -> u64 {
        uleb128.value
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
/// An signed leb128 integer
pub struct Sleb128 {
    value: i64,
    count: usize,
}

impl Sleb128 {
    #[inline]
    /// Return how many bytes this Sleb128 takes up in memory
    pub fn size(&self) -> usize {
        self.count
    }
    #[inline]
    /// Read a variable length i64 from `bytes` at `offset`
    pub fn read<B: AsRef<[u8]>>(bytes: &B, offset: &mut usize) -> error::Result<i64> {
        use Pread;
        let tmp = bytes.pread::<Sleb128>(*offset)?;
        *offset = *offset + tmp.size();
        Ok(tmp.into())
    }
}

impl AsRef<i64> for Sleb128 {
    fn as_ref(&self) -> &i64 {
        &self.value
    }
}

impl From<Sleb128> for i64 {
    #[inline]
    fn from(sleb128: Sleb128) -> i64 {
        sleb128.value
    }
}

// Below implementation heavily adapted from: https://github.com/fitzgen/leb128
const CONTINUATION_BIT: u8 = 1 << 7;
const SIGN_BIT: u8 = 1 << 6;

#[inline]
fn mask_continuation(byte: u8) -> u8 {
    byte & !CONTINUATION_BIT
}

// #[inline]
// fn mask_continuation_u64(val: u64) -> u8 {
//     let byte = val & (u8::MAX as u64);
//     mask_continuation(byte as u8)
// }

impl<'a> TryFromCtx<'a, (usize, Leb128)> for Uleb128 {
    type Error = error::Error;
    #[inline]
    fn try_from_ctx(src: &'a [u8], (offset, _ctx): (usize, Leb128)) -> error::Result<Self> {
        use pread::Pread;
        let mut result = 0;
        let mut shift = 0;
        let mut count = 0;
        loop {
            let byte: u8 = src.pread(offset + count)?;

            if shift == 63 && byte != 0x00 && byte != 0x01 {
                return Err(error::Error::BadInput((offset..offset+count), src.len(), "failed to parse"))
            }

            let low_bits = mask_continuation(byte) as u64;
            result |= low_bits << shift;

            count += 1;
            shift += 7;

            if byte & CONTINUATION_BIT == 0 {
                return Ok(Uleb128 { value: result, count: count });
            }
        }
    }
}

impl<'a> TryFromCtx<'a, (usize, Leb128)> for Sleb128 {
    type Error = error::Error;
    #[inline]
    fn try_from_ctx(src: &'a [u8], (offset, _): (usize, Leb128)) -> error::Result<Self> {
        use greater::Gread;
        let o = offset;
        let offset = &mut offset.clone();
        let mut result = 0;
        let mut shift = 0;
        let size = 64;
        let mut byte: u8;
        loop {
            byte = src.gread(offset)?;

            if shift == 63 && byte != 0x00 && byte != 0x7f {
                return Err(error::Error::BadInput((o..*offset), src.len(), "failed to parse"))
            }

            let low_bits = mask_continuation(byte) as i64;
            result |= low_bits << shift;
            shift += 7;

            if byte & CONTINUATION_BIT == 0 {
                break;
            }
        }

        if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
            // Sign extend the result.
            result |= !0 << shift;
        }
        Ok(Sleb128{ value: result, count: *offset - o })
    }
}

#[cfg(test)]
mod tests {
    use super::{LEB128, Uleb128, Sleb128};
    use super::super::LE;

    #[doc(hidden)]
    const CONTINUATION_BIT: u8 = 1 << 7;
    #[doc(hidden)]
    const SIGN_BIT: u8 = 1 << 6;

    #[test]
    fn uleb_size() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT, 1];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(130u64, num.into());
        assert_eq!(num.size(), 2);

        let buf = [0x00,0x01];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(0u64, num.into());
        assert_eq!(num.size(), 1);

        let buf = [0x21];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).unwrap();
        println!("num: {:?}", &num);
        assert_eq!(0x21u64, num.into());
        assert_eq!(num.size(), 1);
    }

    #[test]
    fn uleb128() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT, 1];
        let bytes = &buf[..];
        let num = bytes.pread::<Uleb128>(0).expect("Should read Uleb128");
        assert_eq!(130u64, num.into());
        assert_eq!(386, bytes.pread_with::<u16>(0, LE).expect("Should read number"));
    }

    #[test]
    fn uleb128_overflow() {
        use super::super::Pread;
        let buf = [2u8 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   2 | CONTINUATION_BIT,
                   1];
        let bytes = &buf[..];
        assert!(bytes.pread_with::<Uleb128>(0, LEB128).is_err());
    }

    #[test]
    fn sleb128() {
        use super::super::Pread;
        let bytes = [0x7fu8 | CONTINUATION_BIT, 0x7e];
        let num: i64 = bytes.pread::<Sleb128>(0).expect("Should read Sleb128").into();
        assert_eq!(-129, num);
    }
}
<|endoftext|>


<commit_before>use super::errors::*;

use fuse;
use fuse::{Filesystem, Request, ReplyAttr, ReplyDirectory, ReplyEntry, FileAttr, ReplyOpen,
           ReplyData, ReplyEmpty, ReplyCreate, ReplyWrite};

use libc::{ENOSYS, ENOENT};

use time::Timespec;
use std;
use std::ffi::OsStr;
use std::fs;
use std::time::SystemTime;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::collections::HashMap;

pub struct S3HierarchicalFilesystem<'a> {
    _mount_path: &'a str,
    _backing_path: &'a str,
    ino_paths: HashMap<u64, PathBuf>,
    files: HashMap<u64, File>,
}

impl<'a> S3HierarchicalFilesystem<'a> {
    pub fn mount(mp: &str, bp: &str) -> Result<()> {
        let mut fs = S3HierarchicalFilesystem {
            _mount_path: mp,
            _backing_path: bp,
            ino_paths: HashMap::new(),
            files: HashMap::new(),
        };
        fs.ino_paths.insert(1, PathBuf::from(bp));
        fuse::mount(fs, &mp, &[]).chain_err(|| "mounting filesystem")
    }
}

fn filetype_tryfrom(ft: &fs::FileType) -> Result<fuse::FileType> {
    if ft.is_file() {
        return Ok(fuse::FileType::RegularFile);
    }
    if ft.is_dir() {
        return Ok(fuse::FileType::Directory);
    }
    if ft.is_symlink() {
        return Ok(fuse::FileType::Symlink);
    }
    bail!("unknown filetype")
}

fn timespec_from(st: &SystemTime) -> Timespec {
    if let Ok(dur_since_epoch) = st.duration_since(std::time::UNIX_EPOCH) {
        Timespec::new(dur_since_epoch.as_secs() as i64,
                      dur_since_epoch.subsec_nanos() as i32)
    } else {
        Timespec::new(0, 0)
    }
}

fn fileattr_from(m: &std::fs::Metadata) -> FileAttr {
    use std::os::unix::fs::{MetadataExt, PermissionsExt};
    use std::time::SystemTime;

    let kind = filetype_tryfrom(&m.file_type()).unwrap();
    let mode = m.permissions().mode();
    FileAttr {
        ino: m.ino(),
        size: m.len(),
        blocks: m.blocks(),
        atime: timespec_from(&m.accessed().unwrap_or(SystemTime::now())),
        mtime: timespec_from(&m.modified().unwrap_or(SystemTime::now())),
        ctime: Timespec::new(m.ctime(), m.ctime_nsec() as i32),
        crtime: timespec_from(&m.created().unwrap_or(SystemTime::now())),
        kind: kind,
        perm: mode as u16,
        nlink: m.nlink() as u32,
        uid: m.uid(),
        gid: m.gid(),
        rdev: m.rdev() as u32,
        flags: 0,
    }
}

fn dir_from(entry_opt: std::io::Result<fs::DirEntry>) -> Option<(u64, fuse::FileType, String)> {
    use std::os::unix::fs::DirEntryExt;

    let mut result = None;
    if let Ok(entry) = entry_opt {
        if let Ok(fsfiletype) = entry.file_type() {
            if let Ok(filetype) = filetype_tryfrom(&fsfiletype) {
                if let Ok(filename) = entry.file_name().into_string() {
                    result = Some((entry.ino(), filetype, filename));
                }
            }
        }
    }
    result
}

macro_rules! unwrap_or_return_error {
    ($v:expr, $log:expr, $err:expr, $reply:ident) => (
        match $v {
            Some(v) => v,
            None => {
                error!($log);
                $reply.error($err);
                return;
            }
        }
    )
}

macro_rules! ok_or_return_error {
    ($v:expr, $err:expr, $reply:ident) => (
        match $v {
            Ok(v) => v,
            Err(e) => {
                error!("{:?}", e);
                $reply.error($err);
                return;
            }
        }
    )
}

impl<'a> Filesystem for S3HierarchicalFilesystem<'a> {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        trace!("getattr(ino={})", ino);

        let path = unwrap_or_return_error!(self.ino_paths.get(&ino),
                                           "ino not found in cache",
                                           ENOENT,
                                           reply);
        let metadata = ok_or_return_error!(std::fs::metadata(path), ENOENT, reply);

        debug!("{:?}", metadata);
        let attr = fileattr_from(&metadata);
        let ttl = Timespec::new(1, 0);
        reply.attr(&ttl, &attr);
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        trace!("lookup(parent={}, name={:?})", parent, name);

        let parent_path = unwrap_or_return_error!(self.ino_paths.get(&parent),
                                                  "ino not found in cache",
                                                  ENOSYS,
                                                  reply);

        let file_name =
            unwrap_or_return_error!(name.to_str(), "unable to read name", ENOSYS, reply);

        let path = Path::new(&parent_path).join(file_name);
        debug!("Path: {:?}", path);
        match path.metadata() {
            Ok(metadata) => {
                debug!("{:?}", metadata);
                let attr = fileattr_from(&metadata);
                let ttl = Timespec::new(1, 0);
                debug!("warning: generation assumed 0");
                reply.entry(&ttl, &attr, 0);
                debug!("{:?}", attr);
            }
            Err(e) => {
                info!("std::fs::metadata: {}", e);
                reply.error(ENOENT);
            }
        };
    }

    fn readdir(&mut self,
               _req: &Request,
               ino: u64,
               fh: u64,
               offset: u64,
               mut reply: ReplyDirectory) {

        trace!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);

        let path = {
            let x = unwrap_or_return_error!(self.ino_paths.get(&ino),
                                            "ino not found in cache",
                                            ENOSYS,
                                            reply);
            x.clone()
        };

        if offset < 1 {
            reply.add(ino, 0, fuse::FileType::Directory, ".");
            reply.add(ino, 1, fuse::FileType::Directory, "..");
        };

        let rd = ok_or_return_error!(path.read_dir(), ENOENT, reply);

        for (i, entry_opt) in rd.enumerate() {
            let entry_offset = (i + 2) as u64;
            if offset >= entry_offset {
                continue;
            };
            let (ino, filetype, filename) = match dir_from(entry_opt) {
                Some(x) => x,
                None => {
                    error!("unable to extract directory entry");
                    reply.error(ENOENT);
                    return;
                }
            };
            debug!("Adding: {}, {}, {:?}, \"{}\"",
                   ino,
                   entry_offset,
                   filetype,
                   filename);
            if reply.add(ino, entry_offset, filetype, &filename) {
                break;
            }
            self.ino_paths.insert(ino, path.join(filename));
        }
        reply.ok();
    }

    fn open(&mut self, _req: &Request, ino: u64, _flags: u32, reply: ReplyOpen) {
        trace!("open(ino={}, flags={})", ino, _flags);

        let path = {
            let x = unwrap_or_return_error!(self.ino_paths.get(&ino),
                                            "ino not found in cache",
                                            ENOSYS,
                                            reply);
            x.clone()
        };

        match File::open(path) {
            Ok(f) => {
                // FIXME: race condition
                let fh: u64 = *self.files.keys().max().unwrap_or(&10u64);
                self.files.insert(fh, f);
                trace!("opened file handle: {}", fh);
                reply.opened(fh, 0);
            }
            Err(e) => {
                error!("File::open: {:?}", e);
                reply.error(e.raw_os_error().unwrap_or(ENOENT));
            }
        };
    }

    fn read(&mut self,
            _req: &Request,
            _ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        use std::io::Read;

        trace!("read(ino={}, fh={}, offset={}, size={})",
               _ino,
               fh,
               offset,
               size);

        let mut f = match self.files.get(&fh) {
            Some(f) => f,
            None => {
                error!("File handle not found: {}", fh);
                reply.error(ENOENT);
                return;
            }
        };
        debug!("File: {:?}", f);
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.resize(size as usize, 0u8);

        match f.read_exact(&mut buffer[..]) {
            Ok(_) => {
                debug!("Read: {:?}", buffer);
                reply.data(&buffer);
            }
            Err(e) => reply.error(e.raw_os_error().unwrap_or(ENOENT)),
        }
    }

    fn release(&mut self,
               _req: &Request,
               _ino: u64,
               fh: u64,
               _flags: u32,
               _lock_owner: u64,
               _flush: bool,
               reply: ReplyEmpty) {
        trace!("release(ino={}, fh={}, flags={}, lock_owner={}, flush={})",
               _ino,
               fh,
               _flags,
               _lock_owner,
               _flush);

        match self.files.remove(&fh) {
            Some(_) => {
                debug!("closed file handle: {}", fh);
                reply.ok();
            }
            None => {
                error!("File handle not found: {}", fh);
                reply.error(ENOENT);
            }
        };
    }

    fn create(&mut self,
              _req: &Request,
              parent: u64,
              name: &OsStr,
              _mode: u32,
              _flags: u32,
              reply: ReplyCreate) {
        trace!("create(parent={}, name={:?}, mode={}, flags={})",
               parent,
               name,
               _mode,
               _flags);

        let parent_path = {
            let p = unwrap_or_return_error!(self.ino_paths.get(&parent),
                                            "parent not found in cache",
                                            ENOSYS,
                                            reply);
            p.clone()
        };

        let file_name =
            unwrap_or_return_error!(name.to_str(), "unable to read name", ENOSYS, reply);

        let path = Path::new(&parent_path).join(file_name);
        debug!("Path: {:?}", &path);
        match File::create(&path) {
            Ok(f) => {
                trace!("File created");
                let fh: u64 = *self.files.keys().max().unwrap_or(&10u64);
                self.files.insert(fh, f);
                match path.metadata() {
                    Ok(metadata) => {
                        let attr = fileattr_from(&metadata);
                        self.ino_paths.insert(attr.ino, path);
                        let ttl = Timespec::new(1, 0);
                        reply.created(&ttl, &attr, 0, fh, 0);
                    }
                    Err(e) => {
                        error!("std::fs::metadata: {}", e);
                        reply.error(e.raw_os_error().unwrap_or(ENOENT));
                    }
                }
            }
            Err(e) => {
                error!("File::create: {:?}", e);
                reply.error(e.raw_os_error().unwrap_or(ENOENT));
            }
        }
    }

    fn write(&mut self,
             _req: &Request,
             _ino: u64,
             _fh: u64,
             _offset: u64,
             _data: &[u8],
             _flags: u32,
             reply: ReplyWrite) {

        // use std::io::Write;

        trace!("write(ino={}, fh={}, offset={}, data={:?}, flags={})",
               _ino,
               _fh,
               _offset,
               _data,
               _flags);

        reply.error(ENOSYS);
    }
}
<commit_msg>subdirs<commit_after>use super::errors::*;

use fuse;
use fuse::{Filesystem, Request, ReplyAttr, ReplyDirectory, ReplyEntry, FileAttr, ReplyOpen,
           ReplyData, ReplyEmpty, ReplyCreate, ReplyWrite};

use libc::{ENOSYS, ENOENT};

use time::Timespec;
use std;
use std::ffi::OsStr;
use std::fs;
use std::time::SystemTime;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::collections::HashMap;

pub struct S3HierarchicalFilesystem<'a> {
    _mount_path: &'a str,
    _backing_path: &'a str,
    ino_paths: HashMap<u64, PathBuf>,
    files: HashMap<u64, File>,
}

impl<'a> S3HierarchicalFilesystem<'a> {
    pub fn mount(mp: &str, bp: &str) -> Result<()> {
        let mut fs = S3HierarchicalFilesystem {
            _mount_path: mp,
            _backing_path: bp,
            ino_paths: HashMap::new(),
            files: HashMap::new(),
        };
        fs.ino_paths.insert(1, PathBuf::from(bp));
        fuse::mount(fs, &mp, &[]).chain_err(|| "mounting filesystem")
    }
}

fn filetype_tryfrom(ft: &fs::FileType) -> Result<fuse::FileType> {
    if ft.is_file() {
        return Ok(fuse::FileType::RegularFile);
    }
    if ft.is_dir() {
        return Ok(fuse::FileType::Directory);
    }
    if ft.is_symlink() {
        return Ok(fuse::FileType::Symlink);
    }
    bail!("unknown filetype")
}

fn timespec_from(st: &SystemTime) -> Timespec {
    if let Ok(dur_since_epoch) = st.duration_since(std::time::UNIX_EPOCH) {
        Timespec::new(dur_since_epoch.as_secs() as i64,
                      dur_since_epoch.subsec_nanos() as i32)
    } else {
        Timespec::new(0, 0)
    }
}

fn fileattr_from(m: &std::fs::Metadata) -> FileAttr {
    use std::os::unix::fs::{MetadataExt, PermissionsExt};
    use std::time::SystemTime;

    let kind = filetype_tryfrom(&m.file_type()).unwrap();
    let mode = m.permissions().mode();
    FileAttr {
        ino: m.ino(),
        size: m.len(),
        blocks: m.blocks(),
        atime: timespec_from(&m.accessed().unwrap_or(SystemTime::now())),
        mtime: timespec_from(&m.modified().unwrap_or(SystemTime::now())),
        ctime: Timespec::new(m.ctime(), m.ctime_nsec() as i32),
        crtime: timespec_from(&m.created().unwrap_or(SystemTime::now())),
        kind: kind,
        perm: mode as u16,
        nlink: m.nlink() as u32,
        uid: m.uid(),
        gid: m.gid(),
        rdev: m.rdev() as u32,
        flags: 0,
    }
}

fn dir_from(entry_opt: std::io::Result<fs::DirEntry>) -> Option<(u64, fuse::FileType, String)> {
    use std::os::unix::fs::DirEntryExt;

    let mut result = None;
    if let Ok(entry) = entry_opt {
        if let Ok(fsfiletype) = entry.file_type() {
            if let Ok(filetype) = filetype_tryfrom(&fsfiletype) {
                if let Ok(filename) = entry.file_name().into_string() {
                    result = Some((entry.ino(), filetype, filename));
                }
            }
        }
    }
    result
}

macro_rules! ino_path_or_return {
    ($self:ident, $parent:expr, $reply:ident) => ({
        let path = match $self.ino_paths.get($parent) {
            Some(p) => p,
            None => {
                error!("parent not found in cache");
                $reply.error(ENOSYS);
                return;
            }
        };
        path.clone()
    })
}

macro_rules! full_path_or_return {
    ($self:ident, $parent:expr, $name:expr, $reply:ident) => ({
        let parent_path = match $self.ino_paths.get($parent) {
            Some(p) => p,
            None => {
                error!("parent not found in cache");
                $reply.error(ENOSYS);
                return;
            }
        };
        let new_name = match $name.to_str() {
            Some(p) => p,
            None => {
                error!("unable to read name");
                $reply.error(ENOSYS);
                return;
            }
        };
        Path::new(&parent_path).join(new_name).clone()
    })
}

macro_rules! file_handle_or_return {
    ($self:ident, $fh:expr, $reply:ident) => (
        match $self.files.get($fh) {
            Some(f) => f,
            None => {
                error!("File handle not found: {}", $fh);
                $reply.error(ENOENT);
                return;
            }
        }
    )
}

macro_rules! ok_or_return_error {
    ($v:expr, $err:expr, $reply:ident) => (
        match $v {
            Ok(v) => v,
            Err(e) => {
                error!("{:?}", e);
                $reply.error($err);
                return;
            }
        }
    )
}

impl<'a> Filesystem for S3HierarchicalFilesystem<'a> {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        trace!("getattr(ino={})", ino);

        let path = ino_path_or_return!(self, &ino, reply);
        let metadata = ok_or_return_error!(std::fs::metadata(path), ENOENT, reply);

        debug!("{:?}", metadata);
        let attr = fileattr_from(&metadata);
        let ttl = Timespec::new(1, 0);
        reply.attr(&ttl, &attr);
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        trace!("lookup(parent={}, name={:?})", parent, name);

        let path = full_path_or_return!(self, &parent, name, reply);

        match path.metadata() {
            Ok(metadata) => {
                debug!("{:?}", metadata);
                let attr = fileattr_from(&metadata);
                let ttl = Timespec::new(1, 0);
                debug!("warning: generation assumed 0");
                reply.entry(&ttl, &attr, 0);
                debug!("{:?}", attr);
            }
            Err(e) => {
                info!("std::fs::metadata: {}", e);
                reply.error(ENOENT);
            }
        };
    }

    fn readdir(&mut self,
               _req: &Request,
               ino: u64,
               fh: u64,
               offset: u64,
               mut reply: ReplyDirectory) {

        trace!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);

        let path: PathBuf = ino_path_or_return!(self, &ino, reply);

        if offset < 1 {
            reply.add(ino, 0, fuse::FileType::Directory, ".");
            reply.add(ino, 1, fuse::FileType::Directory, "..");
        };

        let rd = ok_or_return_error!(path.read_dir(), ENOENT, reply);

        for (i, entry_opt) in rd.enumerate() {
            let entry_offset = (i + 2) as u64;
            if offset >= entry_offset {
                continue;
            };
            let (ino, filetype, filename) = match dir_from(entry_opt) {
                Some(x) => x,
                None => {
                    error!("unable to extract directory entry");
                    reply.error(ENOENT);
                    return;
                }
            };
            debug!("Adding: {}, {}, {:?}, \"{}\"",
                   ino,
                   entry_offset,
                   filetype,
                   filename);
            if reply.add(ino, entry_offset, filetype, &filename) {
                break;
            }
            self.ino_paths.insert(ino, path.join(filename));
        }
        reply.ok();
    }

    fn open(&mut self, _req: &Request, ino: u64, _flags: u32, reply: ReplyOpen) {
        trace!("open(ino={}, flags={})", ino, _flags);

        let path = ino_path_or_return!(self, &ino, reply);

        match File::open(path) {
            Ok(f) => {
                // FIXME: race condition
                let fh: u64 = *self.files.keys().max().unwrap_or(&10u64) + 1;
                self.files.insert(fh, f);
                trace!("opened file handle: {}", fh);
                reply.opened(fh, 0);
            }
            Err(e) => {
                error!("File::open: {:?}", e);
                reply.error(e.raw_os_error().unwrap_or(ENOENT));
            }
        };
    }

    fn read(&mut self,
            _req: &Request,
            _ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        use std::io::Read;

        trace!("read(ino={}, fh={}, offset={}, size={})",
               _ino,
               fh,
               offset,
               size);

        let mut f = file_handle_or_return!(self, &fh, reply);
        debug!("File: {:?}", f);

        let mut buffer = Vec::with_capacity(size as usize);
        buffer.resize(size as usize, 0u8);

        match f.read_exact(&mut buffer[..]) {
            Ok(_) => {
                debug!("Read {} bytes", size);
                reply.data(&buffer);
            }
            Err(e) => reply.error(e.raw_os_error().unwrap_or(ENOENT)),
        }
    }

    fn release(&mut self,
               _req: &Request,
               _ino: u64,
               fh: u64,
               _flags: u32,
               _lock_owner: u64,
               _flush: bool,
               reply: ReplyEmpty) {
        trace!("release(ino={}, fh={}, flags={}, lock_owner={}, flush={})",
               _ino,
               fh,
               _flags,
               _lock_owner,
               _flush);

        match self.files.remove(&fh) {
            Some(_) => {
                debug!("closed file handle: {}", fh);
                reply.ok();
            }
            None => {
                error!("File handle not found: {}", fh);
                reply.error(ENOENT);
            }
        };
    }

    fn create(&mut self,
              _req: &Request,
              parent: u64,
              name: &OsStr,
              _mode: u32,
              _flags: u32,
              reply: ReplyCreate) {
        trace!("create(parent={}, name={:?}, mode={}, flags={})",
               parent,
               name,
               _mode,
               _flags);

        let path = full_path_or_return!(self, &parent, name, reply);

        match File::create(&path) {
            Ok(f) => {
                trace!("File created: {:?}", f);
                let fh: u64 = *self.files.keys().max().unwrap_or(&10u64) + 1;
                debug!("Handle: {}", fh);
                self.files.insert(fh, f);
                match path.metadata() {
                    Ok(metadata) => {
                        let attr = fileattr_from(&metadata);
                        self.ino_paths.insert(attr.ino, path);
                        let ttl = Timespec::new(1, 0);
                        reply.created(&ttl, &attr, 0, fh, 0);
                    }
                    Err(e) => {
                        error!("std::fs::metadata: {}", e);
                        reply.error(e.raw_os_error().unwrap_or(ENOENT));
                    }
                }
            }
            Err(e) => {
                error!("File::create: {:?}", e);
                reply.error(e.raw_os_error().unwrap_or(ENOENT));
            }
        }
    }

    fn write(&mut self,
             _req: &Request,
             _ino: u64,
             fh: u64,
             offset: u64,
             data: &[u8],
             _flags: u32,
             reply: ReplyWrite) {

        use std::io::{Seek, SeekFrom, Write};

        trace!("write(ino={}, fh={}, offset={}, data={:?}, flags={})",
               _ino,
               fh,
               offset,
               data,
               _flags);

        let mut f = file_handle_or_return!(self, &fh, reply);
        debug!("File: {:?}", f);

        if let Err(e) = f.seek(SeekFrom::Start(offset)) {
            error!("Unable to seek to position: {}", offset);
            reply.error(e.raw_os_error().unwrap_or(ENOENT));
            return;
        }

        match f.write(&data) {
            Ok(size) => {
                debug!("Written {} bytes", size);
                reply.written(size as u32);
            }
            Err(e) => reply.error(e.raw_os_error().unwrap_or(ENOENT)),
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &OsStr, _mode: u32, reply: ReplyEntry) {
        trace!("mkdir(parent={}, name={:?}, mode={})", parent, name, _mode);

        let path = full_path_or_return!(self, &parent, name, reply);

        match fs::create_dir(&path) {
            Ok(()) => {
                trace!("Subdir created");
                match path.metadata() {
                    Ok(metadata) => {
                        let attr = fileattr_from(&metadata);
                        self.ino_paths.insert(attr.ino, path);
                        let ttl = Timespec::new(1, 0);
                        reply.entry(&ttl, &attr, 0);
                    }
                    Err(e) => {
                        error!("std::fs::metadata: {}", e);
                        reply.error(e.raw_os_error().unwrap_or(ENOENT));
                    }
                }
            }
            Err(e) => reply.error(e.raw_os_error().unwrap_or(ENOENT)),
        }
    }
}
<|endoftext|>