<commit_before>use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Deserialize)]
/// The state of the light with similar structure to `LightCommand`
pub struct LightState {
    /// Whether the light is on
    pub on: bool,
    /// Brightness of the light. This is a scale from the minimum capable brightness, 1, to the maximum, 254.
    pub bri: u8,
    /// Hue of the light. Both 0 and 65535 are red, 25500 is green and 46920 is blue.
    pub hue: Option<u16>,
    /// Staturation of the light. 254 is the most saturated (colored) and 0 is the least (white).
    pub sat: Option<u8>,
    /// The x and y coordinates of a colour in [CIE space](http://www.developers.meethue.com/documentation/core-concepts#color_gets_more_complicated)
    pub xy: Option<(f32, f32)>,
    /// The [mired](http://en.wikipedia.org/wiki/Mired) colour temperature of the light.
    pub ct: Option<u16>,
    /// The [alert effect](http://www.developers.meethue.com/documentation/core-concepts#some_extra_fun_stuff)
    pub alert: String,
    /// The dynamic effect of the light. It can be either "none" or "colorloop"
    ///
    /// If "colorloop", the light will cycle hues
    pub effect: Option<String>,
    /// The current colour mode either: "hs" for hue and saturation, "xy" for x and y coordinates in colour space, or "ct" for colour temperature
    pub colormode: Option<String>,
    /// Whether the light can be reached by the bridge
    pub reachable: bool,
}

#[derive(Debug, Clone, Deserialize)]
/// Details about a specific light
pub struct Light {
    /// The unique name given to the light
    pub name: String,
    /// The hardware model of the light
    pub modelid: String,
    /// The version of the software running on the light
    pub swversion: String,
    /// Unique ID of the device
    pub uniqueid: String,
    /// The state of the light (See `LightState` for more)
    pub state: LightState
}

#[derive(Debug, Default, Clone, Serialize)]
/// Struct for building a command that will be sent to the Hue bridge telling it what to do with a light
///
/// View [the lights-api documention](http://www.developers.meethue.com/documentation/lights-api) for more information
pub struct LightCommand {
    /// Whether to turn the light off or on
    pub on: Option<bool>,
    /// Brightness of the colour of the light
    pub bri: Option<u8>,
    /// The hue of the colour of the light
    pub hue: Option<u16>,
    /// The saturation of the colour of the light
    pub sat: Option<u8>,
    /// The x and y coordinates of a colour in [CIE space](http://www.developers.meethue.com/documentation/core-concepts#color_gets_more_complicated)
    pub xy: Option<(f32, f32)>,
    /// The Mired Color temperature of the light. 2012 connected lights are capable of 153 (6500K) to 500 (2000K).
    pub ct: Option<u16>,
    /// The [alert effect](http://www.developers.meethue.com/documentation/core-concepts#some_extra_fun_stuff)
    pub alert: Option<String>,
    /// The dynamic effect of the light. It can be either "none" or "colorloop"
    ///
    /// If "colorloop", the light will cycle hues
    pub effect: Option<String>,
    /// Has to be a value between -254 and 254. Increments or decrements the value of the brightness.
    pub bri_inc: Option<i16>,
    /// Has to be a value between -254 and 254. Increments or decrements the value of the saturation.
    pub sat_inc: Option<i16>,
    /// Has to be a value between -65534 and 65534. Increments or decrements the value of the hue.
    pub hue_inc: Option<i16>,
    /// Has to be a value between -65534 and 65534. Increments or decrements the value of the colour temperature.
    pub ct_inc: Option<i16>,
    /// Increments or decrements the value of the xy.
    pub xy_inc: Option<(i16, i16)>,
}

#[derive(Debug, Clone, Deserialize)]
/// Responses from the `discover` function
pub struct Discovery{
    /// The ID of the bridge
    pub id: String,
    /// The local IP address of the bridge
    pub internalipaddress: String
}

impl Discovery {
    /// The ip of this discovered bridge
    pub fn ip(&self) -> &str{
        &self.internalipaddress
    }
    /// The id of this discovered bridge
    pub fn id(&self) -> &str{
        &self.id
    }
    /// Consumes self and returns the IP
    pub fn into_ip(self) -> String{
        let Discovery{internalipaddress, ..} = self;
        internalipaddress
    }
}

impl LightCommand {
    /// Returns a `LightCommand` that turns a light on
    pub fn on(self) -> Self {
        LightCommand { on: Some(true), ..self }
    }
    /// Returns a `LightCommand` that turns a light on
    pub fn off(self) -> Self {
        LightCommand { on: Some(false), ..self }
    }
    /// Sets the brightness to set the light to
    pub fn with_bri(self, b: u8) -> Self {
        LightCommand { bri: Some(b), ..self }
    }
    /// Sets the hue to set the light to
    pub fn with_hue(self, h: u16) -> Self {
        LightCommand { hue: Some(h), ..self }
    }
    /// Sets the saturation to set the light to
    pub fn with_sat(self, s: u8) -> Self {
        LightCommand { sat: Some(s), ..self }
    }
    /// Sets the temperature to set the light to
    pub fn with_ct(self, c: u16) -> Self {
        LightCommand { ct: Some(c), ..self }
    }
}

#[derive(Debug, Deserialize)]
/// A response that either is an error or a success
pub struct HueResponse<T: Serialize + Deserialize>{
    /// The result from the bridge if it didn't fail
    pub success: Option<T>,
    /// The error that was returned from the bridge
    pub error: Option<Error>
}

#[derive(Debug, Deserialize, Serialize)]
/// A user object returned from the API
pub struct User{
    /// The username of the user
    pub username: String
}

#[derive(Debug, Deserialize)]
/// An error object returned from the API
pub struct Error {
    /// The URI the error happened on
    pub address: String,
    /// A short description of the error
    pub description: String,
    /// Its errorcode
    #[serde(rename="type")]
    pub code: u16,
}
<commit_msg>Implement more methods on `LightCommand`<commit_after>use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Deserialize)]
/// The state of the light with similar structure to `LightCommand`
pub struct LightState {
    /// Whether the light is on
    pub on: bool,
    /// Brightness of the light. This is a scale from the minimum capable brightness, 1, to the maximum, 254.
    pub bri: u8,
    /// Hue of the light. Both 0 and 65535 are red, 25500 is green and 46920 is blue.
    pub hue: Option<u16>,
    /// Staturation of the light. 254 is the most saturated (colored) and 0 is the least (white).
    pub sat: Option<u8>,
    /// The x and y coordinates of a colour in [CIE space](http://www.developers.meethue.com/documentation/core-concepts#color_gets_more_complicated)
    pub xy: Option<(f32, f32)>,
    /// The [mired](http://en.wikipedia.org/wiki/Mired) colour temperature of the light.
    pub ct: Option<u16>,
    /// The [alert effect](http://www.developers.meethue.com/documentation/core-concepts#some_extra_fun_stuff)
    pub alert: String,
    /// The dynamic effect of the light. It can be either "none" or "colorloop"
    ///
    /// If "colorloop", the light will cycle hues
    pub effect: Option<String>,
    /// The current colour mode either: "hs" for hue and saturation, "xy" for x and y coordinates in colour space, or "ct" for colour temperature
    pub colormode: Option<String>,
    /// Whether the light can be reached by the bridge
    pub reachable: bool,
}

#[derive(Debug, Clone, Deserialize)]
/// Details about a specific light
pub struct Light {
    /// The unique name given to the light
    pub name: String,
    /// The hardware model of the light
    pub modelid: String,
    /// The version of the software running on the light
    pub swversion: String,
    /// Unique ID of the device
    pub uniqueid: String,
    /// The state of the light (See `LightState` for more)
    pub state: LightState
}

