<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

// Useful for adding comments about different branches
#![allow(clippy::if_same_then_else)]
// Useful in the syscall function
#![allow(clippy::many_single_char_names)]
// Used for context::context
#![allow(clippy::module_inception)]
// Not implementing default is sometimes useful in the case something has significant cost
// to allocate. If you implement default, it can be allocated without evidence using the
// ..Default::default() syntax. Not fun in kernel space
#![allow(clippy::new_without_default)]
// Used to make it nicer to return errors, for example, .ok_or(Error::new(ESRCH))
#![allow(clippy::or_fun_call)]
// This is needed in some cases, like for syscall
#![allow(clippy::too_many_arguments)]
// There is no harm in this being done
#![allow(clippy::useless_format)]

// TODO: address ocurrances and then deny
#![warn(clippy::not_unsafe_ptr_arg_deref)]
// TODO: address ocurrances and then deny
#![warn(clippy::cast_ptr_alignment)]
// Indexing a slice can cause panics and that is something we always want to avoid
// in kernel code. Use .get and return an error instead
// TODO: address ocurrances and then deny
#![warn(clippy::indexing_slicing)]
// Overflows are very, very bad in kernel code as it may provide an attack vector for
// userspace applications, and it is only checked in debug builds
// TODO: address ocurrances and then deny
#![warn(clippy::integer_arithmetic)]
// Avoid panicking in the kernel without information about the panic. Use expect
// TODO: address ocurrances and then deny
#![warn(clippy::result_unwrap_used)]

// This is usually a serious issue - a missing import of a define where it is interpreted
// as a catch-all variable in a match, for example
#![deny(unreachable_patterns)]

#![feature(allocator_api)]
#![feature(asm)] // TODO: Relax requirements of most asm invocations
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(global_asm)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate rustc_demangle;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::scheme::{FileHandle, SchemeNamespace};

pub use crate::consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use crate::arch::*;

use crate::log::info;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Logging
pub mod log;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Process tracing
pub mod ptrace;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = AtomicUsize::new(0);

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = AtomicUsize::new(0);

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    info!("BSP: {:?} {}", pid, cpus);
    info!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        info!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        info!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    info!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            info!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }

    // Try running kill(getpid(), signal), but fallback to exiting
    syscall::getpid()
        .and_then(|pid| syscall::kill(pid, signal).map(|_| ()))
        .unwrap_or_else(|_| {
            syscall::exit(signal & 0x7F);
        });
}
<commit_msg>elaborate error message for initfs chdir failure<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

// Useful for adding comments about different branches
#![allow(clippy::if_same_then_else)]
// Useful in the syscall function
#![allow(clippy::many_single_char_names)]
// Used for context::context
#![allow(clippy::module_inception)]
// Not implementing default is sometimes useful in the case something has significant cost
// to allocate. If you implement default, it can be allocated without evidence using the
// ..Default::default() syntax. Not fun in kernel space
#![allow(clippy::new_without_default)]
// Used to make it nicer to return errors, for example, .ok_or(Error::new(ESRCH))
#![allow(clippy::or_fun_call)]
// This is needed in some cases, like for syscall
#![allow(clippy::too_many_arguments)]
// There is no harm in this being done
#![allow(clippy::useless_format)]

// TODO: address ocurrances and then deny
#![warn(clippy::not_unsafe_ptr_arg_deref)]
// TODO: address ocurrances and then deny
#![warn(clippy::cast_ptr_alignment)]
// Indexing a slice can cause panics and that is something we always want to avoid
// in kernel code. Use .get and return an error instead
// TODO: address ocurrances and then deny
#![warn(clippy::indexing_slicing)]
// Overflows are very, very bad in kernel code as it may provide an attack vector for
// userspace applications, and it is only checked in debug builds
// TODO: address ocurrances and then deny
#![warn(clippy::integer_arithmetic)]
// Avoid panicking in the kernel without information about the panic. Use expect
// TODO: address ocurrances and then deny
#![warn(clippy::result_unwrap_used)]

// This is usually a serious issue - a missing import of a define where it is interpreted
// as a catch-all variable in a match, for example
#![deny(unreachable_patterns)]

#![feature(allocator_api)]
#![feature(asm)] // TODO: Relax requirements of most asm invocations
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(global_asm)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate rustc_demangle;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::scheme::{FileHandle, SchemeNamespace};

pub use crate::consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use crate::arch::*;

use crate::log::info;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Logging
pub mod log;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Process tracing
pub mod ptrace;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = AtomicUsize::new(0);

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = AtomicUsize::new(0);

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    if let Err(err) = syscall::chdir(b"initfs:") {
        info!("Failed to enter initfs ({}).", err);
        info!("Perhaps the kernel was compiled with an incorrect INITFS_FOLDER \
               environment variable value?");
        panic!("Unexpected error while trying to enter initfs:.");
    }

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    info!("BSP: {:?} {}", pid, cpus);
    info!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        info!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        info!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    info!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            info!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }

    // Try running kill(getpid(), signal), but fallback to exiting
    syscall::getpid()
        .and_then(|pid| syscall::kill(pid, signal).map(|_| ()))
        .unwrap_or_else(|_| {
            syscall::exit(signal & 0x7F);
        });
}
<|endoftext|>


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

//! Graphics state blocks for gfx-rs

#![deny(missing_docs, missing_copy_implementations)]

#[macro_use]
extern crate bitflags;

mod preset;
pub mod state;
pub mod target;

pub use preset::{blend};

/// Compile-time maximum MRT count.
pub const MAX_COLOR_TARGETS:      usize = 4;

/// An assembly of states that affect regular draw calls.
/// Note: reference values are separated from their control blocks
/// due to the fact they can be provided separately from the state setup
/// on the modern hardware (DX11+).
#[must_use]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct DrawState {
    /// How to rasterize geometric primitives.
    pub rasterizer: state::Rasterizer,
    /// Scissor mask to use. If set, no pixel outside of this rectangle (in screen space) will be
    /// written to as a result of rendering.
    pub scissor: Option<target::Rect>,
    /// Stencil test to use. If None, no stencil testing is done.
    pub stencil: Option<state::Stencil>,
    /// Depth test to use. If None, no depth testing is done.
    pub depth: Option<state::Depth>,
    /// Blend function to use. If None, no blending is done.
    pub blend: [Option<state::Blend>; MAX_COLOR_TARGETS],
    /// A set of reference values.
    pub ref_values: state::RefValues,
}

impl DrawState {
    /// Create a default `DrawState`. Uses counter-clockwise winding, culls the backface of each
    /// primitive, and does no scissor/stencil/depth/blend/color masking.
    pub fn new() -> DrawState {
        DrawState {
            rasterizer: state::Rasterizer::new_fill(state::CullFace::Nothing),
            scissor: None,
            stencil: None,
            depth: None,
            blend: [None; MAX_COLOR_TARGETS],
            ref_values: Default::default(),
        }
    }

