<commit_before>/// Contains all functionality pertaining to parsing, tokenizing, and generating input arguments.
pub mod errors;
mod jobs;
mod man;
mod quote;

use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader};
use std::path::Path;
use std::process::exit;
use permutate::Permutator;
use num_cpus;

use super::disk_buffer::{self, DiskBufferTrait};
use super::filepaths;
use super::input_iterator::InputIterator;
use super::tokenizer::{Token, tokenize};
use self::errors::ParseErr;

// Re-export key items from internal modules.
pub use self::errors::{FileErr, InputIteratorErr};

#[derive(PartialEq)]
enum Mode { Arguments, Command, Inputs, Files }

#[derive(Clone)]
pub struct Flags {
    pub inputs_are_commands: bool,
    pub pipe:                bool,
    pub uses_shell:          bool,
    pub quiet:               bool,
    pub verbose:             bool
}

impl Flags {
    fn new() -> Flags {
        Flags {
            inputs_are_commands: false,
            uses_shell: true,
            quiet: false,
            verbose: false,
            pipe: false,
        }
    }
}

/// Defines what quoting mode to use when expanding the command.
enum Quoting { None, Basic, Shell }

/// `Args` is a collection of critical options and arguments that were collected at
/// startup of the application.
pub struct Args {
    pub flags:        Flags,
    pub ncores:       usize,
    pub arguments:    Vec<Token>,
    pub piped_values: Option<Vec<String>>,
    pub ninputs:      usize,
}

impl Args {
    pub fn new() -> Args {
        Args {
            ncores:       num_cpus::get(),
            flags:        Flags::new(),
            arguments:    Vec::new(),
            piped_values: None,
            ninputs:      0,
        }
    }

    pub fn parse(&mut self) -> Result<InputIterator, ParseErr> {
        let unprocessed_path = match filepaths::unprocessed() {
            Some(path) => path,
            None => return Err(ParseErr::File(FileErr::Path))
        };

        let mut quote = Quoting::None;

        // Create a write buffer that automatically writes data to the disk when the buffer is full.
        let mut disk_buffer = disk_buffer::DiskBuffer::new(&unprocessed_path).write()
            .map_err(|why| ParseErr::File(FileErr::Open(unprocessed_path.clone(), why)))?;

        // Temporary stores for input arguments.
        let mut raw_args                    = env::args().skip(1).peekable();
        let mut comm                        = String::with_capacity(128);
        let mut lists: Vec<Vec<String>>     = Vec::new();
        let mut current_inputs: Vec<String> = Vec::new();

        // The purpose of this is to set the initial parsing mode.
        let mut mode = match raw_args.peek().ok_or(ParseErr::NoArguments)?.as_ref() {
            ":::"  => Mode::Inputs,
            "::::" => Mode::Files,
            _      => Mode::Arguments
        };

        // If there are no arguments to be parsed, then the inputs are commands.
        self.flags.inputs_are_commands = mode == Mode::Inputs || mode == Mode::Files;

        // Parse each and every input argument supplied to the program.
        while let Some(argument) = raw_args.next() {
            let argument = argument.as_str();
            match mode {
                Mode::Arguments => {
                    let mut char_iter = argument.chars().peekable();

                    // If the first character is a '-' then it will be processed as an argument.
                    // We can guarantee that there will always be at least one character.
                    if char_iter.next().unwrap() == '-' {
                        // If the second character exists, everything's OK.
                        if let Some(character) = char_iter.next() {
                            // This scope of code allows users to utilize the GNU style
                            // command line arguments, to allow for laziness.
                            if character == 'j' {
                                // The short-hand job argument needs to be handled specially.
                                self.ncores = if char_iter.peek().is_some() {
                                    // Each character that follows after `j` will be considered an
                                    // input value.
                                    jobs::parse(&argument[2..])?
                                } else {
                                    // If there was no character after `j`, the following argument
                                    // must be the job value.
                                    let val = &raw_args.next().ok_or(ParseErr::JobsNoValue)?;
                                    jobs::parse(val)?
                                }
                            } else if character != '-' {
                                // NOTE: Short mode versions of arguments
                                for character in argument[1..].chars() {
                                    match character {
                                        'h' => {
                                            println!("{}", man::MAN_PAGE);
                                            exit(0);
                                        },
                                        'n' => self.flags.uses_shell = false,
                                        'p' => self.flags.pipe = true,
                                        'q' => quote = Quoting::Basic,
                                        's' => self.flags.quiet = true,
                                        'v' => self.flags.verbose = true,
                                        _ => {
                                            return Err(ParseErr::InvalidArgument(argument.to_owned()))
                                        }
                                    }
                                }
                            } else {
                                // NOTE: Long mode versions of arguments
                                match &argument[2..] {
                                    "help" => {
                                        println!("{}", man::MAN_PAGE);
                                        exit(0);
                                    },
                                    "jobs" => {
                                        let val = &raw_args.next().ok_or(ParseErr::JobsNoValue)?;
                                        self.ncores = jobs::parse(val)?
                                    },
                                    "no-shell" => self.flags.uses_shell = false,
                                    "num-cpu-cores" => {
                                        println!("{}", num_cpus::get());
                                        exit(0);
                                    },
                                    "pipe" => self.flags.pipe = true,
                                    "quiet" | "silent" => self.flags.quiet = true,
                                    "quote" => quote = Quoting::Basic,
                                    "shellquote" => quote = Quoting::Shell,
                                    "verbose" => self.flags.verbose = true,
                                    "version" => {
                                        println!("parallel 0.6.2\n\nCrate Dependencies:");
                                        println!("    libc      0.2.15");
                                        println!("    num_cpus  1.0.0");
                                        println!("    permutate 0.1.3");
                                        exit(0);
                                    }
                                    _ => {
                                        return Err(ParseErr::InvalidArgument(argument.to_owned()));
                                    }
                                }
                            }
                        } else {
                            // `-` will never be a valid argument
                            return Err(ParseErr::InvalidArgument("-".to_owned()));
                        }
                    } else {
                        match argument {
                            ":::" => {
                                mode = Mode::Inputs;
                                self.flags.inputs_are_commands = true;
                            },
                            "::::" => {
                                mode = Mode::Files;
                                self.flags.inputs_are_commands = true;
                            }
                            _ => {
                                // The command has been supplied, and argument parsing is over.
                                comm.push_str(argument);
                                mode = Mode::Command;
                            }
                        }
                    }
                },
                Mode::Command => match argument {
                    // Arguments after `:::` are input values.
                    ":::" | ":::+" => mode = Mode::Inputs,
                    // Arguments after `::::` are files with inputs.
                    "::::" | "::::+" => mode = Mode::Files,
                    // All other arguments are command arguments.
                    _ => {
                        comm.push(' ');
                        comm.push_str(argument);
                    }
                },
                _ => match argument {
                    // `:::` denotes that the next set of inputs will be added to a new list.
                    ":::"  => {
                        mode = Mode::Inputs;
                        if !current_inputs.is_empty() {
                            lists.push(current_inputs.clone());
                            current_inputs.clear();
                        }
                    },
                    // `:::+` denotes that the next set of inputs will be added to the current list.
                    ":::+" => mode = Mode::Inputs,
                    // `::::` denotes that the next set of inputs will be added to a new list.
                    "::::"  => {
                        mode = Mode::Files;
                        if !current_inputs.is_empty() {
                            lists.push(current_inputs.clone());
                            current_inputs.clear();
                        }
                    },
                    // `:::+` denotes that the next set of inputs will be added to the current list.
                    "::::+" => mode = Mode::Files,
                    // All other arguments will be added to the current list.
                    _ => match mode {
                        Mode::Inputs => current_inputs.push(argument.to_owned()),
                        Mode::Files => file_parse(&mut current_inputs, argument)?,
                        _ => unreachable!()
                    }
                }
            }
        }

        if !current_inputs.is_empty() {
            lists.push(current_inputs.clone());
        }

        let mut number_of_arguments = 0;

        if lists.len() > 1 {
            // Convert the Vec<Vec<String>> into a Vec<Vec<&str>>
            let tmp: Vec<Vec<&str>> = lists.iter()
                .map(|list| list.iter().map(AsRef::as_ref).collect::<Vec<&str>>())
                .collect();

            // Convert the Vec<Vec<&str>> into a Vec<&[&str]>
            let list_array: Vec<&[&str]> = tmp.iter().map(AsRef::as_ref).collect();

            // Create a `Permutator` with the &[&[&str]] as the input.
            let permutator = Permutator::new(&list_array[..]);

            for permutation in permutator {
                let mut iter = permutation.iter();
                disk_buffer.write(iter.next().unwrap().as_bytes())
                    .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                for element in iter {
                    disk_buffer.write_byte(b' ')
                        .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    disk_buffer.write(element.as_bytes())
                        .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                }
                disk_buffer.write_byte(b'\n')
                    .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                number_of_arguments += 1;
            }
        } else {
            for input in current_inputs {
                disk_buffer.write(input.as_bytes()).map_err(|why|
                    ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                disk_buffer.write_byte(b'\n').map_err(|why|
                    ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                number_of_arguments += 1;
            }
        }

        // If no inputs are provided, read from stdin instead.
        if disk_buffer.is_empty() {
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                if let Ok(line) = line {
                    disk_buffer.write(line.as_bytes()).map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    disk_buffer.write_byte(b'\n').map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    number_of_arguments += 1;
                }
            }
        }

        // Flush the contents of the buffer to the disk before tokenizing the command argument.
        disk_buffer.flush().map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;

        // Expand the command if quoting is enabled
        match quote {
            Quoting::None  => (),
            Quoting::Basic => comm = quote::basic(comm),
            Quoting::Shell => comm = quote::shell(comm),
        }

        // Attempt to tokenize the command argument into simple primitive placeholders.
        tokenize(&mut self.arguments, &comm, &unprocessed_path, number_of_arguments).map_err(ParseErr::Token)?;

        // Return an `InputIterator` of the arguments contained within the unprocessed file.
        let path = filepaths::unprocessed().ok_or(ParseErr::File(FileErr::Path))?;
        Ok(InputIterator::new(&path, number_of_arguments).map_err(ParseErr::File)?)
    }
}

/// Attempts to open an input argument and adds each line to the `inputs` list.
fn file_parse<P: AsRef<Path>>(inputs: &mut Vec<String>, path: P) -> Result<(), ParseErr> {
    let path = path.as_ref();
    let file = fs::File::open(path).map_err(|err| ParseErr::File(FileErr::Open(path.to_owned(), err)))?;
    for line in BufReader::new(file).lines() {
        if let Ok(line) = line { inputs.push(line); }
    }
    Ok(())
}
<commit_msg>Allow supplying commands via stdin<commit_after>/// Contains all functionality pertaining to parsing, tokenizing, and generating input arguments.
pub mod errors;
mod jobs;
mod man;
mod quote;

use std::env;
use std::fs;
use std::io::{self, BufRead, BufReader};
use std::path::Path;
use std::process::exit;
use permutate::Permutator;
use num_cpus;

use super::disk_buffer::{self, DiskBufferTrait};
use super::filepaths;
use super::input_iterator::InputIterator;
use super::tokenizer::{Token, tokenize};
use self::errors::ParseErr;

// Re-export key items from internal modules.
pub use self::errors::{FileErr, InputIteratorErr};

#[derive(PartialEq)]
enum Mode { Arguments, Command, Inputs, Files }

#[derive(Clone)]
pub struct Flags {
    pub inputs_are_commands: bool,
    pub pipe:                bool,
    pub uses_shell:          bool,
    pub quiet:               bool,
    pub verbose:             bool
}

impl Flags {
    fn new() -> Flags {
        Flags {
            inputs_are_commands: false,
            uses_shell: true,
            quiet: false,
            verbose: false,
            pipe: false,
        }
    }
}

/// Defines what quoting mode to use when expanding the command.
enum Quoting { None, Basic, Shell }

/// `Args` is a collection of critical options and arguments that were collected at
/// startup of the application.
pub struct Args {
    pub flags:        Flags,
    pub ncores:       usize,
    pub arguments:    Vec<Token>,
    pub piped_values: Option<Vec<String>>,
    pub ninputs:      usize,
}

impl Args {
    pub fn new() -> Args {
        Args {
            ncores:       num_cpus::get(),
            flags:        Flags::new(),
            arguments:    Vec::new(),
            piped_values: None,
            ninputs:      0,
        }
    }