#[derive(Debug, Default, Clone, Serialize)]
/// Struct for building a command that will be sent to the Hue bridge telling it what to do with a light
///
/// View [the lights-api documention](http://www.developers.meethue.com/documentation/lights-api) for more information
pub struct LightCommand {
    /// Whether to turn the light off or on
    pub on: Option<bool>,
    /// Brightness of the colour of the light
    pub bri: Option<u8>,
    /// The hue of the colour of the light
    pub hue: Option<u16>,
    /// The saturation of the colour of the light
    pub sat: Option<u8>,
    /// The x and y coordinates of a colour in [CIE space](http://www.developers.meethue.com/documentation/core-concepts#color_gets_more_complicated)
    pub xy: Option<(f32, f32)>,
    /// The Mired Color temperature of the light. 2012 connected lights are capable of 153 (6500K) to 500 (2000K).
    pub ct: Option<u16>,
    /// The [alert effect](http://www.developers.meethue.com/documentation/core-concepts#some_extra_fun_stuff)
    pub alert: Option<String>,
    /// The dynamic effect of the light. It can be either "none" or "colorloop"
    ///
    /// If "colorloop", the light will cycle hues
    pub effect: Option<String>,
    /// Has to be a value between -254 and 254. Increments or decrements the value of the brightness.
    pub bri_inc: Option<i16>,
    /// Has to be a value between -254 and 254. Increments or decrements the value of the saturation.
    pub sat_inc: Option<i16>,
    /// Has to be a value between -65534 and 65534. Increments or decrements the value of the hue.
    pub hue_inc: Option<i16>,
    /// Has to be a value between -65534 and 65534. Increments or decrements the value of the colour temperature.
    pub ct_inc: Option<i16>,
    /// Increments or decrements the value of the xy.
    pub xy_inc: Option<(i16, i16)>,
}

impl LightCommand {
    /// Returns a `LightCommand` that turns a light on
    pub fn on(self) -> Self {
        LightCommand { on: Some(true), ..self }
    }
    /// Returns a `LightCommand` that turns a light on
    pub fn off(self) -> Self {
        LightCommand { on: Some(false), ..self }
    }
    /// Sets the brightness to set the light to
    pub fn with_bri(self, b: u8) -> Self {
        LightCommand { bri: Some(b), ..self }
    }
    /// Sets the hue to set the light to
    pub fn with_hue(self, h: u16) -> Self {
        LightCommand { hue: Some(h), ..self }
    }
    /// Sets the saturation to set the light to
    pub fn with_sat(self, s: u8) -> Self {
        LightCommand { sat: Some(s), ..self }
    }
    /// Sets the xy colour coordinates to set the light to
    pub fn with_xy(self, xy: (f32, f32)) -> Self {
        LightCommand { xy: Some(xy), ..self }
    }
    /// Sets the temperature to set the light to
    pub fn with_ct(self, c: u16) -> Self {
        LightCommand { ct: Some(c), ..self }
    }
    /// Sets the alert mode to set the light to
    pub fn with_alert(self, a: String) -> Self {
        LightCommand { alert: Some(a), ..self }
    }
    /// Sets the effect mode to set the light to
    pub fn with_effect(self, a: String) -> Self {
        LightCommand { effect: Some(a), ..self }
    }
    /// Sets the brightness increment value
    pub fn with_bri_inc(self, b: i16) -> Self {
        LightCommand { bri_inc: Some(b), ..self }
    }
    /// Sets the hue increment value
    pub fn with_hue_inc(self, h: i16) -> Self {
        LightCommand { hue_inc: Some(h), ..self }
    }
    /// Sets the saturation increment value
    pub fn with_sat_inc(self, s: i16) -> Self {
        LightCommand { sat_inc: Some(s), ..self }
    }
    /// Sets the saturation increment value
    pub fn with_ct_inc(self, ct: i16) -> Self {
        LightCommand { ct_inc: Some(ct), ..self }
    }
    /// Sets the x and y increment value
    pub fn with_xy_inc(self, xy: (i16, i16)) -> Self {
        LightCommand { xy_inc: Some(xy), ..self }
    }
}

#[derive(Debug, Clone, Deserialize)]
/// Responses from the `discover` function
pub struct Discovery{
    /// The ID of the bridge
    pub id: String,
    /// The local IP address of the bridge
    pub internalipaddress: String
}

impl Discovery {
    /// The ip of this discovered bridge
    pub fn ip(&self) -> &str{
        &self.internalipaddress
    }
    /// The id of this discovered bridge
    pub fn id(&self) -> &str{
        &self.id
    }
    /// Consumes self and returns the IP
    pub fn into_ip(self) -> String{
        let Discovery{internalipaddress, ..} = self;
        internalipaddress
    }
}

#[derive(Debug, Deserialize)]
/// A response that either is an error or a success
pub struct HueResponse<T: Serialize + Deserialize>{
    /// The result from the bridge if it didn't fail
    pub success: Option<T>,
    /// The error that was returned from the bridge
    pub error: Option<Error>
}

#[derive(Debug, Deserialize, Serialize)]
/// A user object returned from the API
pub struct User{
    /// The username of the user
    pub username: String
}

#[derive(Debug, Deserialize)]
/// An error object returned from the API
pub struct Error {
    /// The URI the error happened on
    pub address: String,
    /// A short description of the error
    pub description: String,
    /// Its errorcode
    #[serde(rename="type")]
    pub code: u16,
}
<|endoftext|>


<commit_before>#[allow(unused_imports)]
use log::Event::*;
use std::any::Any;
use std::env;
use std::error::Error;
use std::str::FromStr;
use std::fmt;
use std::sync::Arc;
use registry;
use num_cpus;

/// Contains the rayon thread pool configuration.
pub struct Configuration {
    /// The number of threads in the rayon thread pool.
    /// If zero will use the RAYON_RS_NUM_CPUS environment variable.
    /// If RAYON_RS_NUM_CPUS is invalid or zero will use the default.
    num_threads: usize,

    /// Custom closure, if any, to handle a panic that we cannot propagate
    /// anywhere else.
    panic_handler: Option<PanicHandler>,

    /// Closure to compute the name of a thread.
    get_thread_name: Option<Box<FnMut(usize) -> String>>,

    /// The stack size for the created worker threads
    stack_size: Option<usize>,

    /// Closure invoked on worker thread start.
    start_handler: Option<StartHandler>,

    /// Closure invoked on worker thread exit.
    exit_handler: Option<ExitHandler>,
}

/// The type for a panic handling closure. Note that this same closure
/// may be invoked multiple times in parallel.
pub type PanicHandler = Arc<Fn(Box<Any + Send>) + Send + Sync>;

/// The type for a closure that gets invoked when a thread starts. The
/// closure is passed the index of the thread on which it is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
pub type StartHandler = Arc<Fn(usize) + Send + Sync>;