    /// Return a target mask that contains all the planes required by this state.
    pub fn get_target_mask(&self) -> target::Mask {
        use target as t;
        (if self.stencil.is_some()  {t::STENCIL} else {t::Mask::empty()}) |
        (if self.depth.is_some()    {t::DEPTH}   else {t::Mask::empty()}) |
        (if self.blend[0].is_some() {t::COLOR0}  else {t::Mask::empty()}) |
        (if self.blend[1].is_some() {t::COLOR1}  else {t::Mask::empty()}) |
        (if self.blend[2].is_some() {t::COLOR2}  else {t::Mask::empty()}) |
        (if self.blend[3].is_some() {t::COLOR3}  else {t::Mask::empty()})
    }

    /// Enable multi-sampled rasterization
    pub fn multi_sample(mut self) -> DrawState {
        self.rasterizer.samples = Some(state::MultiSample);
        self
    }

    /// Set the stencil test to a simple expression
    pub fn stencil(mut self, fun: state::Comparison, value: target::Stencil) -> DrawState {
        use state::StencilOp;
        let side = state::StencilSide {
            fun: fun,
            mask_read: target::Stencil::max_value(),
            mask_write: target::Stencil::max_value(),
            op_fail: StencilOp::Keep,
            op_depth_fail: StencilOp::Keep,
            op_pass: StencilOp::Keep,
        };
        self.stencil = Some(state::Stencil {
            front: side,
            back: side,
        });
        self.ref_values.stencil = (value, value);
        self
    }

    /// Set the depth test with the mask
    pub fn depth(mut self, fun: state::Comparison, write: bool) -> DrawState {
        self.depth = Some(state::Depth {
            fun: fun,
            write: write,
        });
        self
    }

    /// Set the scissor
    pub fn scissor(mut self, x: u16, y: u16, w: u16, h: u16) -> DrawState {
        self.scissor = Some(target::Rect { x: x, y: y, w: w, h: h });
        self
    }
}
<commit_msg>Exposed the preset module to public<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Graphics state blocks for gfx-rs

#![deny(missing_docs, missing_copy_implementations)]

#[macro_use]
extern crate bitflags;

pub mod preset;
pub mod state;
pub mod target;

/// Compile-time maximum MRT count.
pub const MAX_COLOR_TARGETS:      usize = 4;

/// An assembly of states that affect regular draw calls.
/// Note: reference values are separated from their control blocks
/// due to the fact they can be provided separately from the state setup
/// on the modern hardware (DX11+).
#[must_use]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct DrawState {
    /// How to rasterize geometric primitives.
    pub rasterizer: state::Rasterizer,
    /// Scissor mask to use. If set, no pixel outside of this rectangle (in screen space) will be
    /// written to as a result of rendering.
    pub scissor: Option<target::Rect>,
    /// Stencil test to use. If None, no stencil testing is done.
    pub stencil: Option<state::Stencil>,
    /// Depth test to use. If None, no depth testing is done.
    pub depth: Option<state::Depth>,
    /// Blend function to use. If None, no blending is done.
    pub blend: [Option<state::Blend>; MAX_COLOR_TARGETS],
    /// A set of reference values.
    pub ref_values: state::RefValues,
}

impl DrawState {
    /// Create a default `DrawState`. Uses counter-clockwise winding, culls the backface of each
    /// primitive, and does no scissor/stencil/depth/blend/color masking.
    pub fn new() -> DrawState {
        DrawState {
            rasterizer: state::Rasterizer::new_fill(state::CullFace::Nothing),
            scissor: None,
            stencil: None,
            depth: None,
            blend: [None; MAX_COLOR_TARGETS],
            ref_values: Default::default(),
        }
    }

    /// Return a target mask that contains all the planes required by this state.
    pub fn get_target_mask(&self) -> target::Mask {
        use target as t;
        (if self.stencil.is_some()  {t::STENCIL} else {t::Mask::empty()}) |
        (if self.depth.is_some()    {t::DEPTH}   else {t::Mask::empty()}) |
        (if self.blend[0].is_some() {t::COLOR0}  else {t::Mask::empty()}) |
        (if self.blend[1].is_some() {t::COLOR1}  else {t::Mask::empty()}) |
        (if self.blend[2].is_some() {t::COLOR2}  else {t::Mask::empty()}) |
        (if self.blend[3].is_some() {t::COLOR3}  else {t::Mask::empty()})
    }

    /// Enable multi-sampled rasterization
    pub fn multi_sample(mut self) -> DrawState {
        self.rasterizer.samples = Some(state::MultiSample);
        self
    }

    /// Set the stencil test to a simple expression
    pub fn stencil(mut self, fun: state::Comparison, value: target::Stencil) -> DrawState {
        use state::StencilOp;
        let side = state::StencilSide {
            fun: fun,
            mask_read: target::Stencil::max_value(),
            mask_write: target::Stencil::max_value(),
            op_fail: StencilOp::Keep,
            op_depth_fail: StencilOp::Keep,
            op_pass: StencilOp::Keep,
        };
        self.stencil = Some(state::Stencil {
            front: side,
            back: side,
        });
        self.ref_values.stencil = (value, value);
        self
    }

    /// Set the depth test with the mask
    pub fn depth(mut self, fun: state::Comparison, write: bool) -> DrawState {
        self.depth = Some(state::Depth {
            fun: fun,
            write: write,
        });
        self
    }

    /// Set the scissor
    pub fn scissor(mut self, x: u16, y: u16, w: u16, h: u16) -> DrawState {
        self.scissor = Some(target::Rect { x: x, y: y, w: w, h: h });
        self
    }
}
<|endoftext|>


<commit_before>extern crate ring;
extern crate toml;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate futures;
extern crate futures_cpupool;
#[macro_use]
extern crate tokio_io;
extern crate tokio_core;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate time;
extern crate ansi_term;

mod net;
mod buffer;
mod crypto;
mod socks5;
mod transfer;

pub mod config;
pub mod client;
pub mod server;
pub mod util;

mod v3 {
    use ring::digest::{Algorithm, SHA256, SHA256_OUTPUT_LEN};

    use crypto::Cipher;

    pub const VERSION: u8 = 0x03;
    pub const MAX_BUFFER_SIZE: usize = 32 * 1024 * 1024;
    pub const DATA_LEN_LEN: usize = 2;
    pub const MAX_PADDING_LEN: usize = 255;

    pub static DEFAULT_DIGEST: &'static Algorithm = &SHA256;
    pub const DEFAULT_DIGEST_LEN: usize = SHA256_OUTPUT_LEN;

    pub const HANDSHAKE_CIPHER: Cipher = Cipher::AES256GCM;

    pub const SERVER_RESP_SUCCESSD: u8 = 0x00;
    pub const SERVER_RESP_CIPHER_ERROR: u8 = 0x01;
    pub const SERVER_RESP_ERROR: u8 = 0x02;
    pub const SERVER_RESP_REMOTE_FAILED: u8 = 0x03;
}
<commit_msg>fix max buf size bug :)<commit_after>extern crate ring;
extern crate toml;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate futures;
extern crate futures_cpupool;
#[macro_use]
extern crate tokio_io;
extern crate tokio_core;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate time;
extern crate ansi_term;

mod net;
mod buffer;
mod crypto;
mod socks5;
mod transfer;