    pub fn parse(&mut self) -> Result<InputIterator, ParseErr> {
        let unprocessed_path = match filepaths::unprocessed() {
            Some(path) => path,
            None => return Err(ParseErr::File(FileErr::Path))
        };

        let mut quote = Quoting::None;

        // Create a write buffer that automatically writes data to the disk when the buffer is full.
        let mut disk_buffer = disk_buffer::DiskBuffer::new(&unprocessed_path).write()
            .map_err(|why| ParseErr::File(FileErr::Open(unprocessed_path.clone(), why)))?;

        // Temporary stores for input arguments.
        let mut raw_args                    = env::args().skip(1).peekable();
        let mut comm                        = String::with_capacity(128);
        let mut lists: Vec<Vec<String>>     = Vec::new();
        let mut current_inputs: Vec<String> = Vec::new();
        let mut number_of_arguments = 0;

        if env::args().len() > 1 {
            // The purpose of this is to set the initial parsing mode.
            let mut mode = match raw_args.peek().unwrap().as_ref() {
                ":::"  => Mode::Inputs,
                "::::" => Mode::Files,
                _      => Mode::Arguments
            };

            // If there are no arguments to be parsed, then the inputs are commands.
            self.flags.inputs_are_commands = mode == Mode::Inputs || mode == Mode::Files;

            // Parse each and every input argument supplied to the program.
            while let Some(argument) = raw_args.next() {
                let argument = argument.as_str();
                match mode {
                    Mode::Arguments => {
                        let mut char_iter = argument.chars().peekable();

                        // If the first character is a '-' then it will be processed as an argument.
                        // We can guarantee that there will always be at least one character.
                        if char_iter.next().unwrap() == '-' {
                            // If the second character exists, everything's OK.
                            if let Some(character) = char_iter.next() {
                                // This scope of code allows users to utilize the GNU style
                                // command line arguments, to allow for laziness.
                                if character == 'j' {
                                    // The short-hand job argument needs to be handled specially.
                                    self.ncores = if char_iter.peek().is_some() {
                                        // Each character that follows after `j` will be considered an
                                        // input value.
                                        jobs::parse(&argument[2..])?
                                    } else {
                                        // If there was no character after `j`, the following argument
                                        // must be the job value.
                                        let val = &raw_args.next().ok_or(ParseErr::JobsNoValue)?;
                                        jobs::parse(val)?
                                    }
                                } else if character != '-' {
                                    // NOTE: Short mode versions of arguments
                                    for character in argument[1..].chars() {
                                        match character {
                                            'h' => {
                                                println!("{}", man::MAN_PAGE);
                                                exit(0);
                                            },
                                            'n' => self.flags.uses_shell = false,
                                            'p' => self.flags.pipe = true,
                                            'q' => quote = Quoting::Basic,
                                            's' => self.flags.quiet = true,
                                            'v' => self.flags.verbose = true,
                                            _ => {
                                                return Err(ParseErr::InvalidArgument(argument.to_owned()))
                                            }
                                        }
                                    }
                                } else {
                                    // NOTE: Long mode versions of arguments
                                    match &argument[2..] {
                                        "help" => {
                                            println!("{}", man::MAN_PAGE);
                                            exit(0);
                                        },
                                        "jobs" => {
                                            let val = &raw_args.next().ok_or(ParseErr::JobsNoValue)?;
                                            self.ncores = jobs::parse(val)?
                                        },
                                        "no-shell" => self.flags.uses_shell = false,
                                        "num-cpu-cores" => {
                                            println!("{}", num_cpus::get());
                                            exit(0);
                                        },
                                        "pipe" => self.flags.pipe = true,
                                        "quiet" | "silent" => self.flags.quiet = true,
                                        "quote" => quote = Quoting::Basic,
                                        "shellquote" => quote = Quoting::Shell,
                                        "verbose" => self.flags.verbose = true,
                                        "version" => {
                                            println!("parallel 0.6.2\n\nCrate Dependencies:");
                                            println!("    libc      0.2.15");
                                            println!("    num_cpus  1.0.0");
                                            println!("    permutate 0.1.3");
                                            exit(0);
                                        }
                                        _ => {
                                            return Err(ParseErr::InvalidArgument(argument.to_owned()));
                                        }
                                    }
                                }
                            } else {
                                // `-` will never be a valid argument
                                return Err(ParseErr::InvalidArgument("-".to_owned()));
                            }
                        } else {
                            match argument {
                                ":::" => {
                                    mode = Mode::Inputs;
                                    self.flags.inputs_are_commands = true;
                                },
                                "::::" => {
                                    mode = Mode::Files;
                                    self.flags.inputs_are_commands = true;
                                }
                                _ => {
                                    // The command has been supplied, and argument parsing is over.
                                    comm.push_str(argument);
                                    mode = Mode::Command;
                                }
                            }
                        }
                    },
                    Mode::Command => match argument {
                        // Arguments after `:::` are input values.
                        ":::" | ":::+" => mode = Mode::Inputs,
                        // Arguments after `::::` are files with inputs.
                        "::::" | "::::+" => mode = Mode::Files,
                        // All other arguments are command arguments.
                        _ => {
                            comm.push(' ');
                            comm.push_str(argument);
                        }
                    },
                    _ => match argument {
                        // `:::` denotes that the next set of inputs will be added to a new list.
                        ":::"  => {
                            mode = Mode::Inputs;
                            if !current_inputs.is_empty() {
                                lists.push(current_inputs.clone());
                                current_inputs.clear();
                            }
                        },
                        // `:::+` denotes that the next set of inputs will be added to the current list.
                        ":::+" => mode = Mode::Inputs,
                        // `::::` denotes that the next set of inputs will be added to a new list.
                        "::::"  => {
                            mode = Mode::Files;
                            if !current_inputs.is_empty() {
                                lists.push(current_inputs.clone());
                                current_inputs.clear();
                            }
                        },
                        // `:::+` denotes that the next set of inputs will be added to the current list.
                        "::::+" => mode = Mode::Files,
                        // All other arguments will be added to the current list.
                        _ => match mode {
                            Mode::Inputs => current_inputs.push(argument.to_owned()),
                            Mode::Files => file_parse(&mut current_inputs, argument)?,
                            _ => unreachable!()
                        }
                    }
                }
            }

            if !current_inputs.is_empty() {
                lists.push(current_inputs.clone());
            }

            if lists.len() > 1 {
                // Convert the Vec<Vec<String>> into a Vec<Vec<&str>>
                let tmp: Vec<Vec<&str>> = lists.iter()
                    .map(|list| list.iter().map(AsRef::as_ref).collect::<Vec<&str>>())
                    .collect();

                // Convert the Vec<Vec<&str>> into a Vec<&[&str]>
                let list_array: Vec<&[&str]> = tmp.iter().map(AsRef::as_ref).collect();

                // Create a `Permutator` with the &[&[&str]] as the input.
                let permutator = Permutator::new(&list_array[..]);

                for permutation in permutator {
                    let mut iter = permutation.iter();
                    disk_buffer.write(iter.next().unwrap().as_bytes())
                        .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    for element in iter {
                        disk_buffer.write_byte(b' ')
                            .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                        disk_buffer.write(element.as_bytes())
                            .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    }
                    disk_buffer.write_byte(b'\n')
                        .map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    number_of_arguments += 1;
                }
            } else {
                for input in current_inputs {
                    disk_buffer.write(input.as_bytes()).map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    disk_buffer.write_byte(b'\n').map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    number_of_arguments += 1;
                }
            }
        }

        // If no inputs are provided, read from stdin instead.
        if disk_buffer.is_empty() {
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                if let Ok(line) = line {
                    disk_buffer.write(line.as_bytes()).map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    disk_buffer.write_byte(b'\n').map_err(|why|
                        ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;
                    number_of_arguments += 1;
                }
            }
        }

        if number_of_arguments == 0 { return Err(ParseErr::NoArguments); }

        // Flush the contents of the buffer to the disk before tokenizing the command argument.
        disk_buffer.flush().map_err(|why| ParseErr::File(FileErr::Write(disk_buffer.path.clone(), why)))?;

        // Expand the command if quoting is enabled
        match quote {
            Quoting::None  => (),
            Quoting::Basic => comm = quote::basic(comm),
            Quoting::Shell => comm = quote::shell(comm),
        }

        // Attempt to tokenize the command argument into simple primitive placeholders.
        tokenize(&mut self.arguments, &comm, &unprocessed_path, number_of_arguments).map_err(ParseErr::Token)?;

        // Return an `InputIterator` of the arguments contained within the unprocessed file.
        let path = filepaths::unprocessed().ok_or(ParseErr::File(FileErr::Path))?;
        Ok(InputIterator::new(&path, number_of_arguments).map_err(ParseErr::File)?)
    }
}

/// Attempts to open an input argument and adds each line to the `inputs` list.
fn file_parse<P: AsRef<Path>>(inputs: &mut Vec<String>, path: P) -> Result<(), ParseErr> {
    let path = path.as_ref();
    let file = fs::File::open(path).map_err(|err| ParseErr::File(FileErr::Open(path.to_owned(), err)))?;
    for line in BufReader::new(file).lines() {
        if let Ok(line) = line { inputs.push(line); }
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! Content interface
use std::fmt;
use std::ops;

use data_encoding::BASE64;
use serde::de::{self, Visitor};
use serde::{Deserialize, Serialize};

use crate::repo_commits::CommitDetails;
use crate::utils::{percent_encode, PATH};
use crate::{Future, Github, Stream};

/// Provides access to the content information for a repository
pub struct Content {
    github: Github,
    owner: String,
    repo: String,
}

impl Content {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Content {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, location: &str) -> String {
        // Handle files with spaces and other characters that can mess up the
        // final URL.
        let location = percent_encode(location.as_ref(), PATH);
        format!("/repos/{}/{}/contents{}", self.owner, self.repo, location)
    }

    /// Gets the contents of the location. This could be a file, symlink, or
    /// submodule. To list the contents of a directory, use `iter`.
    pub fn get(&self, location: &str) -> Future<Contents> {
        self.github.get(&self.path(location))
    }

    /// Information on a single file.
    ///
    /// GitHub only supports downloading files up to 1 megabyte in size. If you
    /// need to retrieve larger files, the Git Data API must be used instead.
    pub fn file(&self, location: &str) -> Future<File> {
        self.github.get(&self.path(location))
    }

    /// List the root directory.
    pub fn root(&self) -> Stream<DirectoryItem> {
        self.iter("/")
    }

    /// Provides a stream over the directory items in `location`.
    ///
    /// GitHub limits the number of items returned to 1000 for this API. If you
    /// need to retrieve more items, the Git Data API must be used instead.
    pub fn iter(&self, location: &str) -> Stream<DirectoryItem> {
        self.github.get_stream(&self.path(location))
    }

    /// Creates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn create(&self, location: &str, content: &str, message: &str) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(&content.to_string().into_bytes()),
            message: message.to_string(),
            sha: None,
        };
        self.github.put(&self.path(location), json!(file))
    }

    /// Updates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn update(
        &self,
        location: &str,
        content: &str,
        message: &str,
        sha: &str,
    ) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(&content.to_string().into_bytes()),
            message: message.to_string(),
            sha: Some(sha.to_string()),
        };
        self.github.put(&self.path(location), json!(file))
    }
}