/// The type for a closure that gets invoked when a thread exits. The
/// closure is passed the index of the thread on which is is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
pub type ExitHandler = Arc<Fn(usize) + Send + Sync>;

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration {
            num_threads: 0,
            get_thread_name: None,
            panic_handler: None,
            stack_size: None,
            start_handler: None,
            exit_handler: None,
        }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> usize {
        if self.num_threads > 0 {
            self.num_threads
        } else {
            match env::var("RAYON_RS_NUM_CPUS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => x,
                _ => num_cpus::get(),
            }
        }
    }

    /// Get the thread name for the thread with the given index.
    pub fn thread_name(&mut self, index: usize) -> Option<String> {
        self.get_thread_name.as_mut().map(|c| c(index))
    }

    /// Set a closure which takes a thread index and returns
    /// the thread's name.
    pub fn set_thread_name<F>(mut self, closure: F) -> Self
    where F: FnMut(usize) -> String + 'static {
        self.get_thread_name = Some(Box::new(closure));
        self
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// If `num_threads` is 0 or you do not call this function,
    /// rayon will use the RAYON_RS_NUM_CPUS environment variable.
    /// If RAYON_RS_NUM_CPUS is invalid or is zero, a suitable default will be used.
    /// Currently, the default is one thread per logical CPU.
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = num_threads;
        self
    }

    /// Returns (and takes ownership of) the current panic handler.
    /// After this call, no panic handler is registered in the
    /// configuration anymore.
    pub fn panic_handler(&self) -> Option<PanicHandler> {
        self.panic_handler.clone()
    }

    /// Normally, whenever Rayon catches a panic, it tries to
    /// propagate it to someplace sensible, to try and reflect the
    /// semantics of sequential execution. But in some cases,
    /// particularly with the `spawn_async()` APIs, there is no
    /// obvious place where we should propagate the panic to.
    /// In that case, this panic handler is invoked.
    ///
    /// If no panic handler is set, the default is to abort the
    /// process, under the principle that panics should not go
    /// unobserved.
    ///
    /// If the panic handler itself panics, this will abort the
    /// process. To prevent this, wrap the body of your panic handler
    /// in a call to `std::panic::catch_unwind()`.
    pub fn set_panic_handler(mut self, panic_handler: PanicHandler) -> Configuration {
        self.panic_handler = Some(panic_handler);
        self
    }

    /// Get the stack size of the worker threads
    pub fn stack_size(&self) -> Option<usize>{
        self.stack_size
    }

    /// Set the stack size of the worker threads
    pub fn set_stack_size(mut self, stack_size: usize) -> Self {
        self.stack_size = Some(stack_size);
        self
    }

    /// Returns a copy of the current thread start callback.
    pub fn start_handler(&self) -> Option<StartHandler> {
        self.start_handler.clone()
    }

    /// Set a callback to be invoked on thread start.
    ///
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then startup will continue normally.
    pub fn set_start_handler(mut self, start_handler: StartHandler) -> Configuration {
        self.start_handler = Some(start_handler);
        self
    }

    /// Returns a copy of the current thread exit callback.
    pub fn exit_handler(&self) -> Option<ExitHandler> {
        self.exit_handler.clone()
    }

    /// Set a callback to be invoked on thread exit.
    ///
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then the thread will exit normally.
    pub fn set_exit_handler(mut self, exit_handler: ExitHandler) -> Configuration {
        self.exit_handler = Some(exit_handler);
        self
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will return an error. An `Ok` result indicates that this
/// is the first initialization of the thread pool.
pub fn initialize(config: Configuration) -> Result<(), Box<Error>> {
    let registry = try!(registry::init_global_registry(config));
    registry.wait_until_primed();
    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

impl fmt::Debug for Configuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Configuration { ref num_threads, ref get_thread_name, ref panic_handler, ref stack_size,
                            ref start_handler, ref exit_handler } = *self;

        // Just print `Some("<closure>")` or `None` to the debug
        // output.
        let get_thread_name = get_thread_name.as_ref().map(|_| "<closure>");

        // Just print `Some("<closure>")` or `None` to the debug
        // output.
        let panic_handler = panic_handler.as_ref().map(|_| "<closure>");
        let start_handler = start_handler.as_ref().map(|_| "<closure>");
        let exit_handler = exit_handler.as_ref().map(|_| "<closure>");

        f.debug_struct("Configuration")
         .field("num_threads", num_threads)
         .field("get_thread_name", &get_thread_name)
         .field("panic_handler", &panic_handler)
         .field("stack_size", &stack_size)
         .field("start_handler", &start_handler)
         .field("exit_handler", &exit_handler)
         .finish()
    }
}
<commit_msg>fix the documentation for Configuration::panic_handler<commit_after>#[allow(unused_imports)]
use log::Event::*;
use std::any::Any;
use std::env;
use std::error::Error;
use std::str::FromStr;
use std::fmt;
use std::sync::Arc;
use registry;
use num_cpus;

/// Contains the rayon thread pool configuration.
pub struct Configuration {
    /// The number of threads in the rayon thread pool.
    /// If zero will use the RAYON_RS_NUM_CPUS environment variable.
    /// If RAYON_RS_NUM_CPUS is invalid or zero will use the default.
    num_threads: usize,

    /// Custom closure, if any, to handle a panic that we cannot propagate
    /// anywhere else.
    panic_handler: Option<PanicHandler>,

    /// Closure to compute the name of a thread.
    get_thread_name: Option<Box<FnMut(usize) -> String>>,

    /// The stack size for the created worker threads
    stack_size: Option<usize>,

    /// Closure invoked on worker thread start.
    start_handler: Option<StartHandler>,

    /// Closure invoked on worker thread exit.
    exit_handler: Option<ExitHandler>,
}

/// The type for a panic handling closure. Note that this same closure
/// may be invoked multiple times in parallel.
pub type PanicHandler = Arc<Fn(Box<Any + Send>) + Send + Sync>;

/// The type for a closure that gets invoked when a thread starts. The
/// closure is passed the index of the thread on which it is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
pub type StartHandler = Arc<Fn(usize) + Send + Sync>;

/// The type for a closure that gets invoked when a thread exits. The
/// closure is passed the index of the thread on which is is invoked.
/// Note that this same closure may be invoked multiple times in parallel.
pub type ExitHandler = Arc<Fn(usize) + Send + Sync>;

impl Configuration {
    /// Creates and return a valid rayon thread pool configuration, but does not initialize it.
    pub fn new() -> Configuration {
        Configuration {
            num_threads: 0,
            get_thread_name: None,
            panic_handler: None,
            stack_size: None,
            start_handler: None,
            exit_handler: None,
        }
    }

    /// Get the number of threads that will be used for the thread
    /// pool. See `set_num_threads` for more information.
    pub fn num_threads(&self) -> usize {
        if self.num_threads > 0 {
            self.num_threads
        } else {
            match env::var("RAYON_RS_NUM_CPUS").ok().and_then(|s| usize::from_str(&s).ok()) {
                Some(x) if x > 0 => x,
                _ => num_cpus::get(),
            }
        }
    }

    /// Get the thread name for the thread with the given index.
    pub fn thread_name(&mut self, index: usize) -> Option<String> {
        self.get_thread_name.as_mut().map(|c| c(index))
    }

    /// Set a closure which takes a thread index and returns
    /// the thread's name.
    pub fn set_thread_name<F>(mut self, closure: F) -> Self
    where F: FnMut(usize) -> String + 'static {
        self.get_thread_name = Some(Box::new(closure));
        self
    }

    /// Set the number of threads to be used in the rayon threadpool.
    /// If `num_threads` is 0 or you do not call this function,
    /// rayon will use the RAYON_RS_NUM_CPUS environment variable.
    /// If RAYON_RS_NUM_CPUS is invalid or is zero, a suitable default will be used.
    /// Currently, the default is one thread per logical CPU.
    pub fn set_num_threads(mut self, num_threads: usize) -> Configuration {
        self.num_threads = num_threads;
        self
    }

    /// Returns a copy of the current panic handler.
    pub fn panic_handler(&self) -> Option<PanicHandler> {
        self.panic_handler.clone()
    }

    /// Normally, whenever Rayon catches a panic, it tries to
    /// propagate it to someplace sensible, to try and reflect the
    /// semantics of sequential execution. But in some cases,
    /// particularly with the `spawn_async()` APIs, there is no
    /// obvious place where we should propagate the panic to.
    /// In that case, this panic handler is invoked.
    ///
    /// If no panic handler is set, the default is to abort the
    /// process, under the principle that panics should not go
    /// unobserved.
    ///
    /// If the panic handler itself panics, this will abort the
    /// process. To prevent this, wrap the body of your panic handler
    /// in a call to `std::panic::catch_unwind()`.
    pub fn set_panic_handler(mut self, panic_handler: PanicHandler) -> Configuration {
        self.panic_handler = Some(panic_handler);
        self
    }

    /// Get the stack size of the worker threads
    pub fn stack_size(&self) -> Option<usize>{
        self.stack_size
    }

    /// Set the stack size of the worker threads
    pub fn set_stack_size(mut self, stack_size: usize) -> Self {
        self.stack_size = Some(stack_size);
        self
    }

    /// Returns a copy of the current thread start callback.
    pub fn start_handler(&self) -> Option<StartHandler> {
        self.start_handler.clone()
    }

    /// Set a callback to be invoked on thread start.
    ///
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then startup will continue normally.
    pub fn set_start_handler(mut self, start_handler: StartHandler) -> Configuration {
        self.start_handler = Some(start_handler);
        self
    }

    /// Returns a copy of the current thread exit callback.
    pub fn exit_handler(&self) -> Option<ExitHandler> {
        self.exit_handler.clone()
    }

    /// Set a callback to be invoked on thread exit.
    ///
    /// If this closure panics, the panic will be passed to the panic handler.
    /// If that handler returns, then the thread will exit normally.
    pub fn set_exit_handler(mut self, exit_handler: ExitHandler) -> Configuration {
        self.exit_handler = Some(exit_handler);
        self
    }
}