pub mod config;
pub mod client;
pub mod server;
pub mod util;

mod v3 {
    use ring::digest::{Algorithm, SHA256, SHA256_OUTPUT_LEN};

    use crypto::Cipher;

    pub const VERSION: u8 = 0x03;
    pub const MAX_BUFFER_SIZE: usize = 32 * 1024;
    pub const DATA_LEN_LEN: usize = 2;
    pub const MAX_PADDING_LEN: usize = 255;

    pub static DEFAULT_DIGEST: &'static Algorithm = &SHA256;
    pub const DEFAULT_DIGEST_LEN: usize = SHA256_OUTPUT_LEN;

    pub const HANDSHAKE_CIPHER: Cipher = Cipher::AES256GCM;

    pub const SERVER_RESP_SUCCESSD: u8 = 0x00;
    pub const SERVER_RESP_CIPHER_ERROR: u8 = 0x01;
    pub const SERVER_RESP_ERROR: u8 = 0x02;
    pub const SERVER_RESP_REMOTE_FAILED: u8 = 0x03;
}
<|endoftext|>


<commit_before>#![feature(scoped)]

extern crate threadpool;
extern crate time;

use threadpool::ThreadPool;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::rc::Rc;
use std::fmt::{Formatter, Error, Debug};
use std::collections::vec_deque::VecDeque;

#[cfg(test)]
mod test;

pub struct Subscription{
	pubsub: PubSub,
	channel_id: String,
	id: u64
}

impl Debug for Subscription{
	fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error>{
		fmt.write_str(&format!("Sub(channel={})", self.channel_id))
	}
}

impl Subscription{
	pub fn cancel(self){}
}
impl Drop for Subscription{
	fn drop(&mut self){
		self.pubsub.unregister(self);
	}
}
//impl Deref for Subscription{
//	type Target = Receiver<String>;
//	fn deref<'a>(&'a self) -> &'a Receiver<String>{
//		&self.receiver
//	}
//}
struct SubData{
	running: RAIIBool,
	backlog: VecDeque<String>,
	func: Arc<Mutex<Box<FnMut(String) + Send>>>
}

struct InnerPubSub{
	channels: HashMap<String, HashMap<u64, SubData>>,

	//id will stay unique for hundreds of years, even at ~1 billion/sec
	next_id: u64,
	thread_pool: Rc<ThreadPool>
}
#[derive(Clone)]
pub struct PubSub{
	inner: Arc<Mutex<InnerPubSub>>
}
unsafe impl Send for PubSub{}

#[derive(Clone)]
pub struct RAIIBool{
	value: Arc<Mutex<bool>>
}
impl RAIIBool{
	fn new(value: bool) -> RAIIBool{
		RAIIBool{
			value: Arc::new(Mutex::new(value))
		}
	}
	fn get(&self) -> bool{
		*self.value.lock().unwrap()
	}
	fn set(&self, value: bool){
		*self.value.lock().unwrap() = value;
	}
	fn new_guard(&self, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard::new(self.clone(), value)
	}
}

pub struct RAIIBoolGuard{
	data: RAIIBool,
	value: bool
}
impl RAIIBoolGuard{
	fn new(data: RAIIBool, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard{
			data: data,
			value: value
		}
	}
	fn done(self){}
}
impl Drop for RAIIBoolGuard{
	fn drop(&mut self){
		self.data.set(self.value);
	}
}
//pub struct RAIIBool{
//	value: Rc<Cell<bool>>
//}
//impl RAIIBool{
//	fn new<F>(value: bool) -> RAIIBool{
//		RAIIBool{
//			value: Cell::new(value)
//		}
//	}
//	fn get(setValue:bool, finalValue:bool) -> RAIIGuard{
//
//	}
//}
impl PubSub{
	pub fn new(num_threads: usize) -> PubSub{
		PubSub{
			inner: Arc::new(Mutex::new(InnerPubSub{
				channels: HashMap::new(),
				next_id: 0,
				thread_pool: Rc::new(ThreadPool::new(num_threads))
			}))
		}
	}
	pub fn subscribe<F>(&self, channel: &str, func: F) -> Subscription
	where F:FnMut(String) + 'static + Send{
		let mut data = self.inner.lock().unwrap();
		//let mut inner: &mut InnerPubSub = &mut *lock_guard;
		if !data.channels.contains_key(channel){
			data.channels.insert(channel.to_string(), HashMap::new());
		}
		let id = data.next_id;
		data.next_id += 1;

		let sub_data = SubData{
			running: RAIIBool::new(false),
			backlog: VecDeque::new(),
			func: Arc::new(Mutex::new(Box::new(func)))
		};

		let subscriptions = data.channels.get_mut(channel).unwrap();
		subscriptions.insert(id, sub_data);
		Subscription{
			pubsub: self.clone(),
			channel_id: channel.to_string(),
			id: id
		}
	}
	pub fn num_channels(&self) -> usize{
		let data = self.inner.lock().unwrap();
		data.channels.len()
	}
	fn unregister(&self, sub: &Subscription){
		let mut inner = self.inner.lock().unwrap();
		let mut remove_channel = false;
		{
			let sub_list = inner.channels.get_mut(&sub.channel_id).unwrap();
			sub_list.remove(&sub.id);
			if sub_list.len() == 0{
				remove_channel = true;
			}
		}
		if remove_channel{
			inner.channels.remove(&sub.channel_id);
		}
	}
	pub fn notify(&self, channel: &str, msg: &str){
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		if let Some(subscriptions) = inner.channels.get_mut(channel){
			for (id,sub_data) in subscriptions{
				sub_data.backlog.push_back(msg.to_string());
				if sub_data.running.get(){
					println!("already running, nothing to do");
				}else{
					let thread_running = sub_data.running.clone();
					thread_running.set(true);

					let func:Arc<Mutex<Box<FnMut(String) + Send>>> = sub_data.func.clone();
					let pubsub = self.clone();
					let channel = channel.to_string();
					let id = id.clone();
					pool.execute(move ||{
						use std::ops::DerefMut;

						let finish_guard = thread_running.new_guard(false);
						println!("running on thread pool");
						let mut guard = func.lock().unwrap();
						let mut func = guard.deref_mut();
						let mut running = true;
						while running{
							let mut notification_message = None;

							{
								let mut inner = pubsub.inner.lock().unwrap();
								if let Some(subs) = inner.channels.get_mut(&channel){
									if let Some(sub_data) = subs.get_mut(&id){
										println!("backlog_size:{}", sub_data.backlog.len());
										if let Some(msg) = sub_data.backlog.pop_front(){
											notification_message = Some(msg);
										}
									}
								}
							}//unlock 'inner'

							if let Some(msg) = notification_message{
								func(msg);
							}else{
								running = false;
							}
						}
						finish_guard.done();
					});
					println!("need to assign thread, none running");
				}
//				match subData.func.try_lock(){
//					Ok(guard) => {
//						println!("need to run immediately: channel= {}, data= {}", channel, msg);
//						//let func = Arc::new(Mutex::new(guard));
//						pool.execute(move || {
//
//							println!("running in thread pool");
//							guard(msg);
//						});
//					},
//					Err(_) => {
//						println!("need to queue: channel= {}, data= {}", channel, msg);
//					}
//				}

				//let _ = sender.send(msg.to_string());
			}
		}
	}
}
<commit_msg>add Sync to PubSub<commit_after>#![feature(scoped)]