/// Contents of a path in a repository.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Contents {
    File(File),
    Symlink(Symlink),
    Submodule(Submodule),
}

/// The type of content encoding.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Encoding {
    Base64,
    // Are there actually any other encoding types?
}

#[derive(Debug, Serialize)]
pub struct NewFile {
    pub content: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sha: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct NewFileResponse {
    pub commit: CommitDetails,
}

#[derive(Debug, Deserialize)]
pub struct File {
    pub encoding: Encoding,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub content: DecodedContents,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct DirectoryItem {
    #[serde(rename = "type")]
    pub _type: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Symlink {
    pub target: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Submodule {
    pub submodule_git_url: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Links {
    pub git: String,
    #[serde(rename = "self")]
    pub _self: String,
    pub html: String,
}

/// Decoded file contents.
#[derive(Debug)]
pub struct DecodedContents(Vec<u8>);

impl Into<Vec<u8>> for DecodedContents {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl AsRef<[u8]> for DecodedContents {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl ops::Deref for DecodedContents {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'de> Deserialize<'de> for DecodedContents {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DecodedContentsVisitor;

        impl<'de> Visitor<'de> for DecodedContentsVisitor {
            type Value = DecodedContents;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "base64 string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                // GitHub wraps the base64 to column 60. The base64 crate
                // doesn't handle whitespace, nor does it take a reader, so we
                // must unfortunately allocate again and remove all new lines.
                let v = v.replace("\n", "");

                let decoded = base64::decode_config(&v, base64::STANDARD).map_err(|e| match e {
                    base64::DecodeError::InvalidLength => {
                        E::invalid_length(v.len(), &"invalid base64 length")
                    }
                    base64::DecodeError::InvalidByte(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid base64 character at offset {}", offset).as_str(),
                    ),
                    base64::DecodeError::InvalidLastSymbol(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid last base64 character at offset {}", offset).as_str(),
                    ),
                })?;

                Ok(DecodedContents(decoded))
            }
        }

        deserializer.deserialize_str(DecodedContentsVisitor)
    }
}
<commit_msg>content: allow for getting content from a specific ref<commit_after>//! Content interface
use std::fmt;
use std::ops;

use data_encoding::BASE64;
use serde::de::{self, Visitor};
use serde::{Deserialize, Serialize};

use crate::repo_commits::CommitDetails;
use crate::utils::{percent_encode, PATH};
use crate::{Future, Github, Stream};

/// Provides access to the content information for a repository
pub struct Content {
    github: Github,
    owner: String,
    repo: String,
}

impl Content {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Content {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, location: &str, ref_: &str) -> String {
        // Handle files with spaces and other characters that can mess up the
        // final URL.
        let location = percent_encode(location.as_ref(), PATH);
        let mut path = format!("/repos/{}/{}/contents{}", self.owner, self.repo, location);
        if !ref_.is_empty() {
            path += &format!("?ref={}", ref_);
        }
        path
    }

    /// Gets the contents of the location. This could be a file, symlink, or
    /// submodule. To list the contents of a directory, use `iter`.
    pub fn get(&self, location: &str, ref_: &str) -> Future<Contents> {
        self.github.get(&self.path(location, ref_))
    }

    /// Information on a single file.
    ///
    /// GitHub only supports downloading files up to 1 megabyte in size. If you
    /// need to retrieve larger files, the Git Data API must be used instead.
    pub fn file(&self, location: &str, ref_: &str) -> Future<File> {
        self.github.get(&self.path(location, ref_))
    }

    /// List the root directory.
    pub fn root(&self, ref_: &str) -> Stream<DirectoryItem> {
        self.iter("/", ref_)
    }

    /// Provides a stream over the directory items in `location`.
    ///
    /// GitHub limits the number of items returned to 1000 for this API. If you
    /// need to retrieve more items, the Git Data API must be used instead.
    pub fn iter(&self, location: &str, ref_: &str) -> Stream<DirectoryItem> {
        self.github.get_stream(&self.path(location, ref_))
    }

    /// Creates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn create(&self, location: &str, content: &str, message: &str) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(&content.to_string().into_bytes()),
            message: message.to_string(),
            sha: None,
        };
        self.github.put(&self.path(location, ""), json!(file))
    }

    /// Updates a file at a specific location in a repository.
    /// You DO NOT need to base64 encode the content, we will do it for you.
    pub fn update(
        &self,
        location: &str,
        content: &str,
        message: &str,
        sha: &str,
    ) -> Future<NewFileResponse> {
        let file = &NewFile {
            content: BASE64.encode(&content.to_string().into_bytes()),
            message: message.to_string(),
            sha: Some(sha.to_string()),
        };
        self.github.put(&self.path(location, ""), json!(file))
    }
}

/// Contents of a path in a repository.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum Contents {
    File(File),
    Symlink(Symlink),
    Submodule(Submodule),
}

/// The type of content encoding.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Encoding {
    Base64,
    // Are there actually any other encoding types?
}

#[derive(Debug, Serialize)]
pub struct NewFile {
    pub content: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sha: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct NewFileResponse {
    pub commit: CommitDetails,
}

#[derive(Debug, Deserialize)]
pub struct File {
    pub encoding: Encoding,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub content: DecodedContents,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct DirectoryItem {
    #[serde(rename = "type")]
    pub _type: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Symlink {
    pub target: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: String,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Submodule {
    pub submodule_git_url: String,
    pub size: u32,
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub download_url: Option<String>,
    pub _links: Links,
}

#[derive(Debug, Deserialize)]
pub struct Links {
    pub git: String,
    #[serde(rename = "self")]
    pub _self: String,
    pub html: String,
}

/// Decoded file contents.
#[derive(Debug)]
pub struct DecodedContents(Vec<u8>);

impl Into<Vec<u8>> for DecodedContents {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl AsRef<[u8]> for DecodedContents {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl ops::Deref for DecodedContents {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'de> Deserialize<'de> for DecodedContents {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DecodedContentsVisitor;

        impl<'de> Visitor<'de> for DecodedContentsVisitor {
            type Value = DecodedContents;

            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(f, "base64 string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                // GitHub wraps the base64 to column 60. The base64 crate
                // doesn't handle whitespace, nor does it take a reader, so we
                // must unfortunately allocate again and remove all new lines.
                let v = v.replace("\n", "");

                let decoded = base64::decode_config(&v, base64::STANDARD).map_err(|e| match e {
                    base64::DecodeError::InvalidLength => {
                        E::invalid_length(v.len(), &"invalid base64 length")
                    }
                    base64::DecodeError::InvalidByte(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid base64 character at offset {}", offset).as_str(),
                    ),
                    base64::DecodeError::InvalidLastSymbol(offset, byte) => E::invalid_value(
                        de::Unexpected::Bytes(&[byte]),
                        &format!("valid last base64 character at offset {}", offset).as_str(),
                    ),
                })?;

                Ok(DecodedContents(decoded))
            }
        }

        deserializer.deserialize_str(DecodedContentsVisitor)
    }
}
<|endoftext|>


<commit_before>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::node::Node;
use crate::parsers::ParseValue;
use crate::property_defs::ColorInterpolationFilters;
use crate::xml::Attributes;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, Primitive, PrimitiveParams, ResolvedPrimitive};

/// The `feOffset` filter primitive.
#[derive(Clone)]
pub struct FeOffset {
    base: Primitive,
    in1: Input,
    dx: f64,
    dy: f64,
}

/// Resolved `feOffset` primitive for rendering.
pub struct Offset {
    in1: Input,
    dx: f64,
    dy: f64,
}

impl Default for FeOffset {
    /// Constructs a new `Offset` with empty properties.
    #[inline]
    fn default() -> FeOffset {
        FeOffset {
            base: Default::default(),
            in1: Default::default(),
            dx: 0f64,
            dy: 0f64,
        }
    }
}

impl SetAttributes for FeOffset {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.in1 = self.base.parse_one_input(attrs)?;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "dx") => self.dx = attr.parse(value)?,
                expanded_name!("", "dy") => self.dy = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Offset {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        // https://www.w3.org/TR/filter-effects/#ColorInterpolationFiltersProperty
        //
        // "Note: The color-interpolation-filters property just has an
        // effect on filter operations. Therefore, it has no effect on
        // filter primitives like feOffset"
        //
        // This is why we pass Auto here.
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;
        let bounds = primitive
            .get_bounds(ctx)?
            .add_input(&input_1)
            .into_irect(ctx, draw_ctx);

        let (dx, dy) = ctx.paffine().transform_distance(self.dx, self.dy);

        let surface = input_1.surface().offset(bounds, dx, dy)?;

        Ok(FilterResult {
            name: primitive.result.clone(),
            output: FilterOutput { surface, bounds },
        })
    }
}

impl FilterEffect for FeOffset {
    fn resolve(&self, _node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        Ok((
            self.base.clone(),
            PrimitiveParams::Offset(Offset {
                in1: self.in1.clone(),
                dx: self.dx,
                dy: self.dy,
            }),
        ))
    }
}
<commit_msg>feOffset: shorten code by implementing Default and Clone for its parameters<commit_after>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::node::Node;
use crate::parsers::ParseValue;
use crate::property_defs::ColorInterpolationFilters;
use crate::xml::Attributes;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, Input, Primitive, PrimitiveParams, ResolvedPrimitive};

/// The `feOffset` filter primitive.
#[derive(Default)]
pub struct FeOffset {
    base: Primitive,
    params: Offset,
}

/// Resolved `feOffset` primitive for rendering.
#[derive(Clone, Default)]
pub struct Offset {
    in1: Input,
    dx: f64,
    dy: f64,
}

impl SetAttributes for FeOffset {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs)?;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "dx") => self.params.dx = attr.parse(value)?,
                expanded_name!("", "dy") => self.params.dy = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Offset {
    pub fn render(
        &self,
        primitive: &ResolvedPrimitive,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        // https://www.w3.org/TR/filter-effects/#ColorInterpolationFiltersProperty
        //
        // "Note: The color-interpolation-filters property just has an
        // effect on filter operations. Therefore, it has no effect on
        // filter primitives like feOffset"
        //
        // This is why we pass Auto here.
        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;
        let bounds = primitive
            .get_bounds(ctx)?
            .add_input(&input_1)
            .into_irect(ctx, draw_ctx);

        let (dx, dy) = ctx.paffine().transform_distance(self.dx, self.dy);

        let surface = input_1.surface().offset(bounds, dx, dy)?;

        Ok(FilterResult {
            name: primitive.result.clone(),
            output: FilterOutput { surface, bounds },
        })
    }
}

impl FilterEffect for FeOffset {
    fn resolve(&self, _node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError> {
        Ok((
            self.base.clone(),
            PrimitiveParams::Offset(self.params.clone()),
        ))
    }
}
<|endoftext|>


<commit_before>mod primitives;

use specs::prelude::*;

use crate::components::*;
use crate::core::*;
use primitives::*;

pub use primitives::{can_attack_melee, can_charge, can_move_towards, find_movement_obstacles};

pub fn action(e: &(Entity, Actor), w: &World) -> (Action, u8) {
    zombi_action(&e, w)
}

fn zombi_action((_, a): &(Entity, Actor), w: &World) -> (Action, u8) {
    let (entities, game_objects, map): (Entities, ReadStorage<GameObjectCmp>, Read<Map>) =
        w.system_data();

    for (te, ta) in find_enemies(a, &entities, &game_objects) {
        if let Some(attack) = can_attack_melee(a, &ta, &map, &game_objects) {
            return Action::melee_attack(te, attack);
        }
        if let Some(attack) = can_charge(a, &ta, &map, &game_objects) {
            return Action::charge(te, attack);
        }

        if a.can_move() {
            if let Some(path) = can_move_towards(a, &ta, &map, &game_objects) {
                return Action::move_to(
                    path.iter()
                        .take(a.move_distance().into())
                        .cloned()
                        .collect(),
                );
            }
        }
    }

    Action::recover()
}

pub fn actions_at(
    (entity, actor): &(Entity, Actor),
    selected_pos: WorldPos,
    world: &World,
) -> Vec<(Action, u8)> {
    let (map, objects): (Read<Map>, ReadStorage<GameObjectCmp>) = world.system_data();
    let mut result = vec![];

    if let Some((other_entity, other_actor)) = find_actor_at(world, &selected_pos) {
        if entity.id() == other_entity.id() {
            for (n, t, d) in actor.ability_self() {
                result.push(Action::use_ability(*entity, n, t, d));
            }
        } else {
            if actor.team == other_actor.team {
                if other_actor.can_activate() {
                    result.push(Action::activate(other_entity));
                }
            } else {
                if let Some(attack) = can_attack_melee(actor, &other_actor, &map, &objects) {
                    result.push(Action::melee_attack(other_entity, attack));
                }
                if let Some(attack) = can_charge(actor, &other_actor, &map, &objects) {
                    result.push(Action::charge(other_entity, attack));
                }
            }
        }
    }

    if actor.can_move() {
        let from = MapPos::from_world_pos(actor.pos);
        let to = MapPos::from_world_pos(selected_pos);
        let obstacles = find_movement_obstacles(&objects);

        if let Some(path) = map.find_path(from, to, &obstacles) {
            if path.len() <= actor.move_distance().into() {
                result.push(Action::move_to(path));
            }
        }
    }

    result
}
<commit_msg>[FIX] fixed bug that allows to 'move' in place<commit_after>mod primitives;

use specs::prelude::*;

use crate::components::*;
use crate::core::*;
use primitives::*;

pub use primitives::{can_attack_melee, can_charge, can_move_towards, find_movement_obstacles};

pub fn action(e: &(Entity, Actor), w: &World) -> (Action, u8) {
    zombi_action(&e, w)
}

fn zombi_action((_, a): &(Entity, Actor), w: &World) -> (Action, u8) {
    let (entities, game_objects, map): (Entities, ReadStorage<GameObjectCmp>, Read<Map>) =
        w.system_data();

    for (te, ta) in find_enemies(a, &entities, &game_objects) {
        if let Some(attack) = can_attack_melee(a, &ta, &map, &game_objects) {
            return Action::melee_attack(te, attack);
        }
        if let Some(attack) = can_charge(a, &ta, &map, &game_objects) {
            return Action::charge(te, attack);
        }

        if a.can_move() {
            if let Some(path) = can_move_towards(a, &ta, &map, &game_objects) {
                return Action::move_to(
                    path.iter()
                        .take(a.move_distance().into())
                        .cloned()
                        .collect(),
                );
            }
        }
    }

    Action::recover()
}

pub fn actions_at(
    (entity, actor): &(Entity, Actor),
    selected_pos: WorldPos,
    world: &World,
) -> Vec<(Action, u8)> {
    let (map, objects): (Read<Map>, ReadStorage<GameObjectCmp>) = world.system_data();
    let mut result = vec![];

    if let Some((other_entity, other_actor)) = find_actor_at(world, &selected_pos) {
        if entity.id() == other_entity.id() {
            for (n, t, d) in actor.ability_self() {
                result.push(Action::use_ability(*entity, n, t, d));
            }
        } else {
            if actor.team == other_actor.team {
                if other_actor.can_activate() {
                    result.push(Action::activate(other_entity));
                }
            } else {
                if let Some(attack) = can_attack_melee(actor, &other_actor, &map, &objects) {
                    result.push(Action::melee_attack(other_entity, attack));
                }
                if let Some(attack) = can_charge(actor, &other_actor, &map, &objects) {
                    result.push(Action::charge(other_entity, attack));
                }
            }
        }
    }

    if actor.can_move() {
        let from = MapPos::from_world_pos(actor.pos);
        let to = MapPos::from_world_pos(selected_pos);
        let obstacles = find_movement_obstacles(&objects);

        if let Some(path) = map.find_path(from, to, &obstacles) {
            if path.len() > 0 && path.len() <= actor.move_distance().into() {
                result.push(Action::move_to(path));
            }
        }
    }

    result
}
<|endoftext|>


<commit_before>//! The Divide & Conquer recursive strategy.
//!
//! From [Wikipedia][1]:
//! > A divide and conquer algorithm works by recursively breaking down a
//! > problem into two or more sub-problems of the same (or related) type
//! > (**divide**) until these become simple enough to be solved directly
//! > (**conquer**). The solution to the sub-problems are then combined
//! > to give a solution to the original problem.
//!
//! To use this strategy you need to implement the [`DacProblem`][2] trait and
//! everything else is handled for you.
//!
//! [1]: https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms
//! [2]: trait.DacProblem.html

use std::collections::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;

/// Divide & Conquer Problem.
///
/// You have to implement this trait in order to use the algorithm. Simply fill
/// all the methods and you're all set. We have two generic types:
///
/// - `E`: A partial solution, wich we work with.
/// - `S`: The final solution, the output of the algorithm.
///
/// Sometimes `E` and `S` are the same type because we don't need conversion
/// between the partial and the final solution (e.g. when calculating a
/// factorial), but if we are working with a list or an array, `E` could simply
/// be a pointer to an element and `S` the actual element.
///
/// Once you have defined the problem, use [`DacAlgorithm`][1] or
/// [`DacMemAlgorithm`][2] to solve it.
///
/// [1]: struct.DacAlgorithm.html
/// [2]: struct.DacMemAlgorithm.html
pub trait DacProblem<S, E> {
    /// The size of your problem. Usually referred to as `n`.
    ///
    /// It should decrease as you split the problem, otherwise the algorithm
    /// will never stop, and we don't want that.
    fn size(&self) -> usize;