/// Initializes the global thread pool. This initialization is
/// **optional**.  If you do not call this function, the thread pool
/// will be automatically initialized with the default
/// configuration. In fact, calling `initialize` is not recommended,
/// except for in two scenarios:
///
/// - You wish to change the default configuration.
/// - You are running a benchmark, in which case initializing may
///   yield slightly more consistent results, since the worker threads
///   will already be ready to go even in the first iteration.  But
///   this cost is minimal.
///
/// Initialization of the global thread pool happens exactly
/// once. Once started, the configuration cannot be
/// changed. Therefore, if you call `initialize` a second time, it
/// will return an error. An `Ok` result indicates that this
/// is the first initialization of the thread pool.
pub fn initialize(config: Configuration) -> Result<(), Box<Error>> {
    let registry = try!(registry::init_global_registry(config));
    registry.wait_until_primed();
    Ok(())
}

/// This is a debugging API not really intended for end users. It will
/// dump some performance statistics out using `println`.
pub fn dump_stats() {
    dump_stats!();
}

impl fmt::Debug for Configuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Configuration { ref num_threads, ref get_thread_name, ref panic_handler, ref stack_size,
                            ref start_handler, ref exit_handler } = *self;

        // Just print `Some("<closure>")` or `None` to the debug
        // output.
        let get_thread_name = get_thread_name.as_ref().map(|_| "<closure>");

        // Just print `Some("<closure>")` or `None` to the debug
        // output.
        let panic_handler = panic_handler.as_ref().map(|_| "<closure>");
        let start_handler = start_handler.as_ref().map(|_| "<closure>");
        let exit_handler = exit_handler.as_ref().map(|_| "<closure>");

        f.debug_struct("Configuration")
         .field("num_threads", num_threads)
         .field("get_thread_name", &get_thread_name)
         .field("panic_handler", &panic_handler)
         .field("stack_size", &stack_size)
         .field("start_handler", &start_handler)
         .field("exit_handler", &exit_handler)
         .finish()
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

/// Implementation of a `Stack` which maintains an log of `StackOp`s in order to rewind the stack
/// to a previous state.
use std::fmt::Debug;

#[derive(Debug)]
pub struct Stack<T: Clone + Debug> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>,
    current_snapshot: usize
}