extern crate threadpool;
extern crate time;

use threadpool::ThreadPool;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::rc::Rc;
use std::fmt::{Formatter, Error, Debug};
use std::collections::vec_deque::VecDeque;

#[cfg(test)]
mod test;

pub struct Subscription{
	pubsub: PubSub,
	channel_id: String,
	id: u64
}

impl Debug for Subscription{
	fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error>{
		fmt.write_str(&format!("Sub(channel={})", self.channel_id))
	}
}

impl Subscription{
	pub fn cancel(self){}
}
impl Drop for Subscription{
	fn drop(&mut self){
		self.pubsub.unregister(self);
	}
}
//impl Deref for Subscription{
//	type Target = Receiver<String>;
//	fn deref<'a>(&'a self) -> &'a Receiver<String>{
//		&self.receiver
//	}
//}
struct SubData{
	running: RAIIBool,
	backlog: VecDeque<String>,
	func: Arc<Mutex<Box<FnMut(String) + Send>>>
}

struct InnerPubSub{
	channels: HashMap<String, HashMap<u64, SubData>>,

	//id will stay unique for hundreds of years, even at ~1 billion/sec
	next_id: u64,
	thread_pool: Rc<ThreadPool>
}
#[derive(Clone)]
pub struct PubSub{
	inner: Arc<Mutex<InnerPubSub>>
}
unsafe impl Send for PubSub{}
unsafe impl Sync for PubSub{}

#[derive(Clone)]
pub struct RAIIBool{
	value: Arc<Mutex<bool>>
}
impl RAIIBool{
	fn new(value: bool) -> RAIIBool{
		RAIIBool{
			value: Arc::new(Mutex::new(value))
		}
	}
	fn get(&self) -> bool{
		*self.value.lock().unwrap()
	}
	fn set(&self, value: bool){
		*self.value.lock().unwrap() = value;
	}
	fn new_guard(&self, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard::new(self.clone(), value)
	}
}

pub struct RAIIBoolGuard{
	data: RAIIBool,
	value: bool
}
impl RAIIBoolGuard{
	fn new(data: RAIIBool, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard{
			data: data,
			value: value
		}
	}
	fn done(self){}
}
impl Drop for RAIIBoolGuard{
	fn drop(&mut self){
		self.data.set(self.value);
	}
}
//pub struct RAIIBool{
//	value: Rc<Cell<bool>>
//}
//impl RAIIBool{
//	fn new<F>(value: bool) -> RAIIBool{
//		RAIIBool{
//			value: Cell::new(value)
//		}
//	}
//	fn get(setValue:bool, finalValue:bool) -> RAIIGuard{
//
//	}
//}
impl PubSub{
	pub fn new(num_threads: usize) -> PubSub{
		PubSub{
			inner: Arc::new(Mutex::new(InnerPubSub{
				channels: HashMap::new(),
				next_id: 0,
				thread_pool: Rc::new(ThreadPool::new(num_threads))
			}))
		}
	}
	pub fn subscribe<F>(&self, channel: &str, func: F) -> Subscription
	where F:FnMut(String) + 'static + Send{
		let mut data = self.inner.lock().unwrap();
		//let mut inner: &mut InnerPubSub = &mut *lock_guard;
		if !data.channels.contains_key(channel){
			data.channels.insert(channel.to_string(), HashMap::new());
		}
		let id = data.next_id;
		data.next_id += 1;

		let sub_data = SubData{
			running: RAIIBool::new(false),
			backlog: VecDeque::new(),
			func: Arc::new(Mutex::new(Box::new(func)))
		};

		let subscriptions = data.channels.get_mut(channel).unwrap();
		subscriptions.insert(id, sub_data);
		Subscription{
			pubsub: self.clone(),
			channel_id: channel.to_string(),
			id: id
		}
	}
	pub fn num_channels(&self) -> usize{
		let data = self.inner.lock().unwrap();
		data.channels.len()
	}
	fn unregister(&self, sub: &Subscription){
		let mut inner = self.inner.lock().unwrap();
		let mut remove_channel = false;
		{
			let sub_list = inner.channels.get_mut(&sub.channel_id).unwrap();
			sub_list.remove(&sub.id);
			if sub_list.len() == 0{
				remove_channel = true;
			}
		}
		if remove_channel{
			inner.channels.remove(&sub.channel_id);
		}
	}
	pub fn notify(&self, channel: &str, msg: &str){
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		if let Some(subscriptions) = inner.channels.get_mut(channel){
			for (id,sub_data) in subscriptions{
				sub_data.backlog.push_back(msg.to_string());
				if sub_data.running.get(){
					println!("already running, nothing to do");
				}else{
					let thread_running = sub_data.running.clone();
					thread_running.set(true);

					let func:Arc<Mutex<Box<FnMut(String) + Send>>> = sub_data.func.clone();
					let pubsub = self.clone();
					let channel = channel.to_string();
					let id = id.clone();
					pool.execute(move ||{
						use std::ops::DerefMut;

						let finish_guard = thread_running.new_guard(false);
						println!("running on thread pool");
						let mut guard = func.lock().unwrap();
						let mut func = guard.deref_mut();
						let mut running = true;
						while running{
							let mut notification_message = None;

							{
								let mut inner = pubsub.inner.lock().unwrap();
								if let Some(subs) = inner.channels.get_mut(&channel){
									if let Some(sub_data) = subs.get_mut(&id){
										println!("backlog_size:{}", sub_data.backlog.len());
										if let Some(msg) = sub_data.backlog.pop_front(){
											notification_message = Some(msg);
										}
									}
								}
							}//unlock 'inner'

							if let Some(msg) = notification_message{
								func(msg);
							}else{
								running = false;
							}
						}
						finish_guard.done();
					});
					println!("need to assign thread, none running");
				}
//				match subData.func.try_lock(){
//					Ok(guard) => {
//						println!("need to run immediately: channel= {}, data= {}", channel, msg);
//						//let func = Arc::new(Mutex::new(guard));
//						pool.execute(move || {
//
//							println!("running in thread pool");
//							guard(msg);
//						});
//					},
//					Err(_) => {
//						println!("need to queue: channel= {}, data= {}", channel, msg);
//					}
//				}

				//let _ = sender.send(msg.to_string());
			}
		}
	}
}
<|endoftext|>


<commit_before>extern crate nom;

use std::str;
use nom::*;

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}

fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_uchar(c: char) -> bool {
    c == '\\' || c == 'u' || is_hex_digit(c as u8)
}

fn is_echar(c: char) -> bool {
    c == '\\' || c == 't' || c == 'b' || c == 'n' || c == 'r' || c == 'f' || c == '"'
}

/* [159s] UCHAR */
named!(uchar<&str, &str>, alt!(
    verify!(
        take_s!(6),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'u'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    ) |
    verify!(
        take_s!(10),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'U'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    )
));