    /// The moment when the problem is simple enough to be solved directly.
    ///
    /// Here `DacProblem::size` is the smallest.
    fn is_base_case(&self) -> bool;

    /// The base case's solution.
    fn base_case_solution(&self) -> E;

    /// The number of subproblems the problem has.
    fn subproblem_count(&self) -> usize;

    /// Return the subproblem corresponding to the given `i`. (i.e. the first
    /// subproblem, the second...).
    ///
    /// `i` is in the range [0, `DacProblem::subproblem_count`).
    fn get_subproblem(&self, i: usize) -> Self;

    /// How to combine the subproblems' solutions into the current problem's
    /// solution.
    fn combine(&self, solutions: Vec<E>) -> E;

    /// Transforms the partial solution `E`, if it is possible, into a final
    /// solution `S`.
    fn get_solution(&self, partial_solution: &E) -> Option<S>;
}

/// The problem solver.
///
/// Solves a divide & conquer problem without memory. Useful if we don't need
/// to store partial solutions.
pub struct DacAlgorithm<P, S, E>
    where P: DacProblem<S, E>
{
    phan: PhantomData<S>,
    partial_solution: E,
    problem: P,
}

impl<P, S, E> DacAlgorithm<P, S, E>
    where P: DacProblem<S, E>
{
    /// Solve the `problem` problem.
    pub fn new(problem: P) -> Self {
        let e = Self::solve(&problem);

        DacAlgorithm {
            phan: PhantomData,
            partial_solution: e,
            problem: problem,
        }
    }

    fn solve(problem: &P) -> E {
        if problem.is_base_case() {
            problem.base_case_solution()

        } else {
            let solutions = (0..problem.subproblem_count())
                                .map(|i| problem.get_subproblem(i))
                                .map(|p| Self::solve(&p))
                                .collect::<Vec<E>>();

            problem.combine(solutions)
        }
    }

    /// Get the final solution.
    pub fn get_solution(&self) -> Option<S> {
        self.problem.get_solution(&self.partial_solution)
    }
}

/// The problem solver, with memory.
///
/// # Explanation
///
/// Solves a divide & conquer problem with memory: it stores the partial
/// solutions of all the subproblems, in case they are needed by another
/// subproblem. An usual example is the [Fibonacci sequence][1]:
///
/// ``` text
/// fib(0) = 0
/// fib(1) = 1
/// fib(n) = fib(n - 1) + fib(n - 2)
/// ```
///
/// As you can see, `fib(5)` needs `fib(4)` and `fib(3)`. But then `fib(4)` also
/// needs `fib(3)`. Memory here is useful so we don't recalculate values.
///
/// # Usage
///
/// Using this is the same as using [`DacAlgorithm`][2] but you problem has to
/// implement some traits:
///
/// - `DacProblem` has to implement the following traits:
///     - `Eq` (and therefore `PartialEq`)
///     - `Hash`
///     - `Clone`
/// - `E` has to be `Clone` too.
///
/// Which is not complicated to do:
///
///     #[derive(Eq, PartialEq, Hash, Clone)]
///     struct Fibonacci(u64);
///
/// [1]: https://en.wikipedia.org/wiki/Fibonacci_number
/// [2]: struct.DacAlgorithm.html#usage
pub struct DacMemAlgorithm<P, S, E>
    where P: DacProblem<S, E> + Eq + Hash + Clone,
          E: Clone
{
    phan: PhantomData<S>,
    solutions: HashMap<P, E>,
    problem: P,
}

impl<P, S, E> DacMemAlgorithm<P, S, E>
    where P: DacProblem<S, E> + Eq + Hash + Clone,
          E: Clone
{
    pub fn new(problem: P) -> Self {
        let mut map = HashMap::new();
        Self::solve(&problem, &mut map);

        DacMemAlgorithm {
            phan: PhantomData,
            solutions: map,
            problem: problem,
        }
    }

    fn solve(problem: &P, mut solutions: &mut HashMap<P, E>) -> E {
        if problem.is_base_case() {
            problem.base_case_solution()

        } else if solutions.contains_key(&problem) {
            solutions.get(&problem).unwrap().clone()

        } else {
            let solution = {
                let solutions = (0..problem.subproblem_count())
                                    .map(|i| problem.get_subproblem(i))
                                    .map(|p| Self::solve(&p, &mut solutions))
                                    .collect::<Vec<E>>();

                problem.combine(solutions)
            };

            solutions.insert(problem.clone(), solution);
            solutions.get(&problem).unwrap().clone()
        }
    }

    pub fn get_solution(&self) -> Option<S> {
        self.solutions
            .get(&self.problem)
            .and_then(|e| self.problem.get_solution(e))
    }
}
<commit_msg>Document & Write examples<commit_after>//! The Divide & Conquer recursive strategy.
//!
//! From [Wikipedia][1]:
//! > A divide and conquer algorithm works by recursively breaking down a
//! > problem into two or more sub-problems of the same (or related) type
//! > (**divide**) until these become simple enough to be solved directly
//! > (**conquer**). The solution to the sub-problems are then combined
//! > to give a solution to the original problem.
//!
//! To use this strategy you need to implement the [`DacProblem`][2] trait and
//! everything else is handled for you.
//!
//! [1]: https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms
//! [2]: trait.DacProblem.html

use std::collections::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;

/// Divide & Conquer Problem.
///
/// You have to implement this trait in order to use the algorithm. Simply fill
/// all the methods and you're all set. We have two generic types:
///
/// - `E`: A partial solution, wich we work with.
/// - `S`: The final solution, the output of the algorithm.
///
/// Sometimes `E` and `S` are the same type because we don't need conversion
/// between the partial and the final solution (e.g. when calculating a
/// factorial), but if we are working with a list or an array, `E` could simply
/// be a pointer to an element and `S` the actual element.
///
/// Once you have defined the problem, use [`DacAlgorithm`][1] or
/// [`DacMemAlgorithm`][2] to solve it.
///
/// # Examples
///
/// In [Required Methods][3] you'll find the description to all the methods you
/// need to implement. Here is an example solving the [Fibonacci][4] problem:
///
///     use strategies::dac::DacProblem;
///     use strategies::dac::{DacAlgorithm, DacMemAlgorithm};
///
///     // This is where we store our problem.
///     // (The derive part is only needed for DacMemAlgorithm).
///     #[derive(Clone, Eq, PartialEq, Hash)]
///     struct Fibonacci(u64);
///
///     // Since the problem is simple, `E` and `S` are the same type.
///     impl DacProblem<u64, u64> for Fibonacci {
///         fn size(&self) -> usize {
///             self.0 as usize
///         }
///
///         // We know directly that if the problem is 0 or 1, the solution
///         // is the same as the problem.
///         fn is_base_case(&self) -> bool {
///             self.size() < 2
///         }
///
///         fn base_case_solution(&self) -> u64 {
///             self.0
///         }
///
///         // As the fibonacci definition has 2 recursive subproblems...
///         fn subproblem_count(&self) -> usize {
///             2
///         }
///
///         fn get_subproblem(&self, i: usize) -> Fibonacci {
///             match i {
///                 0 => Fibonacci(self.0 - 1),
///                 _ => Fibonacci(self.0 - 2),
///             }
///         }
///
///         // We add the to subproblems' solutions.
///         fn combine(&self, solutions: Vec<u64>) -> u64 {
///             let a = solutions.get(0).unwrap();
///             let b = solutions.get(1).unwrap();
///
///             a + b
///         }
///
///         fn get_solution(&self, partial_solution: &u64) -> Option<u64> {
///             Some(*partial_solution)
///         }
///     }
///
///     // Now we can use DacAlgorithm...
///     let p = DacAlgorithm::new(Fibonacci(5));
///     let s = p.get_solution().unwrap();
///     assert_eq!(s, 5);
///
///     // ...or DacMemAlgorithm, which is the best option for this problem
///     // (go to DacMemAlgorithm's page to see why).
///     let p = DacMemAlgorithm::new(Fibonacci(50));
///     let s = p.get_solution().unwrap();
///     assert_eq!(s, 12586269025);
///
/// **Note**: Although you will be doing any other kind of problems, you'll
/// have to pick the best types for the problem. In the above's example I used
/// `u64` because it's part of Rust, but it can't store the solution to
/// Fibonacci(100).
///
/// [1]: struct.DacAlgorithm.html
/// [2]: struct.DacMemAlgorithm.html
/// [3]: #required-methods
/// [4]: https://en.wikipedia.org/wiki/Fibonacci_number
pub trait DacProblem<S, E> {
    /// The size of your problem. Usually referred to as `n`.
    ///
    /// It should decrease as you split the problem, otherwise the algorithm
    /// will never stop, and we don't want that.
    fn size(&self) -> usize;