impl<T: Clone + Debug> Stack<T> {
    /// Creates a new `Stack`.
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![],
            current_snapshot: 0
        }
    }

    /// Returns `true` if the stack is currently empty.
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    /// Returns the top-most `&T` in the `Stack`.
    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    /// Pushes a `T` onto the `Stack`.
    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    /// Pops the top-most `T` from the `Stack`.
    pub fn pop(&mut self) -> Option<T> {
        let popped = self.cache.pop();
        if let Some(val) = popped.clone() {
            self.ops.push(StackOp::Pop(val));
        }
        popped
    }

    /// Takes a snapshot of the current `Stack`.
    pub fn snapshot(&mut self) {
        let ops_index = self.ops.len();
        if ops_index > self.current_snapshot {
            self.snapshots.push(ops_index);
            self.current_snapshot = ops_index;
        }
    }

    /// Rewinds the `Stack` to the most recent `snapshot()`. If no `snapshot()` has been taken, this
    /// function will do nothing.
    pub fn restore(&mut self) {
        if let Some(ops_index) = self.snapshots.pop() {
            self.rewind_to(ops_index);
            self.ops.truncate(ops_index);
            self.current_snapshot = self.ops.len();
        }
    }

    // Rewind the stack to a particular index
    fn rewind_to(&mut self, index: usize) {
        let ops_to_rewind = &self.ops[index..];
        for op in ops_to_rewind.iter().rev() {
            match op {
                &StackOp::Push(_) => {
                    self.cache.pop();
                }
                &StackOp::Pop(ref elem) => {
                    self.cache.push(elem.clone());
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop(T)
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());

        // Test backtracking
        // [0, 2]
        stack.restore();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.restore();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<commit_msg>minor tweaks<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

/// Implementation of a `Stack` which maintains an log of `StackOp`s in order to rewind the stack
/// to a previous state.
#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>,
    current_snapshot: usize
}

impl<T: Clone> Stack<T> {
    /// Creates a new `Stack`.
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![],
            current_snapshot: 0
        }
    }

    /// Returns `true` if the stack is currently empty.
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    /// Returns the top-most `&T` in the `Stack`.
    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    /// Pushes a `T` onto the `Stack`.
    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    /// Pops the top-most `T` from the `Stack`.
    pub fn pop(&mut self) -> Option<T> {
        let popped = self.cache.pop();
        if let Some(ref val) = popped {
            self.ops.push(StackOp::Pop(val.clone()));
        }
        popped
    }

    /// Takes a snapshot of the current `Stack`.
    pub fn snapshot(&mut self) {
        let ops_index = self.ops.len();
        if ops_index > self.current_snapshot {
            self.snapshots.push(ops_index);
            self.current_snapshot = ops_index;
        }
    }

    /// Rewinds the `Stack` to the most recent `snapshot()`. If no `snapshot()` has been taken, this
    /// function will do nothing.
    pub fn restore(&mut self) {
        if let Some(ops_index) = self.snapshots.pop() {
            self.rewind_to(ops_index);
            self.ops.truncate(ops_index);
            self.current_snapshot = self.ops.len();
        }
    }

    // Rewind the stack to a particular index
    fn rewind_to(&mut self, index: usize) {
        let ops_to_rewind = &self.ops[index..];
        for op in ops_to_rewind.iter().rev() {
            match op {
                &StackOp::Push(_) => {
                    self.cache.pop();
                }
                &StackOp::Pop(ref elem) => {
                    self.cache.push(elem.clone());
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop(T)
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());

        // Test backtracking
        // [0, 2]
        stack.restore();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.restore();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<|endoftext|>


<commit_before>// Purge all references to a crate from the database.
//
// Please be super sure you want to do this before running this.
//
// Usage:
//      cargo run --bin delete-crate crate-name

#![deny(warnings)]

extern crate cargo_registry;
extern crate postgres;
extern crate time;

use std::env;
use std::io;
use std::io::prelude::*;

use cargo_registry::Crate;

#[allow(dead_code)]
fn main() {
    let conn = cargo_registry::db::connect_now();
    {
        let tx = conn.transaction().unwrap();
        delete(&tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

fn delete(tx: &postgres::transaction::Transaction) {
    let name = match env::args().nth(1) {
        None => { println!("needs a crate-name argument"); return }
        Some(s) => s,
    };

    let krate = Crate::find_by_name(tx, &name).unwrap();
    print!("Are you sure you want to delete {} ({}) [y/N]: ", name, krate.id);
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with("y") { return }

    let versions = krate.versions(tx).unwrap();

    for v in versions.iter() {
        println!("deleting version {} ({})", v.num, v.id);
        let n = tx.execute("DELETE FROM version_downloads WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} download records deleted", n);
        let n = tx.execute("DELETE FROM version_authors WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} author records deleted", n);
        let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} dependencies deleted", n);
        tx.execute("DELETE FROM versions WHERE id = $1",
                   &[&v.id]).unwrap();
    }

    println!("deleting follows");
    let n = tx.execute("DELETE FROM follows WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate download records");
    let n = tx.execute("DELETE FROM crate_downloads WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate owners");
    let n = tx.execute("DELETE FROM crate_owners WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate keyword connections");
    let n = tx.execute("DELETE FROM crates_keywords WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate category connections");
    let n = tx.execute("DELETE FROM crates_categories WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate badges");
    let n = tx.execute("DELETE FROM badges WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting the crate");
    let n = tx.execute("DELETE FROM crates WHERE id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    print!("commit? [y/N]: ");
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with("y") { panic!("aborting transaction"); }
}
<commit_msg>Temporarily disable trigger to allow deletion of crates with reserved names<commit_after>// Purge all references to a crate from the database.
//
// Please be super sure you want to do this before running this.
//
// Usage:
//      cargo run --bin delete-crate crate-name

#![deny(warnings)]

extern crate cargo_registry;
extern crate postgres;
extern crate time;

use std::env;
use std::io;
use std::io::prelude::*;

use cargo_registry::Crate;

#[allow(dead_code)]
fn main() {
    let conn = cargo_registry::db::connect_now();
    {
        let tx = conn.transaction().unwrap();
        delete(&tx);
        tx.set_commit();
        tx.finish().unwrap();
    }
}

fn delete(tx: &postgres::transaction::Transaction) {
    let name = match env::args().nth(1) {
        None => { println!("needs a crate-name argument"); return }
        Some(s) => s,
    };

    let krate = Crate::find_by_name(tx, &name).unwrap();
    print!("Are you sure you want to delete {} ({}) [y/N]: ", name, krate.id);
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with("y") { return }

    let versions = krate.versions(tx).unwrap();

    for v in versions.iter() {
        println!("deleting version {} ({})", v.num, v.id);
        let n = tx.execute("DELETE FROM version_downloads WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} download records deleted", n);
        let n = tx.execute("DELETE FROM version_authors WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} author records deleted", n);
        let n = tx.execute("DELETE FROM dependencies WHERE version_id = $1",
                           &[&v.id]).unwrap();
        println!("  {} dependencies deleted", n);
        tx.execute("DELETE FROM versions WHERE id = $1",
                   &[&v.id]).unwrap();
    }

    println!("deleting follows");
    let n = tx.execute("DELETE FROM follows WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate download records");
    let n = tx.execute("DELETE FROM crate_downloads WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate owners");
    let n = tx.execute("DELETE FROM crate_owners WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("disabling reserved crate name trigger");
    let _ = tx.execute("ALTER TABLE crates DISABLE TRIGGER trigger_ensure_crate_name_not_reserved;",
                       &[]).unwrap();

    println!("deleting crate keyword connections");
    let n = tx.execute("DELETE FROM crates_keywords WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting crate category connections");
    let n = tx.execute("DELETE FROM crates_categories WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("enabling reserved crate name trigger");
    let _ = tx.execute("ALTER TABLE crates ENABLE TRIGGER trigger_ensure_crate_name_not_reserved;",
                       &[]).unwrap();

    println!("deleting crate badges");
    let n = tx.execute("DELETE FROM badges WHERE crate_id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    println!("deleting the crate");
    let n = tx.execute("DELETE FROM crates WHERE id = $1",
                       &[&krate.id]).unwrap();
    println!("  {} deleted", n);

    print!("commit? [y/N]: ");
    io::stdout().flush().unwrap();
    let mut line = String::new();
    io::stdin().read_line(&mut line).unwrap();
    if !line.starts_with("y") { panic!("aborting transaction"); }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::common::utils::create_dir_if_not_exist;
use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    CliCommand,
};
use aptos_config::config::Token;
use aptos_genesis::config::Layout;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use framework::ReleaseBundle;
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use std::{fmt::Debug, io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_FILE: &str = "layout.yaml";
pub const OPERATOR_FILE: &str = "operator.yaml";
pub const OWNER_FILE: &str = "owner.yaml";
pub const FRAMEWORK_NAME: &str = "framework.mrb";
pub const BALANCES_FILE: &str = "balances.yaml";
pub const EMPLOYEE_VESTING_ACCOUNTS_FILE: &str = "employee_vesting_accounts.yaml";

/// Setup a shared Git repository for Genesis
///
/// This will setup a folder or an online Github repository to be used
/// for Genesis.  If it's the local, it will create the folders but not
/// set up a Git repository.
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    pub(crate) git_options: GitOptions,

    /// Path to the `Layout` file which defines where all the files are
    #[clap(long, parse(from_os_str))]
    pub(crate) layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(Path::new(LAYOUT_FILE), &layout)?;

        Ok(())
    }
}

#[derive(Clone, Debug, Default)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.first().unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Default, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    pub(crate) github_repository: Option<GithubRepo>,

    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    pub(crate) github_branch: String,

    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    pub(crate) github_token_file: Option<PathBuf>,

    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    pub(crate) local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-dir or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned + Debug>(&self, path: &Path) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(path);

                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }

                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&path.display().to_string())?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &Path, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);

                // Create repository path and any sub-directories
                if let Some(dir) = path.parent() {
                    self.create_dir(dir)?;
                } else {
                    return Err(CliError::UnexpectedError(format!(
                        "Path should always have a parent {}",
                        path.display()
                    )));
                }
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&name.display().to_string(), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, dir: &Path) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(dir);
                create_dir_if_not_exist(path.as_path())?;
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve framework release bundle.
    pub fn get_framework(&self) -> CliTypedResult<ReleaseBundle> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(FRAMEWORK_NAME);
                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }
                Ok(ReleaseBundle::read(path)?)
            }
            Client::Github(client) => {
                let bytes = base64::decode(client.get_file(FRAMEWORK_NAME)?)?;
                Ok(bcs::from_bytes::<ReleaseBundle>(&bytes)?)
            }
        }
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<commit_msg>[genesis] Add eprintln for file that is currently being read<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::common::utils::create_dir_if_not_exist;
use crate::{
    common::{
        types::{CliError, CliTypedResult},
        utils::write_to_file,
    },
    CliCommand,
};
use aptos_config::config::Token;
use aptos_genesis::config::Layout;
use aptos_github_client::Client as GithubClient;
use async_trait::async_trait;
use clap::Parser;
use framework::ReleaseBundle;
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use std::{fmt::Debug, io::Read, path::PathBuf, str::FromStr};

pub const LAYOUT_FILE: &str = "layout.yaml";
pub const OPERATOR_FILE: &str = "operator.yaml";
pub const OWNER_FILE: &str = "owner.yaml";
pub const FRAMEWORK_NAME: &str = "framework.mrb";
pub const BALANCES_FILE: &str = "balances.yaml";
pub const EMPLOYEE_VESTING_ACCOUNTS_FILE: &str = "employee_vesting_accounts.yaml";

/// Setup a shared Git repository for Genesis
///
/// This will setup a folder or an online Github repository to be used
/// for Genesis.  If it's the local, it will create the folders but not
/// set up a Git repository.
#[derive(Parser)]
pub struct SetupGit {
    #[clap(flatten)]
    pub(crate) git_options: GitOptions,

    /// Path to the `Layout` file which defines where all the files are
    #[clap(long, parse(from_os_str))]
    pub(crate) layout_file: PathBuf,
}

#[async_trait]
impl CliCommand<()> for SetupGit {
    fn command_name(&self) -> &'static str {
        "SetupGit"
    }

    async fn execute(self) -> CliTypedResult<()> {
        let layout = Layout::from_disk(&self.layout_file)?;

        // Upload layout file to ensure we can read later
        let client = self.git_options.get_client()?;
        client.put(Path::new(LAYOUT_FILE), &layout)?;

        Ok(())
    }
}

#[derive(Clone, Debug, Default)]
pub struct GithubRepo {
    owner: String,
    repository: String,
}

impl FromStr for GithubRepo {
    type Err = CliError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<_> = s.split('/').collect();
        if parts.len() != 2 {
            Err(CliError::CommandArgumentError("Invalid repository must be of the form 'owner/repository` e.g. 'aptos-labs/aptos-core'".to_string()))
        } else {
            Ok(GithubRepo {
                owner: parts.first().unwrap().to_string(),
                repository: parts.get(1).unwrap().to_string(),
            })
        }
    }
}

#[derive(Clone, Default, Parser)]
pub struct GitOptions {
    /// Github repository e.g. 'aptos-labs/aptos-core'
    #[clap(long)]
    pub(crate) github_repository: Option<GithubRepo>,

    /// Github repository branch e.g. main
    #[clap(long, default_value = "main")]
    pub(crate) github_branch: String,

    /// Path to Github API token.  Token must have repo:* permissions
    #[clap(long, parse(from_os_str))]
    pub(crate) github_token_file: Option<PathBuf>,

    /// Path to local git repository
    #[clap(long, parse(from_os_str))]
    pub(crate) local_repository_dir: Option<PathBuf>,
}

impl GitOptions {
    pub fn get_client(self) -> CliTypedResult<Client> {
        if self.github_repository.is_none()
            && self.github_token_file.is_none()
            && self.local_repository_dir.is_some()
        {
            Ok(Client::local(self.local_repository_dir.unwrap()))
        } else if self.github_repository.is_some()
            && self.github_token_file.is_some()
            && self.local_repository_dir.is_none()
        {
            Client::github(
                self.github_repository.unwrap(),
                self.github_branch,
                self.github_token_file.unwrap(),
            )
        } else {
            Err(CliError::CommandArgumentError("Must provide either only --local-repository-dir or both --github-repository and --github-token-path".to_string()))
        }
    }
}

/// A client for abstracting away local vs Github storage
///
/// Note: Writes do not commit locally
pub enum Client {
    Local(PathBuf),
    Github(GithubClient),
}