/* [159s] ECHAR */
named!(echar<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '\\'
            } else {
                is_echar(c)
            }
        })
    }
));

/* [161s] WS */
named!(ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

fn is_pn_local(c: char) -> bool {
    is_pn_chars(c) ||
    c == '.'  || c == ':'              ||
    c == '%'  || is_hex_digit(c as u8) ||
    c == '\\' || is_pn_local_esc(c)
}
/* [168s] PN_LOCAL */
named!(pn_local<&str, &str>, verify!(
    take_while_s!(is_pn_local),
    |val:&str| {
        let len = val.char_indices().count();
        let mut percent_count = 0;
        let mut pn_local_esc_count = 0;
        val.char_indices().all(|(idx, c)| {
            if percent_count > 0 {
                percent_count = percent_count - 1;
                is_hex_digit(c as u8)
            } else if c == '%' {
                percent_count = 2;
                true
            } else if pn_local_esc_count > 0 {
                pn_local_esc_count = pn_local_esc_count - 1;
                is_pn_local_esc(c)
            } else if c == '\\' {
                pn_local_esc_count = 1;
                true
            } else if idx == 0 {
                is_pn_chars_u(c) || c == ':'
            } else if idx == len - 1 {
                is_pn_chars(c) || c == ':'
            } else {
                is_pn_chars(c) || c == ':' || c == '.'
            }
        }) && percent_count == 0 && pn_local_esc_count == 0
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

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

    #[test]
    fn uchar_test() {
        assert_eq!(uchar("\\u02FFa")         , IResult::Done("a", "\\u02FF")    );
        assert_eq!(uchar("\\U02FFAABBa")     , IResult::Done("a", "\\U02FFAABB"));
    }

    #[test]
    fn echar_test() {
        assert_eq!(echar("\\ta"), IResult::Done("a", "\\t"));
    }

    #[test]
    fn ws_test() {
        assert_eq!(ws("   a"), IResult::Done("a", "   "));
    }

    #[test]
    fn anon_test() {
        assert_eq!(anon("[ ]a"), IResult::Done("a", "[ ]"));
    }

    #[test]
    fn pn_chars_base_test() {
        assert_eq!(pn_chars_base("a%2Ab"), IResult::Done("%2Ab", "a"));
    }

    #[test]
    fn pn_chars_u_test() {
        assert_eq!(pn_chars_u("_a"), IResult::Done("a", "_"));
    }

    #[test]
    fn pn_chars_test() {
        assert_eq!(pn_chars("-_a")  , IResult::Done("_a"  , "-")       );
        assert_eq!(pn_chars(":a2Ab"), IResult::Error(ErrorKind::Verify));
    }

    #[test]
    fn pn_prefix_test() {
        assert_eq!(pn_prefix("hog.e:"), IResult::Done(":", "hog.e")      );
        assert_eq!(pn_prefix("hoge.:"), IResult::Error(ErrorKind::Verify));
    }

    #[test]
    fn pn_local_test() {
        assert_eq!(pn_local("hoge:fuga piyo"), IResult::Done(" piyo", "hoge:fuga"));
        assert_eq!(pn_local("hoge:%28 piyo") , IResult::Done(" piyo", "hoge:%28") );
        assert_eq!(pn_local("hoge:%2 piyo")  , IResult::Error(ErrorKind::Verify)  );
        assert_eq!(pn_local("hoge:%__ piyo") , IResult::Error(ErrorKind::Verify)  );
        assert_eq!(pn_local("hoge:\\* piyo") , IResult::Done(" piyo", "hoge:\\*") );
        assert_eq!(pn_local("%28\\* piyo")   , IResult::Done(" piyo", "%28\\*")   );
        assert_eq!(pn_local("%28\\ piyo")    , IResult::Error(ErrorKind::Verify)  );
    }

    #[test]
    fn plx_test() {
        assert_eq!(plx("%2Abc") , IResult::Done("bc" , "%2A"));
        assert_eq!(plx("\\.%2A"), IResult::Done("%2A", "\\."));
    }

    #[test]
    fn percent_test() {
        assert_eq!(percent("%2Abc"), IResult::Done("bc", "%2A"));
    }

    #[test]
    fn pn_local_esc_test() {
        assert_eq!(pn_local_esc("\\.a b c"), IResult::Done("a b c", "\\."));
    }
}
<commit_msg>Fix alignment<commit_after>extern crate nom;

use std::str;
use nom::*;

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}

fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_uchar(c: char) -> bool {
    c == '\\' || c == 'u' || is_hex_digit(c as u8)
}

fn is_echar(c: char) -> bool {
    c == '\\' || c == 't' || c == 'b' || c == 'n' || c == 'r' || c == 'f' || c == '"'
}

/* [159s] UCHAR */
named!(uchar<&str, &str>, alt!(
    verify!(
        take_s!(6),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'u'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    ) |
    verify!(
        take_s!(10),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'U'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    )
));

/* [159s] ECHAR */
named!(echar<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '\\'
            } else {
                is_echar(c)
            }
        })
    }
));