    /// The moment when the problem is simple enough to be solved directly.
    ///
    /// Here `DacProblem::size` is the smallest.
    fn is_base_case(&self) -> bool;

    /// The base case's solution.
    fn base_case_solution(&self) -> E;

    /// The number of subproblems the problem has.
    fn subproblem_count(&self) -> usize;

    /// Return the subproblem corresponding to the given `i`. (i.e. the first
    /// subproblem, the second...).
    ///
    /// `i` is in the range [0, `DacProblem::subproblem_count`).
    fn get_subproblem(&self, i: usize) -> Self;

    /// How to combine the subproblems' solutions into the current problem's
    /// solution.
    fn combine(&self, solutions: Vec<E>) -> E;

    /// Transforms the partial solution `E`, if it is possible, into a final
    /// solution `S`.
    fn get_solution(&self, partial_solution: &E) -> Option<S>;
}

/// The problem solver.
///
/// Solves a divide & conquer problem without memory. Useful if we don't need
/// to store partial solutions.
///
/// # Usage
///
/// First, implement a `DacProblem`. Then, solve it. A good example is in
/// [`DacProblem`][1].
///
/// [1]: trait.DacProblem.html#examples
pub struct DacAlgorithm<P, S, E>
    where P: DacProblem<S, E>
{
    phan: PhantomData<S>,
    partial_solution: E,
    problem: P,
}

impl<P, S, E> DacAlgorithm<P, S, E>
    where P: DacProblem<S, E>
{
    /// Solve the `problem` problem.
    pub fn new(problem: P) -> Self {
        let e = Self::solve(&problem);

        DacAlgorithm {
            phan: PhantomData,
            partial_solution: e,
            problem: problem,
        }
    }

    fn solve(problem: &P) -> E {
        if problem.is_base_case() {
            problem.base_case_solution()

        } else {
            let solutions = (0..problem.subproblem_count())
                                .map(|i| problem.get_subproblem(i))
                                .map(|p| Self::solve(&p))
                                .collect::<Vec<E>>();

            problem.combine(solutions)
        }
    }

    /// Get the final solution.
    pub fn get_solution(&self) -> Option<S> {
        self.problem.get_solution(&self.partial_solution)
    }
}

/// The problem solver, with memory.
///
/// # Explanation
///
/// Solves a divide & conquer problem with memory: it stores the partial
/// solutions of all the subproblems, in case they are needed by another
/// subproblem. An usual example is the [Fibonacci sequence][1]:
///
/// ``` text
/// fib(0) = 0
/// fib(1) = 1
/// fib(n) = fib(n - 1) + fib(n - 2)
/// ```
///
/// As you can see, `fib(5)` needs `fib(4)` and `fib(3)`. But then `fib(4)` also
/// needs `fib(3)`. Memory here is useful so we don't recalculate values.
///
/// # Usage
///
/// Using this is the same as using [`DacAlgorithm`][2] but you problem has to
/// implement some traits:
///
/// - `DacProblem` has to implement the following traits:
///     - `Eq` (and therefore `PartialEq`)
///     - `Hash`
///     - `Clone`
/// - `E` has to be `Clone` too.
///
/// Which is not complicated to do:
///
///     #[derive(Eq, PartialEq, Hash, Clone)]
///     struct Fibonacci(u64);
///
/// [1]: https://en.wikipedia.org/wiki/Fibonacci_number
/// [2]: struct.DacAlgorithm.html#usage
pub struct DacMemAlgorithm<P, S, E>
    where P: DacProblem<S, E> + Eq + Hash + Clone,
          E: Clone
{
    phan: PhantomData<S>,
    solutions: HashMap<P, E>,
    problem: P,
}

impl<P, S, E> DacMemAlgorithm<P, S, E>
    where P: DacProblem<S, E> + Eq + Hash + Clone,
          E: Clone
{
    pub fn new(problem: P) -> Self {
        let mut map = HashMap::new();
        Self::solve(&problem, &mut map);

        DacMemAlgorithm {
            phan: PhantomData,
            solutions: map,
            problem: problem,
        }
    }

    fn solve(problem: &P, mut solutions: &mut HashMap<P, E>) -> E {
        if problem.is_base_case() {
            problem.base_case_solution()

        } else if solutions.contains_key(&problem) {
            solutions.get(&problem).unwrap().clone()

        } else {
            let solution = {
                let solutions = (0..problem.subproblem_count())
                                    .map(|i| problem.get_subproblem(i))
                                    .map(|p| Self::solve(&p, &mut solutions))
                                    .collect::<Vec<E>>();

                problem.combine(solutions)
            };

            solutions.insert(problem.clone(), solution);
            solutions.get(&problem).unwrap().clone()
        }
    }

    pub fn get_solution(&self) -> Option<S> {
        self.solutions
            .get(&self.problem)
            .and_then(|e| self.problem.get_solution(e))
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::fmt::{self, Write};

#[derive(Clone, Debug)]
pub enum Destination {
    Http(String, String),
    Path(String),
}

#[derive(Clone, Debug)]
pub struct Route {
    subdomain: Option<String>,
    path: String,
    destination: Destination,
}

impl FromStr for Destination {
    type Err = String;
    fn from_str(data: &str) -> Result<Destination, String> {
        if data.starts_with("http://") {
            let mut pair = data[7..].splitn(2, '/');
            Ok(Destination::Http(
                String::from(pair.next().unwrap()),
                String::from(pair.next().unwrap_or("")),
            ))
        } else if data.starts_with("https://") {
            unimplemented!();
        } else {
            Ok(Destination::Path(String::from(data)))
        }
    }
}

impl FromStr for Route {
    type Err = String;
    fn from_str(data: &str) -> Result<Route, String> {
        let mut pair = data.splitn(2, '=');
        match (pair.next().unwrap(), pair.next()) {
            (dest, None) => {
                Ok(Route {
                    subdomain: None,
                    path: String::from(""),
                    destination: dest.parse()?,
                })
            }
            (pattern, Some(dest)) => {
                let mut pair = pattern.splitn(2, '/');
                let subdomain = pair.next().unwrap();
                Ok(Route {
                    subdomain: if subdomain == "" { None }
                               else { Some(String::from(subdomain)) },
                    path: String::from(pair.next().unwrap_or("")),
                    destination: dest.parse()?,
                })
            }
        }
    }
}

pub fn generate_config(port: u16, routes: &[Route], crossdomain: bool)
    -> String
{
    let mut buffer = String::new();
    _generate_config(&mut buffer, port, routes, crossdomain).unwrap();
    return buffer;
}

fn _generate_config(buf: &mut String, port: u16, routes: &[Route],
    crossdomain: bool)
    -> Result<(), fmt::Error>
{
    writeln!(buf, "listen: [127.0.0.1:{}]", port)?;
    writeln!(buf, "")?;
    writeln!(buf, "routing:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { subdomain: Some(ref subdomain), ref path, .. } => {
                writeln!(buf, "  {}.devd.io/{}: h{}", subdomain, path, idx)?;
            }
            Route { subdomain: None, ref path, .. } => {
                writeln!(buf, "  localhost/{}: h{}", path, idx)?;
                writeln!(buf, "  devd.io/{}: h{}", path, idx)?;
            }
        }
    }
    writeln!(buf, "")?;
    writeln!(buf, "handlers:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { destination: Destination::Path(ref path), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  h{}: !Static", idx)?;
                writeln!(buf, "    mode: relative_to_route")?;
                writeln!(buf, "    path: {:?}", path)?;
                writeln!(buf, "    text-charset: utf-8")?;
                if crossdomain {
                    writeln!(buf, "    extra-headers:")?;
                    writeln!(buf, "      Access-Control-Allow-Origin: '*'")?;
                }
            }
            Route { destination: Destination::Http(_, ref path), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  h{}: !Proxy", idx)?;
                writeln!(buf, "    mode: forward")?;
                writeln!(buf, "    destination: d{}/{}", idx, path)?;
                if crossdomain {
                    writeln!(buf, "    extra-headers:")?;
                    writeln!(buf, "      Access-Control-Allow-Origin: '*'")?;
                }
            }
        }
    }
    writeln!(buf, "")?;
    writeln!(buf, "http-destinations:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { destination: Destination::Path(_), .. } => {}
            Route { destination: Destination::Http(ref host, _), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  d{}:", idx)?;
                writeln!(buf, "    load-balancing: queue")?;
                writeln!(buf, "    addresses: [{}]", host)?;
            }
        }
    }
    Ok(())
}
<commit_msg>Adds index-files by default to devd<commit_after>use std::str::FromStr;
use std::fmt::{self, Write};

#[derive(Clone, Debug)]
pub enum Destination {
    Http(String, String),
    Path(String),
}

#[derive(Clone, Debug)]
pub struct Route {
    subdomain: Option<String>,
    path: String,
    destination: Destination,
}

impl FromStr for Destination {
    type Err = String;
    fn from_str(data: &str) -> Result<Destination, String> {
        if data.starts_with("http://") {
            let mut pair = data[7..].splitn(2, '/');
            Ok(Destination::Http(
                String::from(pair.next().unwrap()),
                String::from(pair.next().unwrap_or("")),
            ))
        } else if data.starts_with("https://") {
            unimplemented!();
        } else {
            Ok(Destination::Path(String::from(data)))
        }
    }
}

impl FromStr for Route {
    type Err = String;
    fn from_str(data: &str) -> Result<Route, String> {
        let mut pair = data.splitn(2, '=');
        match (pair.next().unwrap(), pair.next()) {
            (dest, None) => {
                Ok(Route {
                    subdomain: None,
                    path: String::from(""),
                    destination: dest.parse()?,
                })
            }
            (pattern, Some(dest)) => {
                let mut pair = pattern.splitn(2, '/');
                let subdomain = pair.next().unwrap();
                Ok(Route {
                    subdomain: if subdomain == "" { None }
                               else { Some(String::from(subdomain)) },
                    path: String::from(pair.next().unwrap_or("")),
                    destination: dest.parse()?,
                })
            }
        }
    }
}

pub fn generate_config(port: u16, routes: &[Route], crossdomain: bool)
    -> String
{
    let mut buffer = String::new();
    _generate_config(&mut buffer, port, routes, crossdomain).unwrap();
    return buffer;
}

fn _generate_config(buf: &mut String, port: u16, routes: &[Route],
    crossdomain: bool)
    -> Result<(), fmt::Error>
{
    writeln!(buf, "listen: [127.0.0.1:{}]", port)?;
    writeln!(buf, "")?;
    writeln!(buf, "routing:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { subdomain: Some(ref subdomain), ref path, .. } => {
                writeln!(buf, "  {}.devd.io/{}: h{}", subdomain, path, idx)?;
            }
            Route { subdomain: None, ref path, .. } => {
                writeln!(buf, "  localhost/{}: h{}", path, idx)?;
                writeln!(buf, "  devd.io/{}: h{}", path, idx)?;
            }
        }
    }
    writeln!(buf, "")?;
    writeln!(buf, "handlers:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { destination: Destination::Path(ref path), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  h{}: !Static", idx)?;
                writeln!(buf, "    mode: relative_to_route")?;
                writeln!(buf, "    index-files: [index.html, index.htm]")?;
                writeln!(buf, "    path: {:?}", path)?;
                writeln!(buf, "    text-charset: utf-8")?;
                if crossdomain {
                    writeln!(buf, "    extra-headers:")?;
                    writeln!(buf, "      Access-Control-Allow-Origin: '*'")?;
                }
            }
            Route { destination: Destination::Http(_, ref path), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  h{}: !Proxy", idx)?;
                writeln!(buf, "    mode: forward")?;
                writeln!(buf, "    destination: d{}/{}", idx, path)?;
                if crossdomain {
                    writeln!(buf, "    extra-headers:")?;
                    writeln!(buf, "      Access-Control-Allow-Origin: '*'")?;
                }
            }
        }
    }
    writeln!(buf, "")?;
    writeln!(buf, "http-destinations:")?;
    for (idx, route) in routes.iter().enumerate() {
        match *route {
            Route { destination: Destination::Path(_), .. } => {}
            Route { destination: Destination::Http(ref host, _), .. } => {
                writeln!(buf, "")?;
                writeln!(buf, "  d{}:", idx)?;
                writeln!(buf, "    load-balancing: queue")?;
                writeln!(buf, "    addresses: [{}]", host)?;
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::convert::TryFrom;
use std::{cmp, fmt, hash};

use unsigned_varint::{decode as varint_decode, encode as varint_encode};

use crate::errors::{DecodeError, DecodeOwnedError};
use crate::hashes::Code;
use crate::storage::Storage;

/// Represents a valid multihash.
#[derive(Clone)]
pub struct Multihash {
    storage: Storage,
}

impl fmt::Debug for Multihash {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
    }
}

impl PartialEq for Multihash {
    fn eq(&self, other: &Self) -> bool {
        self.storage.bytes() == other.storage.bytes()
    }
}

impl Eq for Multihash {}

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

impl Multihash {
    /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
    pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
        if let Err(err) = MultihashRef::from_slice(&bytes) {
            return Err(DecodeOwnedError {
                error: err,
                data: bytes,
            });
        }
        Ok(Multihash {
            storage: Storage::from_slice(&bytes),
        })
    }

    /// Returns the bytes representation of the multihash.
    pub fn into_bytes(self) -> Vec<u8> {
        self.to_vec()
    }

    /// Returns the bytes representation of the multihash.
    pub fn to_vec(&self) -> Vec<u8> {
        Vec::from(self.as_bytes())
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &[u8] {
        self.storage.bytes()
    }

    /// Builds a `MultihashRef` corresponding to this `Multihash`.
    pub fn as_ref(&self) -> MultihashRef {
        MultihashRef {
            bytes: self.as_bytes(),
        }
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Code {
        self.as_ref().algorithm()
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &[u8] {
        self.as_ref().digest()
    }
}

impl AsRef<[u8]> for Multihash {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl Borrow<[u8]> for Multihash {
    fn borrow(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
    fn eq(&self, other: &MultihashRef<'a>) -> bool {
        &*self.as_bytes() == other.as_bytes()
    }
}

impl TryFrom<Vec<u8>> for Multihash {
    type Error = DecodeOwnedError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Multihash::from_bytes(value)
    }
}

impl PartialOrd for Multihash {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Multihash {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.as_ref().cmp(&other.as_ref())
    }
}

/// Represents a valid multihash.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultihashRef<'a> {
    bytes: &'a [u8],
}

impl<'a> MultihashRef<'a> {
    /// Creates a `MultihashRef` from the given `input`.
    pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
        if input.is_empty() {
            return Err(DecodeError::BadInputLength);
        }

        let (_code, bytes) = varint_decode::u64(&input).map_err(|_| DecodeError::BadInputLength)?;

        let (hash_len, bytes) =
            varint_decode::u64(&bytes).map_err(|_| DecodeError::BadInputLength)?;
        if (bytes.len() as u64) != hash_len {
            return Err(DecodeError::BadInputLength);
        }

        Ok(MultihashRef { bytes: input })
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Code {
        let (code, _bytes) =
            varint_decode::u64(&self.bytes).expect("multihash is known to be valid algorithm");
        Code::from_u64(code)
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &'a [u8] {
        let (_code, bytes) =
            varint_decode::u64(&self.bytes).expect("multihash is known to be valid digest");
        let (_hash_len, bytes) =
            varint_decode::u64(&bytes).expect("multihash is known to be a valid digest");
        &bytes[..]
    }

    /// Builds a `Multihash` that owns the data.
    ///
    /// This operation allocates.
    pub fn to_owned(&self) -> Multihash {
        Multihash {
            storage: Storage::from_slice(self.bytes),
        }
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &'a [u8] {
        &self.bytes
    }
}

impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
    fn eq(&self, other: &Multihash) -> bool {
        self.as_bytes() == &*other.as_bytes()
    }
}

/// The `MultihashDigest` trait specifies an interface common for all multihash functions.
pub trait MultihashDigest {
    /// The Mutlihash byte value.
    fn code(&self) -> Code;

    /// Hash some input and return the digest.
    ///
    /// # Panics
    ///
    /// Panics if the digest length is bigger than 2^32. This only happens for identity hasing.
    fn digest(&self, data: &[u8]) -> Multihash;
}

/// Wraps a hash digest in Multihash with the given Mutlihash code.
///
/// The size of the hash is determoned by the size of the input hash. If it should be truncated
/// the input data must already be the truncated hash.
pub fn wrap(code: Code, data: &[u8]) -> Multihash {
    let mut code_buf = varint_encode::u64_buffer();
    let code = varint_encode::u64(code.to_u64(), &mut code_buf);

    let mut size_buf = varint_encode::u64_buffer();
    let size = varint_encode::u64(data.len() as u64, &mut size_buf);

    Multihash {
        storage: Storage::from_slices(&[code, &size, &data]),
    }
}
<commit_msg>feat: add `Deref` an `Into<Vec<u8>>` implementations<commit_after>use std::borrow::Borrow;
use std::convert::TryFrom;
use std::{cmp, fmt, hash, ops};

use unsigned_varint::{decode as varint_decode, encode as varint_encode};

use crate::errors::{DecodeError, DecodeOwnedError};
use crate::hashes::Code;
use crate::storage::Storage;

/// Represents a valid multihash.
#[derive(Clone)]
pub struct Multihash {
    storage: Storage,
}

impl fmt::Debug for Multihash {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Multihash").field(&self.as_bytes()).finish()
    }
}

impl PartialEq for Multihash {
    fn eq(&self, other: &Self) -> bool {
        self.storage.bytes() == other.storage.bytes()
    }
}

impl Eq for Multihash {}

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

impl Multihash {
    /// Verifies whether `bytes` contains a valid multihash, and if so returns a `Multihash`.
    pub fn from_bytes(bytes: Vec<u8>) -> Result<Multihash, DecodeOwnedError> {
        if let Err(err) = MultihashRef::from_slice(&bytes) {
            return Err(DecodeOwnedError {
                error: err,
                data: bytes,
            });
        }
        Ok(Multihash {
            storage: Storage::from_slice(&bytes),
        })
    }

    /// Returns the bytes representation of the multihash.
    pub fn into_bytes(self) -> Vec<u8> {
        self.to_vec()
    }

    /// Returns the bytes representation of the multihash.
    pub fn to_vec(&self) -> Vec<u8> {
        Vec::from(self.as_bytes())
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &[u8] {
        self.storage.bytes()
    }

    /// Builds a `MultihashRef` corresponding to this `Multihash`.
    pub fn as_ref(&self) -> MultihashRef {
        MultihashRef {
            bytes: self.as_bytes(),
        }
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Code {
        self.as_ref().algorithm()
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &[u8] {
        self.as_ref().digest()
    }
}

impl AsRef<[u8]> for Multihash {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ops::Deref for Multihash {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.as_bytes()
    }
}

impl Borrow<[u8]> for Multihash {
    fn borrow(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<'a> PartialEq<MultihashRef<'a>> for Multihash {
    fn eq(&self, other: &MultihashRef<'a>) -> bool {
        &*self.as_bytes() == other.as_bytes()
    }
}

impl TryFrom<Vec<u8>> for Multihash {
    type Error = DecodeOwnedError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Multihash::from_bytes(value)
    }
}

impl Into<Vec<u8>> for Multihash {
    fn into(self) -> Vec<u8> {
        self.to_vec()
    }
}

impl PartialOrd for Multihash {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Multihash {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.as_ref().cmp(&other.as_ref())
    }
}

/// Represents a valid multihash.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MultihashRef<'a> {
    bytes: &'a [u8],
}

impl<'a> MultihashRef<'a> {
    /// Creates a `MultihashRef` from the given `input`.
    pub fn from_slice(input: &'a [u8]) -> Result<Self, DecodeError> {
        if input.is_empty() {
            return Err(DecodeError::BadInputLength);
        }

        let (_code, bytes) = varint_decode::u64(&input).map_err(|_| DecodeError::BadInputLength)?;

        let (hash_len, bytes) =
            varint_decode::u64(&bytes).map_err(|_| DecodeError::BadInputLength)?;
        if (bytes.len() as u64) != hash_len {
            return Err(DecodeError::BadInputLength);
        }

        Ok(MultihashRef { bytes: input })
    }

    /// Returns which hashing algorithm is used in this multihash.
    pub fn algorithm(&self) -> Code {
        let (code, _bytes) =
            varint_decode::u64(&self.bytes).expect("multihash is known to be valid algorithm");
        Code::from_u64(code)
    }

    /// Returns the hashed data.
    pub fn digest(&self) -> &'a [u8] {
        let (_code, bytes) =
            varint_decode::u64(&self.bytes).expect("multihash is known to be valid digest");
        let (_hash_len, bytes) =
            varint_decode::u64(&bytes).expect("multihash is known to be a valid digest");
        &bytes[..]
    }

    /// Builds a `Multihash` that owns the data.
    ///
    /// This operation allocates.
    pub fn to_owned(&self) -> Multihash {
        Multihash {
            storage: Storage::from_slice(self.bytes),
        }
    }

    /// Returns the bytes representation of this multihash.
    pub fn as_bytes(&self) -> &'a [u8] {
        &self.bytes
    }
}

impl<'a> PartialEq<Multihash> for MultihashRef<'a> {
    fn eq(&self, other: &Multihash) -> bool {
        self.as_bytes() == &*other.as_bytes()
    }
}

impl<'a> ops::Deref for MultihashRef<'a> {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.as_bytes()
    }
}

impl<'a> Into<Vec<u8>> for MultihashRef<'a> {
    fn into(self) -> Vec<u8> {
        self.to_vec()
    }
}

/// The `MultihashDigest` trait specifies an interface common for all multihash functions.
pub trait MultihashDigest {
    /// The Mutlihash byte value.
    fn code(&self) -> Code;

    /// Hash some input and return the digest.
    ///
    /// # Panics
    ///
    /// Panics if the digest length is bigger than 2^32. This only happens for identity hasing.
    fn digest(&self, data: &[u8]) -> Multihash;
}

/// Wraps a hash digest in Multihash with the given Mutlihash code.
///
/// The size of the hash is determoned by the size of the input hash. If it should be truncated
/// the input data must already be the truncated hash.
pub fn wrap(code: Code, data: &[u8]) -> Multihash {
    let mut code_buf = varint_encode::u64_buffer();
    let code = varint_encode::u64(code.to_u64(), &mut code_buf);

    let mut size_buf = varint_encode::u64_buffer();
    let size = varint_encode::u64(data.len() as u64, &mut size_buf);

    Multihash {
        storage: Storage::from_slices(&[code, &size, &data]),
    }
}
<|endoftext|>