impl Client {
    pub fn local(path: PathBuf) -> Client {
        Client::Local(path)
    }

    pub fn github(
        repository: GithubRepo,
        branch: String,
        token_path: PathBuf,
    ) -> CliTypedResult<Client> {
        let token = Token::FromDisk(token_path).read_token()?;
        Ok(Client::Github(GithubClient::new(
            repository.owner,
            repository.repository,
            branch,
            token,
        )))
    }

    /// Retrieves an object as a YAML encoded file from the appropriate storage
    pub fn get<T: DeserializeOwned + Debug>(&self, path: &Path) -> CliTypedResult<T> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(path);

                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }

                eprintln!("Reading {}", path.display());
                let mut file = std::fs::File::open(path.as_path())
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;

                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .map_err(|e| CliError::IO(path.display().to_string(), e))?;
                from_yaml(&contents)
            }
            Client::Github(client) => {
                from_base64_encoded_yaml(&client.get_file(&path.display().to_string())?)
            }
        }
    }

    /// Puts an object as a YAML encoded file to the appropriate storage
    pub fn put<T: Serialize + ?Sized>(&self, name: &Path, input: &T) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(name);

                // Create repository path and any sub-directories
                if let Some(dir) = path.parent() {
                    self.create_dir(dir)?;
                } else {
                    return Err(CliError::UnexpectedError(format!(
                        "Path should always have a parent {}",
                        path.display()
                    )));
                }
                write_to_file(
                    path.as_path(),
                    &path.display().to_string(),
                    to_yaml(input)?.as_bytes(),
                )?;
            }
            Client::Github(client) => {
                client.put(&name.display().to_string(), &to_base64_encoded_yaml(input)?)?;
            }
        }

        Ok(())
    }

    pub fn create_dir(&self, dir: &Path) -> CliTypedResult<()> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(dir);
                create_dir_if_not_exist(path.as_path())?;
            }
            Client::Github(_) => {
                // There's no such thing as an empty directory in Git, so do nothing
            }
        }

        Ok(())
    }

    /// Retrieve framework release bundle.
    pub fn get_framework(&self) -> CliTypedResult<ReleaseBundle> {
        match self {
            Client::Local(local_repository_path) => {
                let path = local_repository_path.join(FRAMEWORK_NAME);
                if !path.exists() {
                    return Err(CliError::UnableToReadFile(
                        path.display().to_string(),
                        "File not found".to_string(),
                    ));
                }
                Ok(ReleaseBundle::read(path)?)
            }
            Client::Github(client) => {
                let bytes = base64::decode(client.get_file(FRAMEWORK_NAME)?)?;
                Ok(bcs::from_bytes::<ReleaseBundle>(&bytes)?)
            }
        }
    }
}

pub fn to_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(serde_yaml::to_string(input)?)
}

pub fn from_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    Ok(serde_yaml::from_str(input)?)
}

pub fn to_base64_encoded_yaml<T: Serialize + ?Sized>(input: &T) -> CliTypedResult<String> {
    Ok(base64::encode(to_yaml(input)?))
}

pub fn from_base64_encoded_yaml<T: DeserializeOwned>(input: &str) -> CliTypedResult<T> {
    from_yaml(&String::from_utf8(base64::decode(input)?)?)
}
<|endoftext|>


<commit_before>use cssparser::{Parser, Token};