/* [161s] WS */
named!(ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

fn is_pn_local(c: char) -> bool {
    is_pn_chars(c) ||
    c == '.'  || c == ':'              ||
    c == '%'  || is_hex_digit(c as u8) ||
    c == '\\' || is_pn_local_esc(c)
}
/* [168s] PN_LOCAL */
named!(pn_local<&str, &str>, verify!(
    take_while_s!(is_pn_local),
    |val:&str| {
        let len = val.char_indices().count();
        let mut percent_count = 0;
        let mut pn_local_esc_count = 0;
        val.char_indices().all(|(idx, c)| {
            if percent_count > 0 {
                percent_count = percent_count - 1;
                is_hex_digit(c as u8)
            } else if c == '%' {
                percent_count = 2;
                true
            } else if pn_local_esc_count > 0 {
                pn_local_esc_count = pn_local_esc_count - 1;
                is_pn_local_esc(c)
            } else if c == '\\' {
                pn_local_esc_count = 1;
                true
            } else if idx == 0 {
                is_pn_chars_u(c) || c == ':'
            } else if idx == len - 1 {
                is_pn_chars(c) || c == ':'
            } else {
                is_pn_chars(c) || c == ':' || c == '.'
            }
        }) && percent_count == 0 && pn_local_esc_count == 0
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

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

    #[test]
    fn uchar_test() {
        assert_eq!(uchar("\\u02FFa")    , IResult::Done("a", "\\u02FF")    );
        assert_eq!(uchar("\\U02FFAABBa"), IResult::Done("a", "\\U02FFAABB"));
    }

    #[test]
    fn echar_test() {
        assert_eq!(echar("\\ta"), IResult::Done("a", "\\t"));
    }

    #[test]
    fn ws_test() {
        assert_eq!(ws("   a"), IResult::Done("a", "   "));
    }

    #[test]
    fn anon_test() {
        assert_eq!(anon("[ ]a"), IResult::Done("a", "[ ]"));
    }

    #[test]
    fn pn_chars_base_test() {
        assert_eq!(pn_chars_base("a%2Ab"), IResult::Done("%2Ab", "a"));
    }

    #[test]
    fn pn_chars_u_test() {
        assert_eq!(pn_chars_u("_a"), IResult::Done("a", "_"));
    }

    #[test]
    fn pn_chars_test() {
        assert_eq!(pn_chars("-_a")  , IResult::Done("_a", "-")         );
        assert_eq!(pn_chars(":a2Ab"), IResult::Error(ErrorKind::Verify));
    }

    #[test]
    fn pn_prefix_test() {
        assert_eq!(pn_prefix("hog.e:"), IResult::Done(":", "hog.e")      );
        assert_eq!(pn_prefix("hoge.:"), IResult::Error(ErrorKind::Verify));
    }

    #[test]
    fn pn_local_test() {
        assert_eq!(pn_local("hoge:fuga piyo"), IResult::Done(" piyo", "hoge:fuga"));
        assert_eq!(pn_local("hoge:%28 piyo") , IResult::Done(" piyo", "hoge:%28") );
        assert_eq!(pn_local("hoge:%2 piyo")  , IResult::Error(ErrorKind::Verify)  );
        assert_eq!(pn_local("hoge:%__ piyo") , IResult::Error(ErrorKind::Verify)  );
        assert_eq!(pn_local("hoge:\\* piyo") , IResult::Done(" piyo", "hoge:\\*") );
        assert_eq!(pn_local("%28\\* piyo")   , IResult::Done(" piyo", "%28\\*")   );
        assert_eq!(pn_local("%28\\ piyo")    , IResult::Error(ErrorKind::Verify)  );
    }

    #[test]
    fn plx_test() {
        assert_eq!(plx("%2Abc") , IResult::Done("bc" , "%2A"));
        assert_eq!(plx("\\.%2A"), IResult::Done("%2A", "\\."));
    }

    #[test]
    fn percent_test() {
        assert_eq!(percent("%2Abc"), IResult::Done("bc", "%2A"));
    }

    #[test]
    fn pn_local_esc_test() {
        assert_eq!(pn_local_esc("\\.a b c"), IResult::Done("a b c", "\\."));
    }
}
<|endoftext|>


<commit_before>//! # Scuttlebutt
//!
//! Scuttlebutt is an interface for extending kubernetes by feeding off a stream of kubernetes
//! cluster events

#[macro_use]
extern crate log;
extern crate hyper;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use hyper::{Client, Error as HttpError, Url};
use std::env;
use std::io::{self, Read};
use std::sync::mpsc::{channel, Receiver};
use std::thread;

// Kubernets cluster event
#[derive(Serialize, Deserialize, Debug)]
pub struct Event {
    pub object: Object,
    #[serde(rename = "type")]
    pub event_type: String,
}

/// A description of the event
#[derive(Serialize, Deserialize, Debug)]
pub struct Object {
    /// APIVersion defines the versioned schema of this representation of an object.
    /// Servers should convert recognized schemas to the latest internal value,
    /// and may reject unrecognized values. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#resources
    #[serde(rename = "apiVersion")]
    pub api_version: String,
    /// The number of times this event has occurred.
    pub count: usize,
    /// The time at which the event was first recorded. (Time of server receipt is in TypeMeta.)
    #[serde(rename = "firstTimestamp")]
    pub first_timestamp: String,
    /// The time at which the most recent occurrence of this event was recorded.
    #[serde(rename = "lastTimestamp")]
    pub last_timestamp: String,
    /// The object that this event is about.
    #[serde(rename = "involvedObject")]
    pub involved_object: ObjectReference,
    /// Kind is a string value representing the REST resource this object represents.
    /// Servers may infer this from the endpoint the client submits requests to.
    /// Cannot be updated. In CamelCase. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#types-kinds
    pub kind: String,
    /// A human-readable description of the status of this operation.
    pub message: String,
    /// Standard object’s metadata. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    pub metadata: ObjectMeta,
    /// This should be a short, machine understandable string that gives the reason for the
    /// transition into the object’s current status.
    pub reason: String,
    /// The component reporting this event. Should be a short machine understandable string.
    pub source: EventSource,
    /// Type of this event (Normal, Warning), new types could be added in the future
    #[serde(rename = "type")]
    pub object_type: String,
}

/// ObjectMeta is metadata that all persisted resources must have, which includes all
/// objects users must create.
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectMeta {
    /// CreationTimestamp is a timestamp representing the server time when this object was
    // created. It is not guaranteed to be set in happens-before order across separate operations.
    // Clients may not set this value. It is represented in RFC3339 form and is in UTC.
    /// Populated by the system. Read-only. Null for lists. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    #[serde(rename = "creationTimestamp")]
    pub creation_timestamp: String,
    /// DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted.
    /// This field is set by the server when a graceful deletion is requested by the user,
    // and is not directly settable by a client. The resource will be deleted (no longer visible
    // from resource lists, and not reachable by name) after the time in this field. Once set,
    /// this value may not be unset or be set further into the future, although it may be shortened
    /// or the resource may be deleted prior to this time. For example, a user may request that a
    /// pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination
    /// signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet
    /// will send a hard termination signal to the container. If not set, graceful deletion of
    /// the object has not been requested.
    /// Populated by the system when a graceful deletion is requested. Read-only. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    #[serde(rename = "deletionTimestamp")]
    pub deletion_timestamp: Option<String>,
    /// Name must be unique within a namespace. Is required when creating resources, although
    /// some resources may allow a client to request the generation of an appropriate name
    /// automatically. Name is primarily intended for creation idempotence and configuration
    /// definition. Cannot be updated. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#names
    pub name: String,
    /// Namespace defines the space within each name must be unique. An empty namespace is
    /// equivalent to the "default" namespace, but "default" is the canonical representation.
    /// Not all objects are required to be scoped to a namespace - the value of this field for
    /// those objects will be empty.
    /// Must be a DNS_LABEL. Cannot be updated. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/namespaces.md
    pub namespace: String,
    /// An opaque value that represents the internal version of this object that can be used
    /// by clients to determine when objects have changed. May be used for optimistic concurrency,
    /// change detection, and the watch operation on a resource or set of resources.
    /// Clients must treat these values as opaque and passed unmodified back to the server.
    /// They may only be valid for a particular resource or set of resources.
    /// Populated by the system. Read-only. Value must be treated as opaque by clients
    #[serde(rename = "resourceVersion")]
    pub resource_version: String,
    /// SelfLink is a URL representing this object. Populated by the system. Read-only.
    #[serde(rename = "selfLink")]
    pub self_link: String,
    /// UID is the unique in time and space value for this object. It is typically generated by
    /// the server on successful creation of a resource and is not allowed to change on PUT
    /// operations.
    /// Populated by the system. Read-only. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#uids
    pub uid: String,
}

/// EventSource contains information for an event.
#[derive(Serialize, Deserialize, Debug)]
pub struct EventSource {
    /// Component from which the event is generated.
    pub component: String,
    /// Host name on which the event is generated.
    pub host: Option<String>,
}

/// ObjectReference contains enough information to let you inspect or modify the referred object.
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectReference {
    /// API version of the referent.
    #[serde(rename = "apiVersion")]
    pub api_version: String,
    /// Specific resourceVersion to which this reference is made, if any.
    #[serde(rename = "resourceVersion")]
    pub resource_version: String,
    /// UID of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#uids
    pub uid: String,
    /// If referring to a piece of an object instead of an entire object,
    /// this string should contain a valid JSON/Go field access statement,
    /// such as desiredState.manifest.containers[2]. For example, if the object reference
    /// is to a container within a pod, this would take on a value like: "spec.containers{name}"
    /// (where "name" refers to the name of the container that triggered the event) or if no
    /// container name is specified "spec.containers[2]" (container with index 2 in this pod).
    /// This syntax is chosen only to have some well-defined way of referencing a part of an
    /// object.
    #[serde(rename = "fieldPath")]
    pub field_path: Option<String>,
    /// Kind of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#types-kinds
    pub kind: String,
    /// Name of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#names
    pub name: String,
    /// Namespace of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/namespaces.md
    pub namespace: String,
}

pub type Result<T> = std::result::Result<T, Error>;

/// An enumeratation of potential errors
#[derive(Debug)]
pub enum Error {
    Transport(HttpError),
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Transport(error)
    }
}

/// A cluster contains an address
/// for interacting with a kubernetes Cluster
/// of nodes
pub struct Cluster {
    host: Url,
}

/// Events provides a means for generating
/// a receiver for events
pub trait Events {
    fn events(&mut self) -> Result<Receiver<Event>>;

    fn generator<Bytes>(&self, bytes: Bytes) -> Result<Receiver<Event>>
    where
        Bytes: 'static + Iterator<Item = io::Result<u8>>,
        Bytes: Send,
    {
        let (tx, rx) = channel();
        let stream = serde_json::Deserializer::from_iter(bytes).into_iter::<Event>();
        thread::spawn(
            move || for e in stream {
                match e {
                    Ok(event) => {
                        if let Err(e) = tx.send(event) {
                            debug!("{:#?}", e);
                            break;
                        }
                    }
                    Err(e) => {
                        debug!("{:#?}", e);
                        break;
                    }
                }
            },
        );
        Ok(rx)
    }
}

impl Cluster {
    pub fn new() -> Cluster {
        let kubernetes_api_host: &str = &env::var("KUBERNETES_API_HOST").expect("KUBERNETES_API_HOST not set.");
        Cluster { host: Url::parse(kubernetes_api_host).unwrap() }
    }
}

impl Events for Cluster {
    fn events(&mut self) -> Result<Receiver<Event>> {
        let res = try!(
            Client::new()
                .get(self.host.join("/api/v1/events?watch=true").unwrap())
                .send()
        );
        self.generator(res.bytes())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::Receiver;
    #[test]
    fn events_generator() {
        impl Events for &'static str {
            fn events(&mut self) -> Result<Receiver<Event>> {
                self.generator(self.bytes().into_iter().map(|b| Ok(b)))
            }
        }
        let events = r#"{
            "object":{
                "apiVersion": "1",
                "count": 1,
                "firstTimestamp": "...",
                "lastTimestamp": "...",
                "kind":"Event",
                "message":"test",
                "involvedObject": {
                    "apiVersion": "1",
                    "resourceVersion": "2",
                    "uid":"2",
                    "kind": "POD",
                    "name": "test_name",
                    "namespace": "test_namespace"
                },
                "metadata": {
                    "creationTimestamp": "...",
                    "deletionTimestamp": "...",
                    "name": "test",
                    "namespace":"default",
                    "resourceVersion": "1",
                    "selfLink": "...",
                    "uid": "1"
                },
                "reason": "started",
                "source": {
                    "component": "test",
                    "host": "foo.com"
                },
                "type": "Normal"
            },
            "type":"ADDED"
        }"#
                .events();
        assert!(
            events
                .unwrap()
                .into_iter()
                .map(|e| e.object.involved_object.namespace)
                .nth(0) == Some("test_namespace".to_owned())
        )
    }
}
<commit_msg>Add default host as fallback. (#3)<commit_after>//! # Scuttlebutt
//!
//! Scuttlebutt is an interface for extending kubernetes by feeding off a stream of kubernetes
//! cluster events

#[macro_use]
extern crate log;
extern crate hyper;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use hyper::{Client, Error as HttpError, Url};
use std::env;
use std::io::{self, Read};
use std::sync::mpsc::{channel, Receiver};
use std::thread;

// Kubernets cluster event
#[derive(Serialize, Deserialize, Debug)]
pub struct Event {
    pub object: Object,
    #[serde(rename = "type")]
    pub event_type: String,
}

/// A description of the event
#[derive(Serialize, Deserialize, Debug)]
pub struct Object {
    /// APIVersion defines the versioned schema of this representation of an object.
    /// Servers should convert recognized schemas to the latest internal value,
    /// and may reject unrecognized values. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#resources
    #[serde(rename = "apiVersion")]
    pub api_version: String,
    /// The number of times this event has occurred.
    pub count: usize,
    /// The time at which the event was first recorded. (Time of server receipt is in TypeMeta.)
    #[serde(rename = "firstTimestamp")]
    pub first_timestamp: String,
    /// The time at which the most recent occurrence of this event was recorded.
    #[serde(rename = "lastTimestamp")]
    pub last_timestamp: String,
    /// The object that this event is about.
    #[serde(rename = "involvedObject")]
    pub involved_object: ObjectReference,
    /// Kind is a string value representing the REST resource this object represents.
    /// Servers may infer this from the endpoint the client submits requests to.
    /// Cannot be updated. In CamelCase. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#types-kinds
    pub kind: String,
    /// A human-readable description of the status of this operation.
    pub message: String,
    /// Standard object’s metadata. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    pub metadata: ObjectMeta,
    /// This should be a short, machine understandable string that gives the reason for the
    /// transition into the object’s current status.
    pub reason: String,
    /// The component reporting this event. Should be a short machine understandable string.
    pub source: EventSource,
    /// Type of this event (Normal, Warning), new types could be added in the future
    #[serde(rename = "type")]
    pub object_type: String,
}

/// ObjectMeta is metadata that all persisted resources must have, which includes all
/// objects users must create.
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectMeta {
    /// CreationTimestamp is a timestamp representing the server time when this object was
    // created. It is not guaranteed to be set in happens-before order across separate operations.
    // Clients may not set this value. It is represented in RFC3339 form and is in UTC.
    /// Populated by the system. Read-only. Null for lists. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    #[serde(rename = "creationTimestamp")]
    pub creation_timestamp: String,
    /// DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted.
    /// This field is set by the server when a graceful deletion is requested by the user,
    // and is not directly settable by a client. The resource will be deleted (no longer visible
    // from resource lists, and not reachable by name) after the time in this field. Once set,
    /// this value may not be unset or be set further into the future, although it may be shortened
    /// or the resource may be deleted prior to this time. For example, a user may request that a
    /// pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination
    /// signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet
    /// will send a hard termination signal to the container. If not set, graceful deletion of
    /// the object has not been requested.
    /// Populated by the system when a graceful deletion is requested. Read-only. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#metadata
    #[serde(rename = "deletionTimestamp")]
    pub deletion_timestamp: Option<String>,
    /// Name must be unique within a namespace. Is required when creating resources, although
    /// some resources may allow a client to request the generation of an appropriate name
    /// automatically. Name is primarily intended for creation idempotence and configuration
    /// definition. Cannot be updated. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#names
    pub name: String,
    /// Namespace defines the space within each name must be unique. An empty namespace is
    /// equivalent to the "default" namespace, but "default" is the canonical representation.
    /// Not all objects are required to be scoped to a namespace - the value of this field for
    /// those objects will be empty.
    /// Must be a DNS_LABEL. Cannot be updated. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/namespaces.md
    pub namespace: String,
    /// An opaque value that represents the internal version of this object that can be used
    /// by clients to determine when objects have changed. May be used for optimistic concurrency,
    /// change detection, and the watch operation on a resource or set of resources.
    /// Clients must treat these values as opaque and passed unmodified back to the server.
    /// They may only be valid for a particular resource or set of resources.
    /// Populated by the system. Read-only. Value must be treated as opaque by clients
    #[serde(rename = "resourceVersion")]
    pub resource_version: String,
    /// SelfLink is a URL representing this object. Populated by the system. Read-only.
    #[serde(rename = "selfLink")]
    pub self_link: String,
    /// UID is the unique in time and space value for this object. It is typically generated by
    /// the server on successful creation of a resource and is not allowed to change on PUT
    /// operations.
    /// Populated by the system. Read-only. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#uids
    pub uid: String,
}

/// EventSource contains information for an event.
#[derive(Serialize, Deserialize, Debug)]
pub struct EventSource {
    /// Component from which the event is generated.
    pub component: String,
    /// Host name on which the event is generated.
    pub host: Option<String>,
}

/// ObjectReference contains enough information to let you inspect or modify the referred object.
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectReference {
    /// API version of the referent.
    #[serde(rename = "apiVersion")]
    pub api_version: String,
    /// Specific resourceVersion to which this reference is made, if any.
    #[serde(rename = "resourceVersion")]
    pub resource_version: String,
    /// UID of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#uids
    pub uid: String,
    /// If referring to a piece of an object instead of an entire object,
    /// this string should contain a valid JSON/Go field access statement,
    /// such as desiredState.manifest.containers[2]. For example, if the object reference
    /// is to a container within a pod, this would take on a value like: "spec.containers{name}"
    /// (where "name" refers to the name of the container that triggered the event) or if no
    /// container name is specified "spec.containers[2]" (container with index 2 in this pod).
    /// This syntax is chosen only to have some well-defined way of referencing a part of an
    /// object.
    #[serde(rename = "fieldPath")]
    pub field_path: Option<String>,
    /// Kind of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/devel/api-conventions.md#types-kinds
    pub kind: String,
    /// Name of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/identifiers.md#names
    pub name: String,
    /// Namespace of the referent. More info:
    /// http://releases.k8s.io/release-1.3/docs/user-guide/namespaces.md
    pub namespace: String,
}

const DEFAULT_HOST: &'static str = "http://localhost:8001";

pub type Result<T> = std::result::Result<T, Error>;

/// An enumeratation of potential errors
#[derive(Debug)]
pub enum Error {
    Transport(HttpError),
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Transport(error)
    }
}

/// A cluster contains an address
/// for interacting with a kubernetes Cluster
/// of nodes
pub struct Cluster {
    host: Url,
}

/// Events provides a means for generating
/// a receiver for events
pub trait Events {
    fn events(&mut self) -> Result<Receiver<Event>>;

    fn generator<Bytes>(&self, bytes: Bytes) -> Result<Receiver<Event>>
    where
        Bytes: 'static + Iterator<Item = io::Result<u8>>,
        Bytes: Send,
    {
        let (tx, rx) = channel();
        let stream = serde_json::Deserializer::from_iter(bytes).into_iter::<Event>();
        thread::spawn(
            move || for e in stream {
                match e {
                    Ok(event) => {
                        if let Err(e) = tx.send(event) {
                            debug!("{:#?}", e);
                            break;
                        }
                    }
                    Err(e) => {
                        debug!("{:#?}", e);
                        break;
                    }
                }
            },
        );
        Ok(rx)
    }
}

impl Cluster {
    pub fn new() -> Cluster {
        let kubernetes_api_host: &str = &env::var("KUBERNETES_API_HOST").expect("KUBERNETES_API_HOST not set.");
        let active_host = if kubernetes_api_host.len() > 0 { kubernetes_api_host } else { DEFAULT_HOST };
        Cluster { host: Url::parse(active_host).unwrap() }
    }
}

impl Events for Cluster {
    fn events(&mut self) -> Result<Receiver<Event>> {
        let res = try!(
            Client::new()
                .get(self.host.join("/api/v1/events?watch=true").unwrap())
                .send()
        );
        self.generator(res.bytes())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::Receiver;
    #[test]
    fn events_generator() {
        impl Events for &'static str {
            fn events(&mut self) -> Result<Receiver<Event>> {
                self.generator(self.bytes().into_iter().map(|b| Ok(b)))
            }
        }
        let events = r#"{
            "object":{
                "apiVersion": "1",
                "count": 1,
                "firstTimestamp": "...",
                "lastTimestamp": "...",
                "kind":"Event",
                "message":"test",
                "involvedObject": {
                    "apiVersion": "1",
                    "resourceVersion": "2",
                    "uid":"2",
                    "kind": "POD",
                    "name": "test_name",
                    "namespace": "test_namespace"
                },
                "metadata": {
                    "creationTimestamp": "...",
                    "deletionTimestamp": "...",
                    "name": "test",
                    "namespace":"default",
                    "resourceVersion": "1",
                    "selfLink": "...",
                    "uid": "1"
                },
                "reason": "started",
                "source": {
                    "component": "test",
                    "host": "foo.com"
                },
                "type": "Normal"
            },
            "type":"ADDED"
        }"#
                .events();
        assert!(
            events
                .unwrap()
                .into_iter()
                .map(|e| e.object.involved_object.namespace)
                .nth(0) == Some("test_namespace".to_owned())
        )
    }
}
<|endoftext|>


<commit_before>extern crate rust_base58;
extern crate openssl;
#[cfg(test)] extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

// Takes bytes and a HashType, returns multihash of the bytes
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify
    /// that the bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Hash code {} is not recognized", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // Errors because digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());
    }
}
<commit_msg>Add into_bytes method.<commit_after>extern crate rust_base58;
extern crate openssl;
#[cfg(test)] extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

/// Hashes the `data` with the function described by `hash_type` and returns the result
/// as a Multihash.
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify that the
    /// bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] }

    pub fn into_bytes(self) -> Vec<u8> { self.bytes }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        // mismatch between stated digest length and actual digest length
        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());

        let x = "QmR6XorNYAywK4q1dRiRN1gmvfLcx3ccBv68iGtAqon9tt";
        assert!(Multihash::from_base58_str(x).is_ok());
    }
}
<|endoftext|>