use drawing_ctx::DrawingCtx;
use error::*;
use length::{Length, LengthDir, LengthUnit, POINTS_PER_INCH};
use parsers::{Parse, ParseError};
use state::ComputedValues;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length {
        match self {
            FontSizeSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::new(size.length / 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::Larger => Length::new(size.length * 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::XXSmall => {
                Length::new(compute_points(-3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XSmall => {
                Length::new(compute_points(-2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Small => {
                Length::new(compute_points(-1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Medium => {
                Length::new(compute_points(0.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Large => {
                Length::new(compute_points(1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XLarge => {
                Length::new(compute_points(2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XXLarge => {
                Length::new(compute_points(3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::new(size.length * s.length, size.unit, LengthDir::Both)
            }
            FontSizeSpec::Value(s) => s.clone(),
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, draw_ctx: &DrawingCtx) -> f64 {
        self.value().normalize(values, draw_ctx)
    }
}

impl Parse for FontSizeSpec {
    type Data = ();
    type Err = AttributeError;

    fn parse(parser: &mut Parser, _: Self::Data) -> Result<FontSizeSpec, ::error::AttributeError> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Both)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::AttributeError::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100, // FIXME: we should use Weight(100),
    W200, // but we need a smarter macro for that
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Data = ();
    type Err = AttributeError;

    fn parse(
        parser: &mut Parser,
        _: Self::Data,
    ) -> Result<FontWeightSpec, ::error::AttributeError> {
        if let Ok(r) = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            }) {
            Ok(r)
        } else {
            Err(AttributeError::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

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

    #[test]
    fn invalid_font_size_yields_error() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal", ()),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold", ()),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100", ()),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14", ()).is_err());
    }
}
<commit_msg>font_props: improve comments<commit_after>use cssparser::{Parser, Token};

use drawing_ctx::DrawingCtx;
use error::*;
use length::{Length, LengthDir, LengthUnit, POINTS_PER_INCH};
use parsers::{Parse, ParseError};
use state::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length {
        match self {
            FontSizeSpec::Value(s) => s.clone(),
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::new(size.length / 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::Larger => Length::new(size.length * 1.2, size.unit, LengthDir::Both),
            FontSizeSpec::XXSmall => {
                Length::new(compute_points(-3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XSmall => {
                Length::new(compute_points(-2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Small => {
                Length::new(compute_points(-1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Medium => {
                Length::new(compute_points(0.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Large => {
                Length::new(compute_points(1.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XLarge => {
                Length::new(compute_points(2.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::XXLarge => {
                Length::new(compute_points(3.0), LengthUnit::Inch, LengthDir::Both)
            }
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::new(size.length * s.length, size.unit, LengthDir::Both)
            }
            FontSizeSpec::Value(s) => s.clone(),
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, draw_ctx: &DrawingCtx) -> f64 {
        self.value().normalize(values, draw_ctx)
    }
}

impl Parse for FontSizeSpec {
    type Data = ();
    type Err = AttributeError;

    fn parse(parser: &mut Parser, _: Self::Data) -> Result<FontSizeSpec, ::error::AttributeError> {
        let parser_state = parser.state();

        Length::parse(parser, LengthDir::Both)
            .and_then(|s| Ok(FontSizeSpec::Value(s)))
            .or_else(|e| {
                parser.reset(&parser_state);

                {
                    let token = parser.next().map_err(|_| {
                        ::error::AttributeError::Parse(::parsers::ParseError::new("expected token"))
                    })?;

                    if let Token::Ident(ref cow) = token {
                        match cow.as_ref() {
                            "smaller" => return Ok(FontSizeSpec::Smaller),
                            "larger" => return Ok(FontSizeSpec::Larger),
                            "xx-small" => return Ok(FontSizeSpec::XXSmall),
                            "x-small" => return Ok(FontSizeSpec::XSmall),
                            "small" => return Ok(FontSizeSpec::Small),
                            "medium" => return Ok(FontSizeSpec::Medium),
                            "large" => return Ok(FontSizeSpec::Large),
                            "x-large" => return Ok(FontSizeSpec::XLarge),
                            "xx-large" => return Ok(FontSizeSpec::XXLarge),
                            _ => (),
                        };
                    }
                }

                parser.reset(&parser_state);

                Err(e)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    type Data = ();
    type Err = AttributeError;

    fn parse(
        parser: &mut Parser,
        _: Self::Data,
    ) -> Result<FontWeightSpec, ::error::AttributeError> {
        if let Ok(r) = parser.try(|p| {
            p.expect_ident()
                .map_err(|_| ())
                .and_then(|cow| match cow.as_ref() {
                    "normal" => Ok(FontWeightSpec::Normal),
                    "bold" => Ok(FontWeightSpec::Bold),
                    "bolder" => Ok(FontWeightSpec::Bolder),
                    "lighter" => Ok(FontWeightSpec::Lighter),
                    _ => Err(()),
                })
        }) {
            return Ok(r);
        }

        if let Ok(r) = parser
            .expect_integer()
            .map_err(|_| ())
            .and_then(|i| match i {
                100 => Ok(FontWeightSpec::W100),
                200 => Ok(FontWeightSpec::W200),
                300 => Ok(FontWeightSpec::W300),
                400 => Ok(FontWeightSpec::W400),
                500 => Ok(FontWeightSpec::W500),
                600 => Ok(FontWeightSpec::W600),
                700 => Ok(FontWeightSpec::W700),
                800 => Ok(FontWeightSpec::W800),
                900 => Ok(FontWeightSpec::W900),
                _ => Err(()),
            }) {
            Ok(r)
        } else {
            Err(AttributeError::Parse(ParseError::new(
                "invalid font-weight specification",
            )))
        }
    }
}

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

    #[test]
    fn invalid_font_size_yields_error() {
        assert!(is_parse_error(&FontSizeSpec::parse_str("furlong", ())));
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal", ()),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold", ()),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100", ()),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314", ()).is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14", ()).is_err());
    }
}
<|endoftext|>


<commit_before>use std::intrinsics::TypeId;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::fmt::{Formatter, Show, Result};
use std::collections::hashmap::HashMap;
use std::any::{Any, AnyRefExt, AnyMutRefExt};
use std::mem;
use uuid::Uuid;

/// Callback interface for application data connected to the component system
/// world.
pub trait System {
    /// Callback for initially attaching the system to a world
    fn register(&mut self, world: &World<Self>);
    /// Callback for adding a new entity to world
    fn added(&mut self, e: &Entity<Self>);
    /// Callback for a component being added or removed in an entity. Note that
    /// this is not called when the data of an existing component is written
    /// to, only if the component is replaced or removed.
    fn changed<C>(&mut self, e: &Entity<Self>, component: Option<&C>);
    /// Callback for an entity being deleted
    fn deleted(&mut self, e: &Entity<Self>);
}

struct WorldData<T> {
    // XXX: This is much less efficient than it could be. A serious
    // implementation would use unboxed vecs for the components and would
    // provide lookup methods faster than a HashMap find to access the
    // components
    components: HashMap<TypeId, Vec<Option<Box<Any>>>>,

    next_idx: uint,
    reusable_idxs: Vec<uint>,
    uuids: Vec<Option<Uuid>>,

    master_system: T,
}

impl<T: System> WorldData<T> {
    fn new(master_system: T) -> WorldData<T> {
        WorldData {
            components: HashMap::new(),
            next_idx: 0,
            reusable_idxs: vec!(),
            uuids: vec!(),
            master_system: master_system,
        }
    }

    fn register_new_entity(&mut self, id: EntityId) {
        assert!(self.uuids.len() <= id.idx || self.uuids.get(id.idx).is_none(),
            "New entity clobbering existing one");
        self.uuids.grow_set(id.idx, &None, Some(id.uuid));
    }

    fn delete_entity(&mut self, e: &Entity<T>) {
        self.check_entity(e.id);
        self.uuids.as_mut_slice()[e.id.idx] = None;

        for (_, c) in self.components.mut_iter() {
            if c.len() > e.id.idx {
                c.as_mut_slice()[e.id.idx] = None;
            }
        }

        self.reusable_idxs.push(e.id.idx);

        self.master_system.deleted(e);
    }

    /// Return the next unused reusable entity id.
    fn get_idx(&mut self) -> uint {
        match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        }
    }

    fn check_entity(&self, id: EntityId) {
        assert!(self.uuids.get(id.idx).unwrap() == id.uuid, "Entity UUID mismatch");
    }

    fn set_component<C: 'static+Clone>(&mut self, e: &Entity<T>, comp: Option<C>) {
        self.check_entity(e.id);
        let type_id = TypeId::of::<C>();
        // We haven't seen this kind of component yet.
        if !self.components.contains_key(&type_id) {
            self.components.insert(type_id, vec!());
        }

        let bin = self.components.find_mut(&type_id).unwrap();

        // XXX: grow_set didn't work.
        while bin.len() <= e.id.idx { bin.push(None); }
        bin.as_mut_slice()[e.id.idx] = match comp {
            None => None,
            Some(c) => Some(box c as Box<Any>),
        };

        match bin.as_mut_slice()[e.id.idx] {
            None => self.master_system.changed::<C>(e, None),
            Some(ref c) => self.master_system.changed(e, Some(&c)),
        };
    }

    fn comp_ref<'a, C: 'static>(
        &self, id: EntityId) -> Option<&'a C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get(id.idx) {
                        &Some(ref c) => { unsafe { Some(mem::transmute(c.as_ref::<C>().unwrap())) } }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }

    fn comp_ref_mut<'a, C: 'static>(
        &mut self, id: EntityId) -> Option<&'a mut C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find_mut(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get_mut(id.idx) {
                        &Some(ref mut c) => {
                            unsafe { Some(mem::transmute(c.as_mut::<C>().unwrap())) }
                        }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }
}

pub struct World<T> {
    data: Rc<RefCell<WorldData<T>>>,
}

impl<T: System> World<T> {
    /// Create a world coupled with an application specific system object
    pub fn new(master_system: T) -> World<T> {
        let ret = World {
            data: Rc::new(RefCell::new(WorldData::new(master_system))),
        };
        ret.data.borrow_mut().master_system.register(&ret);
        ret
    }

    /// Wrap an EntityId struct into an entity handle that has a backreference
    /// to the world object.
    fn wrap(&self, id: EntityId) -> Entity<T> {
        Entity {
            world: self.data.downgrade(),
            id: id
        }
    }

    /// Create a new entity bound to this world
    pub fn new_entity(&mut self) -> Entity<T> {
        let id = EntityId {
            idx: self.data.borrow_mut().get_idx(),
            uuid: Uuid::new_v4(),
        };
        self.data.borrow_mut().register_new_entity(id);
        let ret = self.wrap(id);
        self.data.borrow_mut().master_system.added(&ret);
        ret
    }

    pub fn system<'a>(&'a self) -> &'a T {
        unsafe { mem::transmute(&self.data.borrow().master_system) }
    }

    pub fn system_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { mem::transmute(&self.data.borrow_mut().master_system) }
    }
}

#[deriving(PartialEq, Clone, Show)]
struct EntityId {
    uuid: Uuid,
    idx: uint,
}

#[deriving(Clone)]
pub struct Entity<T> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T> Show for Entity<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.id)
    }
}

impl<T: System> Entity<T> {
    /// Add or reset a component in the entity. Causes a "changed" call to the
    /// world system.
    pub fn set_component<C: 'static+Clone>(&mut self, comp: C) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, Some(comp));
    }

    /// Remove a component from the entity. Causes a "changed" call to the
    /// world system.
    pub fn remove_component<C: 'static+Clone>(&mut self) {
        let comp : Option<C> = None;
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, comp);
    }

    /// Delete the entity from the world. Causes a "deleted" call to the world
    /// system.
    pub fn delete(&mut self) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .delete_entity(self);
    }

    /// Query whether the entity has a type of component.
    pub fn has<'a, C: 'static>(&self) -> bool {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).is_some()
    }

    /// Get an access proxy to the entity's component if the entity has that
    /// component.
    pub fn into<C: 'static>(&self) -> Option<CompProxyMut<T, C>> {
        if self.has::<C>() {
            Some(CompProxyMut {
                world: self.world.clone(),
                id: self.id
            })
        } else {
            None
        }
    }

    pub fn uuid(&self) -> Uuid {
        self.id.uuid
    }
}

/// Access proxy to entity components. The implementation RefCell (mutable)
/// borrow internally, so using this carelessly may lead to runtime borrow
/// errors. You should generally keep access to the concrete entity data short
/// in scope and low in the call stack to prevent unexpected borrow failures.
pub struct CompProxyMut<T, C> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T: System, C: 'static> Deref<C> for CompProxyMut<T, C> {
    fn deref<'a>(&'a self) -> &'a C {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).unwrap()
    }
}

impl<T: System, C: 'static> DerefMut<C> for CompProxyMut<T, C> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut C {
        self.world.upgrade().unwrap().borrow_mut()
            .comp_ref_mut::<'a, C>(self.id).unwrap()
    }
}
<commit_msg>Uuid lookup in components<commit_after>use std::intrinsics::TypeId;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::fmt::{Formatter, Show, Result};
use std::collections::hashmap::HashMap;
use std::any::{Any, AnyRefExt, AnyMutRefExt};
use std::mem;
use uuid::Uuid;

/// Toplevel container of the entity component system.
pub struct World<T> {
    data: Rc<RefCell<WorldData<T>>>,
}

impl<T: System> World<T> {
    /// Create a world coupled with an application specific system object
    pub fn new(master_system: T) -> World<T> {
        let ret = World {
            data: Rc::new(RefCell::new(WorldData::new(master_system))),
        };
        ret.data.borrow_mut().master_system.register(&ret);
        ret
    }

    /// Wrap an EntityId struct into an entity handle that has a backreference
    /// to the world object.
    fn wrap(&self, id: EntityId) -> Entity<T> {
        Entity {
            world: self.data.downgrade(),
            id: id
        }
    }

    /// Create a new entity bound to this world
    pub fn new_entity(&mut self) -> Entity<T> {
        let id = EntityId {
            idx: self.data.borrow_mut().get_idx(),
            uuid: Uuid::new_v4(),
        };
        self.data.borrow_mut().register_new_entity(id);
        let ret = self.wrap(id);
        self.data.borrow_mut().master_system.added(&ret);
        ret
    }

    pub fn system<'a>(&'a self) -> &'a T {
        unsafe { mem::transmute(&self.data.borrow().master_system) }
    }

    pub fn system_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { mem::transmute(&self.data.borrow_mut().master_system) }
    }

    pub fn find_entity(&self, uuid: &Uuid) -> Option<Entity<T>> {
        match self.data.borrow().uuids.find(uuid) {
            Some(idx) => Some(self.wrap(EntityId { uuid: *uuid, idx: *idx })),
            None => None
        }
    }
}

/// Callback interface for application data connected to the component system
/// world.
pub trait System {
    /// Callback for initially attaching the system to a world
    fn register(&mut self, world: &World<Self>);
    /// Callback for adding a new entity to world
    fn added(&mut self, e: &Entity<Self>);
    /// Callback for a component being added or removed in an entity. Note that
    /// this is not called when the data of an existing component is written
    /// to, only if the component is replaced or removed.
    fn changed<C>(&mut self, e: &Entity<Self>, component: Option<&C>);
    /// Callback for an entity being deleted
    fn deleted(&mut self, e: &Entity<Self>);
}

#[deriving(Clone)]
pub struct Entity<T> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T> Show for Entity<T> {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}", self.id)
    }
}

impl<T: System> Entity<T> {
    /// Add or reset a component in the entity. Causes a "changed" call to the
    /// world system.
    pub fn set_component<C: 'static+Clone>(&mut self, comp: C) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, Some(comp));
    }

    /// Remove a component from the entity. Causes a "changed" call to the
    /// world system.
    pub fn remove_component<C: 'static+Clone>(&mut self) {
        let comp : Option<C> = None;
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .set_component(self, comp);
    }

    /// Delete the entity from the world. Causes a "deleted" call to the world
    /// system.
    pub fn delete(&mut self) {
        self.world.upgrade().unwrap().borrow_mut().deref_mut()
            .delete_entity(self);
    }

    /// Query whether the entity has a type of component.
    pub fn has<'a, C: 'static>(&self) -> bool {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).is_some()
    }

    /// Get an access proxy to the entity's component if the entity has that
    /// component.
    pub fn into<C: 'static>(&self) -> Option<CompProxyMut<T, C>> {
        if self.has::<C>() {
            Some(CompProxyMut {
                world: self.world.clone(),
                id: self.id
            })
        } else {
            None
        }
    }

    pub fn uuid(&self) -> Uuid {
        self.id.uuid
    }
}

/// Access proxy to entity components. The implementation RefCell (mutable)
/// borrow internally, so using this carelessly may lead to runtime borrow
/// errors. You should generally keep access to the concrete entity data short
/// in scope and low in the call stack to prevent unexpected borrow failures.
pub struct CompProxyMut<T, C> {
    world: Weak<RefCell<WorldData<T>>>,
    id: EntityId,
}

impl<T: System, C: 'static> Deref<C> for CompProxyMut<T, C> {
    fn deref<'a>(&'a self) -> &'a C {
        self.world.upgrade().unwrap().borrow()
            .comp_ref::<'a, C>(self.id).unwrap()
    }
}

impl<T: System, C: 'static> DerefMut<C> for CompProxyMut<T, C> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut C {
        self.world.upgrade().unwrap().borrow_mut()
            .comp_ref_mut::<'a, C>(self.id).unwrap()
    }
}

#[deriving(PartialEq, Clone, Show)]
struct EntityId {
    uuid: Uuid,
    idx: uint,
}

struct WorldData<T> {
    // XXX: This is much less efficient than it could be. A serious
    // implementation would use unboxed vecs for the components and would
    // provide lookup methods faster than a HashMap find to access the
    // components
    components: HashMap<TypeId, Vec<Option<Box<Any>>>>,

    next_idx: uint,
    reusable_idxs: Vec<uint>,
    uuids: HashMap<Uuid, uint>,

    master_system: T,
}

impl<T: System> WorldData<T> {
    fn new(master_system: T) -> WorldData<T> {
        WorldData {
            components: HashMap::new(),
            next_idx: 0,
            reusable_idxs: vec!(),
            uuids: HashMap::new(),
            master_system: master_system,
        }
    }

    fn register_new_entity(&mut self, id: EntityId) {
        assert!(!self.uuids.contains_key(&id.uuid),
            "New entity clobbering existing one");
        self.uuids.insert(id.uuid, id.idx);
    }

    fn delete_entity(&mut self, e: &Entity<T>) {
        self.check_entity(e.id);
        self.uuids.remove(&e.id.uuid);

        for (_, c) in self.components.mut_iter() {
            if c.len() > e.id.idx {
                c.as_mut_slice()[e.id.idx] = None;
            }
        }

        self.reusable_idxs.push(e.id.idx);

        self.master_system.deleted(e);
    }

    /// Return the next unused reusable entity id.
    fn get_idx(&mut self) -> uint {
        match self.reusable_idxs.pop() {
            None => {
                let ret = self.next_idx;
                self.next_idx += 1;
                ret
            }
            Some(idx) => idx
        }
    }

    fn check_entity(&self, id: EntityId) {
        assert!(self.uuids.contains_key(&id.uuid), "Unknown entity UUID");
        assert!(*self.uuids.find(&id.uuid).unwrap() == id.idx, "Entity UUID mismatch");
    }

    fn set_component<C: 'static+Clone>(&mut self, e: &Entity<T>, comp: Option<C>) {
        self.check_entity(e.id);
        let type_id = TypeId::of::<C>();
        // We haven't seen this kind of component yet.
        if !self.components.contains_key(&type_id) {
            self.components.insert(type_id, vec!());
        }

        let bin = self.components.find_mut(&type_id).unwrap();

        // XXX: grow_set didn't work.
        while bin.len() <= e.id.idx { bin.push(None); }
        bin.as_mut_slice()[e.id.idx] = match comp {
            None => None,
            Some(c) => Some(box c as Box<Any>),
        };

        match bin.as_mut_slice()[e.id.idx] {
            None => self.master_system.changed::<C>(e, None),
            Some(ref c) => self.master_system.changed(e, Some(&c)),
        };
    }

    fn comp_ref<'a, C: 'static>(
        &self, id: EntityId) -> Option<&'a C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get(id.idx) {
                        &Some(ref c) => { unsafe { Some(mem::transmute(c.as_ref::<C>().unwrap())) } }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }

    fn comp_ref_mut<'a, C: 'static>(
        &mut self, id: EntityId) -> Option<&'a mut C> {
        self.check_entity(id);
        let type_id = TypeId::of::<C>();
        match self.components.find_mut(&type_id) {
            None => { None }
            Some(bin) => {
                if id.idx < bin.len() {
                    match bin.get_mut(id.idx) {
                        &Some(ref mut c) => {
                            unsafe { Some(mem::transmute(c.as_mut::<C>().unwrap())) }
                        }
                        &None => None
                    }
                } else {
                    None
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>
#[ allow( unused_imports ) ]
use derive_tools as TheModule;
use test_tools::*;

#[ path = "inc.rs" ]
mod inc;
<commit_msg>!test<commit_after>
#[ allow( unused_imports ) ]
use derive_tools as TheModule;
use test_tools::*;

#[ path = "inc.rs" ]
mod inc;

<|endoftext|>