<commit_before>use std::sync::Arc;

use zbackup::proto;

/// The size of a ZBackup encryption key, in bytes
pub const KEY_SIZE: usize = 16;

/// The size of a ZBackup HMAC, in bytes
pub const HMAC_SIZE: usize = 20;

/// The size of a ZBackup initialisation vector, in bytes
pub const IV_SIZE: usize = 16;

/// The size of the buffers used when reading and decompressing ZBackup data
pub const BUFFER_SIZE: usize = 0x10000;

/// The default number of total jobs to queue up during a restore operation.
/// Since many chunks can be stored in a single bundle, and we can only use a
/// single thread to decompress one bundle, this needs to be high enough to
/// guarantee that we will always have enough jobs in the queue to make use of
/// all of the threads available.
pub const WORK_JOBS_TOTAL: usize = 0x1000;

/// The batch size for adding and removing jobs from the work queue. By doing
/// this in batches, we can avoid a certain amount of unnecessary locking.
pub const WORK_JOBS_BATCH: usize = 0x100;

/// A ZBackup bundle ID
pub type BundleId = [u8; 24];

/// A ZBackup chunk ID
pub type ChunkId = [u8; 24];

/// A ZBackup index ID
pub type IndexId = [u8; 24];

/// A ZBackup chunk's data
pub type ChunkData = Arc <Vec <u8>>;

/// A ZBackup encryption key
pub type EncryptionKey = [u8; KEY_SIZE];

/// A ZBackup index entry. This combined the header with the bundle info, since
/// generally both of these are needed to make use of the data.
pub type IndexEntry = (
	proto::IndexBundleHeader,
	proto::BundleInfo,
);

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory uncompressed, in an LRU cache.
pub const MAX_UNCOMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x100;

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory after LZO-compression, in an LRU cache.
pub const MAX_COMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x800;

/// The default number of compressed filesystem cache entries. This number of
/// chunks will be stored in a temporary directory after LZO-compression.
pub const MAX_COMPRESSED_FILESYSTEM_CACHE_ENTRIES: usize = 0x4000;

/// The default location for the filesystem cache.
pub const FILESYSTEM_CACHE_PATH: & 'static str = "/tmp/rzbackup-cache";

// ex: noet ts=4 filetype=rust
<commit_msg>make lookahead queue size more conservative, reduce buffer size<commit_after>use std::sync::Arc;

use zbackup::proto;

/// The size of a ZBackup encryption key, in bytes
pub const KEY_SIZE: usize = 16;

/// The size of a ZBackup HMAC, in bytes
pub const HMAC_SIZE: usize = 20;

/// The size of a ZBackup initialisation vector, in bytes
pub const IV_SIZE: usize = 16;

/// The size of the buffers used when reading and decompressing ZBackup data
pub const BUFFER_SIZE: usize = 0x2000;

/// The default number of total jobs to queue up during a restore operation.
/// Since many chunks can be stored in a single bundle, and we can only use a
/// single thread to decompress one bundle, this needs to be high enough to
/// guarantee that we will always have enough jobs in the queue to make use of
/// all of the threads available.
pub const WORK_JOBS_TOTAL: usize = 0x200;

/// The batch size for adding and removing jobs from the work queue. By doing
/// this in batches, we can avoid a certain amount of unnecessary locking.
pub const WORK_JOBS_BATCH: usize = 0x20;

/// A ZBackup bundle ID
pub type BundleId = [u8; 24];

/// A ZBackup chunk ID
pub type ChunkId = [u8; 24];

/// A ZBackup index ID
pub type IndexId = [u8; 24];

/// A ZBackup chunk's data
pub type ChunkData = Arc <Vec <u8>>;

/// A ZBackup encryption key
pub type EncryptionKey = [u8; KEY_SIZE];

/// A ZBackup index entry. This combined the header with the bundle info, since
/// generally both of these are needed to make use of the data.
pub type IndexEntry = (
	proto::IndexBundleHeader,
	proto::BundleInfo,
);

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory uncompressed, in an LRU cache.
pub const MAX_UNCOMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x100;

/// The default number of uncompressed memory cache entries. This number of
/// chunks will be kept in memory after LZO-compression, in an LRU cache.
pub const MAX_COMPRESSED_MEMORY_CACHE_ENTRIES: usize = 0x800;

/// The default number of compressed filesystem cache entries. This number of
/// chunks will be stored in a temporary directory after LZO-compression.
pub const MAX_COMPRESSED_FILESYSTEM_CACHE_ENTRIES: usize = 0x4000;

/// The default location for the filesystem cache.
pub const FILESYSTEM_CACHE_PATH: & 'static str = "/tmp/rzbackup-cache";

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>use calx::color::*;
use calx::{Rgba, Kernel, KernelTerrain};
use calx::backend::{Image};
use content::{TerrainType, Brush};

pub trait RenderTerrain {
    /// Generate draw instructions for a terrain cell.
    ///
    /// Params to the draw function: Draw layer, brush, brush frame, main
    /// color, border color.
    fn render<F>(&self, draw: F)
        where F: FnMut(Image, Angle, Rgba, Rgba);
}

/// Surface angle for a visible sprite, used for dynamic lighting.
///
/// ```notrust
///
///      # north #
///     n         n
///    w           e
///
///  # x_         _y #
///   s  -x_   _y-  s
///    w    -*-    e
///       y-   -x
///      # south #
/// ```
pub enum Angle {
    Up,
    North,
    Northeast,
    Southeast,
    YWall,
    South,
    XWall,
    Southwest,
    Northwest,
}

impl Angle {
    /// Return the angle of the vertical surface, if any, in degrees.
    pub fn degree(&self) -> Option<f32> {
        match *self {
            Angle::Up => None,
            Angle::North => Some(0.0),
            Angle::Northeast => Some(60.0),
            Angle::Southeast => Some(120.0),
            Angle::YWall => Some(150.0),
            Angle::South => Some(180.0),
            Angle::XWall => Some(210.0),
            Angle::Southwest => Some(240.0),
            Angle::Northwest => Some(300.0),
        }
    }
}

impl RenderTerrain for Kernel<TerrainType> {
    fn render<F>(&self, mut draw: F)
        where F: FnMut(Image, Angle, Rgba, Rgba)
    {
        use content::Brush::*;
        use self::Angle::*;

        enum T {
            Floor(Brush, Rgba),
            Floor2(Brush, Rgba, Rgba),
            Prop(Brush, Rgba),
            Prop2(Brush, Rgba, Rgba),
            Wall(Brush, Rgba),
            Wall2(Brush, Rgba, Rgba),
            Block(Brush, Rgba),
            Block2(Brush, Rgba, Rgba),
        }

        fn process<C: KernelTerrain, F>(
            k: &Kernel<C>, draw: &mut F, kind: T)
            where F: FnMut(Image, Angle, Rgba, Rgba)
        {
            match kind {
                T::Floor(brush, color) => process(k, draw, T::Floor2(brush, color, BLACK)),
                T::Prop(brush, color) => process(k, draw, T::Prop2(brush, color, BLACK)),
                T::Wall(brush, color) => process(k, draw, T::Wall2(brush, color, BLACK)),
                T::Block(brush, color) => process(k, draw, T::Block2(brush, color, BLACK)),

                T::Floor2(brush, color, back) => {
                    draw(brush.get(0), Up, color, back);
                }
                T::Prop2(brush, color, back) => {
                    draw(brush.get(0), South, color, back);
                }
                T::Wall2(brush, color, back) => {
                    let extends = k.wall_extends();
                    if extends[0] {
                        draw(brush.get(2), XWall, color, back);
                    } else {
                        draw(brush.get(0), XWall, color, back);
                    }
                    if extends[1] {
                        draw(brush.get(3), YWall, color, back);
                    } else {
                        draw(brush.get(1), YWall, color, back);
                    }
                }
                T::Block2(brush, color, back) => {
                    let faces = k.block_faces();

                    if faces[5] { draw(BlockRear.get(0), Northwest, color, BLACK); }
                    if faces[0] { draw(BlockRear.get(1), North, color, BLACK); }
                    if faces[1] { draw(BlockRear.get(2), Northeast, color, BLACK); }
                    if faces[4] { draw(brush.get(0), Southwest, color, back); }
                    if faces[3] { draw(brush.get(1), South, color, back); }
                    if faces[2] { draw(brush.get(2), Southeast, color, back); }
                }
            }
        }

        for i in match self.center {
            TerrainType::Void => vec![T::Floor(BlankFloor, MAGENTA)],
            TerrainType::Floor => vec![T::Floor(Floor, SLATEGRAY)],
            TerrainType::Water => vec![T::Floor(Water, ROYALBLUE)],
            TerrainType::Shallows => vec![T::Floor(Shallows, CORNFLOWERBLUE)],
            TerrainType::Magma => vec![T::Floor2(Water, YELLOW, DARKRED)],
            TerrainType::Downstairs => vec![T::Floor(StairsDown, SLATEGRAY)],
            TerrainType::Wall => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(BrickWall, LIGHTSLATEGRAY),
            ],
            TerrainType::RockWall => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(RockWall, LIGHTSLATEGRAY),
            ],
            TerrainType::Rock => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Block(BlockRock, DARKGOLDENROD),
            ],
            TerrainType::Tree => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(TreeTrunk, SADDLEBROWN),
                T::Prop(TreeFoliage, GREEN),
            ],
            TerrainType::Grass => vec![T::Floor(Floor, DARKGREEN)],
            TerrainType::Grass2 => vec![ T::Floor(Grass, DARKGREEN)],
            TerrainType::Stalagmite => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Stalagmite, DARKGOLDENROD),
            ],
            TerrainType::Door => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(BrickOpenWall, LIGHTSLATEGRAY),
                T::Wall(DoorWall, SADDLEBROWN),
            ],
            TerrainType::OpenDoor => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(BrickOpenWall, LIGHTSLATEGRAY),
            ],
            TerrainType::Window => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(BrickWindowWall, LIGHTSLATEGRAY),
            ],
            TerrainType::Table => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Table, DARKGOLDENROD),
            ],
            TerrainType::Fence => vec![
                // The floor type beneath the fence tile is visible, make it grass
                // if there's grass behind the fence. Otherwise make it regular
                // floor.
                if self.n == TerrainType::Grass || self.ne == TerrainType::Grass || self.nw == TerrainType::Grass {
                    T::Floor(Grass, GREEN)
                } else {
                    T::Floor(Floor, SLATEGRAY)
                },
                T::Wall(FenceWall, DARKGOLDENROD),
            ],
            TerrainType::Bars => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Wall(BarsWall, GAINSBORO),
            ],
            TerrainType::Fountain => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Table, DARKGOLDENROD),
            ],
            TerrainType::Altar => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Fountain, GAINSBORO),
            ],
            TerrainType::Barrel => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Barrell, DARKGOLDENROD),
            ],
            TerrainType::Grave => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Grave, SLATEGRAY),
            ],
            TerrainType::Stone => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Stone, SLATEGRAY),
            ],
            TerrainType::Menhir => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(Menhir, SLATEGRAY),
            ],
            TerrainType::DeadTree => vec![
                T::Floor(BlankFloor, SLATEGRAY),
                T::Prop(TreeTrunk, SADDLEBROWN),
            ],
        }.into_iter() {
            process(self, &mut draw, i);
        }
    }
}
<commit_msg>Renderterrain as free function<commit_after>use calx::color::*;
use calx::{Rgba, Kernel, KernelTerrain};
use calx::backend::{Image};
use content::{TerrainType, Brush};

/// Surface angle for a visible sprite, used for dynamic lighting.
///
/// ```notrust
///
///      # north #
///     n         n
///    w           e
///
///  # x_         _y #
///   s  -x_   _y-  s
///    w    -*-    e
///       y-   -x
///      # south #
/// ```
pub enum Angle {
    Up,
    North,
    Northeast,
    Southeast,
    YWall,
    South,
    XWall,
    Southwest,
    Northwest,
}

impl Angle {
    /// Return the angle of the vertical surface, if any, in degrees.
    pub fn degree(&self) -> Option<f32> {
        match *self {
            Angle::Up => None,
            Angle::North => Some(0.0),
            Angle::Northeast => Some(60.0),
            Angle::Southeast => Some(120.0),
            Angle::YWall => Some(150.0),
            Angle::South => Some(180.0),
            Angle::XWall => Some(210.0),
            Angle::Southwest => Some(240.0),
            Angle::Northwest => Some(300.0),
        }
    }
}

/// Generate draw instructions for a terrain cell.
///
/// Params to the draw function: Draw layer, brush, brush frame, main
/// color, border color.
pub fn render<F>(k: &Kernel<TerrainType>, mut draw: F)
    where F: FnMut(Image, Angle, Rgba, Rgba)
{
    use content::Brush::*;
    use self::Angle::*;

    enum T {
        Floor(Brush, Rgba),
        Floor2(Brush, Rgba, Rgba),
        Prop(Brush, Rgba),
        Prop2(Brush, Rgba, Rgba),
        Wall(Brush, Rgba),
        Wall2(Brush, Rgba, Rgba),
        Block(Brush, Rgba),
        Block2(Brush, Rgba, Rgba),
    }

    fn process<C: KernelTerrain, F>(
        k: &Kernel<C>, draw: &mut F, kind: T)
        where F: FnMut(Image, Angle, Rgba, Rgba)
        {
            match kind {
                T::Floor(brush, color) => process(k, draw, T::Floor2(brush, color, BLACK)),
                T::Prop(brush, color) => process(k, draw, T::Prop2(brush, color, BLACK)),
                T::Wall(brush, color) => process(k, draw, T::Wall2(brush, color, BLACK)),
                T::Block(brush, color) => process(k, draw, T::Block2(brush, color, BLACK)),

                T::Floor2(brush, color, back) => {
                    draw(brush.get(0), Up, color, back);
                }
                T::Prop2(brush, color, back) => {
                    draw(brush.get(0), South, color, back);
                }
                T::Wall2(brush, color, back) => {
                    let extends = k.wall_extends();
                    if extends[0] {
                        draw(brush.get(2), XWall, color, back);
                    } else {
                        draw(brush.get(0), XWall, color, back);
                    }
                    if extends[1] {
                        draw(brush.get(3), YWall, color, back);
                    } else {
                        draw(brush.get(1), YWall, color, back);
                    }
                }
                T::Block2(brush, color, back) => {
                    let faces = k.block_faces();

                    if faces[5] { draw(BlockRear.get(0), Northwest, color, BLACK); }
                    if faces[0] { draw(BlockRear.get(1), North, color, BLACK); }
                    if faces[1] { draw(BlockRear.get(2), Northeast, color, BLACK); }
                    if faces[4] { draw(brush.get(0), Southwest, color, back); }
                    if faces[3] { draw(brush.get(1), South, color, back); }
                    if faces[2] { draw(brush.get(2), Southeast, color, back); }
                }
            }
        }

    for i in match k.center {
        TerrainType::Void => vec![T::Floor(BlankFloor, MAGENTA)],
        TerrainType::Floor => vec![T::Floor(Floor, SLATEGRAY)],
        TerrainType::Water => vec![T::Floor(Water, ROYALBLUE)],
        TerrainType::Shallows => vec![T::Floor(Shallows, CORNFLOWERBLUE)],
        TerrainType::Magma => vec![T::Floor2(Water, YELLOW, DARKRED)],
        TerrainType::Downstairs => vec![T::Floor(StairsDown, SLATEGRAY)],
        TerrainType::Wall => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(BrickWall, LIGHTSLATEGRAY),
        ],
        TerrainType::RockWall => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(RockWall, LIGHTSLATEGRAY),
        ],
        TerrainType::Rock => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Block(BlockRock, DARKGOLDENROD),
        ],
        TerrainType::Tree => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(TreeTrunk, SADDLEBROWN),
            T::Prop(TreeFoliage, GREEN),
        ],
        TerrainType::Grass => vec![T::Floor(Floor, DARKGREEN)],
        TerrainType::Grass2 => vec![ T::Floor(Grass, DARKGREEN)],
        TerrainType::Stalagmite => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Stalagmite, DARKGOLDENROD),
        ],
        TerrainType::Door => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(BrickOpenWall, LIGHTSLATEGRAY),
            T::Wall(DoorWall, SADDLEBROWN),
        ],
        TerrainType::OpenDoor => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(BrickOpenWall, LIGHTSLATEGRAY),
        ],
        TerrainType::Window => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(BrickWindowWall, LIGHTSLATEGRAY),
        ],
        TerrainType::Table => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Table, DARKGOLDENROD),
        ],
        TerrainType::Fence => vec![
            // The floor type beneath the fence tile is visible, make it grass
            // if there's grass behind the fence. Otherwise make it regular
            // floor.
            if k.n == TerrainType::Grass || k.ne == TerrainType::Grass || k.nw == TerrainType::Grass {
                T::Floor(Grass, GREEN)
            } else {
                T::Floor(Floor, SLATEGRAY)
            },
            T::Wall(FenceWall, DARKGOLDENROD),
        ],
        TerrainType::Bars => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Wall(BarsWall, GAINSBORO),
        ],
        TerrainType::Fountain => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Table, DARKGOLDENROD),
        ],
        TerrainType::Altar => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Fountain, GAINSBORO),
        ],
        TerrainType::Barrel => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Barrell, DARKGOLDENROD),
        ],
        TerrainType::Grave => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Grave, SLATEGRAY),
        ],
        TerrainType::Stone => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Stone, SLATEGRAY),
        ],
        TerrainType::Menhir => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(Menhir, SLATEGRAY),
        ],
        TerrainType::DeadTree => vec![
            T::Floor(BlankFloor, SLATEGRAY),
            T::Prop(TreeTrunk, SADDLEBROWN),
        ],
    }.into_iter() {
        process(k, &mut draw, i);
    }
}
<|endoftext|>


<commit_before>//! Util functions for interaction with Lapin library
//

use std::net::SocketAddr;

use amq_protocol::uri::AMQPUri;

use super::super::cli::CliOptions;

/// Generates a connection URL to RabbitMQ broker.
pub fn get_address_to_rabbitmq(uri: &AMQPUri) -> SocketAddr {
    let host = uri.clone().authority.host;
    let listened_port = uri.clone().authority.port;
    format!("{}:{}", host, listened_port).parse().unwrap()
}

/// Returns an instance of AMQPUri based on the parsed CLI options.
pub fn get_uri(cli: &CliOptions) -> AMQPUri {
    let schema = match cli.rabbitmq_secured {
        true => "amqps",
        false => "amqp",
    };
    format!(
        "{}://{}:{}@{}:{}/{}",
        schema.to_string(),
        cli.rabbitmq_username.clone(),
        cli.rabbitmq_password.clone(),
        cli.rabbitmq_host.clone(),
        cli.rabbitmq_port,
        cli.rabbitmq_virtual_host.clone()
    ).parse().unwrap_or(AMQPUri::default())
}
<commit_msg>Added logging for the case when passed an invalid parameters.<commit_after>//! Util functions for interaction with Lapin library
//

use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};

use amq_protocol::uri::AMQPUri;

use super::super::cli::CliOptions;

/// Generates a connection URL to RabbitMQ broker.
pub fn get_address_to_rabbitmq(uri: &AMQPUri) -> SocketAddr {
    let host = uri.clone().authority.host;
    let listened_port = uri.clone().authority.port;
    let address = format!("{}:{}", host, listened_port).to_socket_addrs();

    match address {
        Ok(addr) => addr.collect::<Vec<_>>()[0],
        Err(_) => {
            error!("Unable to resolve the address to the RabbitMQ \
                    node. Please, check input parameters to the RabbitMQ node \
                    or specify the certain IP-address.");
            warn!("Used the `127.0.0.1:5672` value for connection to the node.");
            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5672)
        }
    }
}

/// Returns an instance of AMQPUri based on the parsed CLI options.
pub fn get_uri(cli: &CliOptions) -> AMQPUri {
    let schema = match cli.rabbitmq_secured {
        true => "amqps",
        false => "amqp",
    };
    format!(
        "{}://{}:{}@{}:{}/{}",
        schema.to_string(),
        cli.rabbitmq_username.clone(),
        cli.rabbitmq_password.clone(),
        cli.rabbitmq_host.clone(),
        cli.rabbitmq_port,
        cli.rabbitmq_virtual_host.clone()
    ).parse().unwrap_or(AMQPUri::default())
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().map(|url| match url.path() {
            "/F32Constant" => PrimitiveEffect::F32Constant,
            "/Delay" => PrimitiveEffect::Delay,
            "/Multiply" => PrimitiveEffect::Multiply,
            "/Divide" => PrimitiveEffect::Divide,
            "/Modulo" => PrimitiveEffect::Modulo,
            "/Minimum" => PrimitiveEffect::Minimum,
            // TODO: return an error type
            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
        });
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        name: id.name.clone(),
                        urls: id.urls.clone(),
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    // sha256 was already verified; no need to update it
                    id: id,
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256");
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    // TODO: since we've matched the effect, we only need to recalculate
                    // the id if the original search had missing hashes.
                    let id = desc.id();
                    match RouteGraph::from_adjlist(desc.adjlist, resman) {
                        Ok(graph) => {
                            let me = Self {
                                id,
                                meta: desc.meta,
                                data: EffectData::RouteGraph(graph),
                            };
                            // TODO: implement some form of caching
                            return Ok(Rc::new(me));
                        },
                        Err(error) => warn!("RouteGraph::from_adjlist failed: {:?}", error)
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            // TODO: sha256 may need to be updated.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        warn!("Unable to deserialize EffectDesc: {:?}", error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.name.as_str()
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<commit_msg>Don't panic on illegal primitive effect<commit_after>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().and_then(|url| match url.path() {
            "/F32Constant" => Some(PrimitiveEffect::F32Constant),
            "/Delay"       => Some(PrimitiveEffect::Delay),
            "/Multiply"    => Some(PrimitiveEffect::Multiply),
            "/Divide"      => Some(PrimitiveEffect::Divide),
            "/Modulo"      => Some(PrimitiveEffect::Modulo),
            "/Minimum"     => Some(PrimitiveEffect::Minimum),
            _ => {
                warn!("Unrecognized primitive effect: {} (full url: {})", url.path(), url);
                None
            }
        });
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        name: id.name.clone(),
                        urls: id.urls.clone(),
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    // sha256 was already verified; no need to update it
                    id: id,
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256");
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    // TODO: since we've matched the effect, we only need to recalculate
                    // the id if the original search had missing hashes.
                    let id = desc.id();
                    match RouteGraph::from_adjlist(desc.adjlist, resman) {
                        Ok(graph) => {
                            let me = Self {
                                id,
                                meta: desc.meta,
                                data: EffectData::RouteGraph(graph),
                            };
                            // TODO: implement some form of caching
                            return Ok(Rc::new(me));
                        },
                        Err(error) => warn!("RouteGraph::from_adjlist failed: {:?}", error)
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            // TODO: sha256 may need to be updated.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        warn!("Unable to deserialize EffectDesc: {:?}", error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.name.as_str()
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

use rustc_serialize::json::Json;
use chrono::{DateTime, UTC};

use search::term::Term;
use search::token::Token;
use search::analysis::Analyzer;

#[derive(Debug, PartialEq)]
pub enum FieldType {
    String,
    Number {
        size: u8,
        is_float: bool,
    },
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType {
        FieldType::String
    }
}

#[derive(Debug)]
pub struct FieldMapping {
    data_type: FieldType,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    analyzer: Analyzer,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            analyzer: Analyzer::Standard,
        }
    }
}

impl FieldMapping {
    pub fn process_value_for_index(&self, value: Json) -> Option<Vec<Token>> {
        if value == Json::Null {
            return None;
        }

        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyzed strings become TSVectors. Unanalyzed strings become... strings
                        if self.analyzer == Analyzer::None {
                            Some(vec![Token{term: Term::String(string), position: 1}])
                        } else {
                            Some(self.analyzer.run(string))
                        }
                    }
                    Json::I64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::U64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::F64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value_for_index(Json::String(strings.join(" ")))
                    }
                    _ => None,
                }
            }
            FieldType::Number{size, is_float} => {
                match value {
                    // TODO check the numbers fit in "size"
                    Json::U64(num) => Some(vec![Token{term: Term::U64(num), position: 1}]),
                    Json::I64(num) => Some(vec![Token{term: Term::I64(num), position: 1}]),
                    /*Json::F64(num) => {
                        if !is_float {
                            return None;
                        }

                        Some(vec![Token{term: Term::F64(num), position: 1}])
                    }*/
                    _ => None,
                }
            }
            FieldType::Boolean => Some(vec![Token{term: Term::Boolean(parse_boolean(&value)), position: 1}]),
            FieldType::Date => {
                match value {
                    Json::String(string) => {
                        let date_parsed = match string.parse::<DateTime<UTC>>() {
                            Ok(date_parsed) => date_parsed,
                            Err(error) => {
                                // TODO: Handle this properly
                                return None;
                            }
                        };

                        Some(vec![Token{term: Term::DateTime(date_parsed), position: 1}])
                    }
                    Json::U64(num) => {
                        // TODO needs to be interpreted as milliseconds since epoch
                        // This would really help: https://github.com/lifthrasiir/rust-chrono/issues/74
                        None
                    }
                    _ => None
                }
            }
        }
    }

    pub fn process_value_for_query(&self, value: Json) -> Option<Vec<Token>> {
        // Currently not different from process_value_for_index
        self.process_value_for_index(value)
    }
}

#[derive(Debug)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

impl Mapping {
    pub fn from_json(json: &Json) -> Mapping {
        let json = json.as_object().unwrap();
        let properties_json = json.get("properties").unwrap().as_object().unwrap();

        // Parse fields
        let mut fields = HashMap::new();
        for (field_name, field_mapping_json) in properties_json.iter() {
            fields.insert(field_name.clone(),
                          FieldMapping::from_json(field_mapping_json));
        }

        Mapping { fields: fields }
    }
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
            }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl FieldMapping {
    pub fn from_json(json: &Json) -> FieldMapping {
        let json = json.as_object().unwrap();
        let mut field_mapping = FieldMapping::default();

        for (key, value) in json.iter() {
            match key.as_ref() {
                "type" => {
                    let type_name = value.as_string().unwrap();

                    field_mapping.data_type = match type_name.as_ref() {
                        "string" => FieldType::String,
                        "integer" => {
                            FieldType::Number {
                                size: 64,
                                is_float: false,
                            }
                        }
                        "boolean" => FieldType::Boolean,
                        "date" => FieldType::Date,
                        _ => {
                            // TODO; make this an error
                            warn!("unimplemented type name! {}", type_name);
                            FieldType::default()
                        }
                    };
                }
                "index" => {
                    let index = value.as_string().unwrap();
                    if index == "not_analyzed" {
                        field_mapping.analyzer = Analyzer::None;
                    } else {
                        // TODO: Implement other variants and make this an error
                        warn!("unimplemented index setting! {}", index);
                    }
                }
                "index_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        if s == &"edgengram_analyzer" {
                            field_mapping.analyzer = Analyzer::EdgeNGram;
                        }
                    }
                }
                "boost" => {
                    field_mapping.boost = value.as_f64().unwrap();
                }
                "store" => {
                    field_mapping.is_stored = parse_boolean(value);
                }
                "include_in_all" => {
                    field_mapping.is_in_all = parse_boolean(value);
                }
                _ => warn!("unimplemented field mapping key! {}", key),
            }

        }

        field_mapping
    }
}

#[derive(Debug)]
pub struct MappingRegistry {
    mappings: HashMap<String, Mapping>,
}

impl MappingRegistry {
    pub fn new() -> MappingRegistry {
        MappingRegistry {
            mappings: HashMap::new(),
        }
    }

    pub fn get_field(&self, name: &str) -> Option<&FieldMapping> {
        for mapping in self.mappings.values() {
            if let Some(ref field_mapping) = mapping.fields.get(name) {
                return Some(field_mapping);
            }
        }

        None
    }
}

impl Deref for MappingRegistry {
    type Target = HashMap<String, Mapping>;

    fn deref(&self) -> &HashMap<String, Mapping> {
        &self.mappings
    }
}

impl DerefMut for MappingRegistry {
    fn deref_mut(&mut self) -> &mut HashMap<String, Mapping> {
        &mut self.mappings
    }
}
<commit_msg>Simplify FieldMapping number type<commit_after>use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

use rustc_serialize::json::Json;
use chrono::{DateTime, UTC};

use search::term::Term;
use search::token::Token;
use search::analysis::Analyzer;

#[derive(Debug, PartialEq)]
pub enum FieldType {
    String,
    Integer,
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType {
        FieldType::String
    }
}

#[derive(Debug)]
pub struct FieldMapping {
    data_type: FieldType,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    analyzer: Analyzer,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            analyzer: Analyzer::Standard,
        }
    }
}

impl FieldMapping {
    pub fn process_value_for_index(&self, value: Json) -> Option<Vec<Token>> {
        if value == Json::Null {
            return None;
        }

        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyzed strings become TSVectors. Unanalyzed strings become... strings
                        if self.analyzer == Analyzer::None {
                            Some(vec![Token{term: Term::String(string), position: 1}])
                        } else {
                            Some(self.analyzer.run(string))
                        }
                    }
                    Json::I64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::F64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value_for_index(Json::String(strings.join(" ")))
                    }
                    _ => None,
                }
            }
            FieldType::Integer => {
                match value {
                    Json::U64(num) => Some(vec![Token{term: Term::I64(num as i64), position: 1}]),
                    Json::I64(num) => Some(vec![Token{term: Term::I64(num), position: 1}]),
                    _ => None,
                }
            }
            FieldType::Boolean => Some(vec![Token{term: Term::Boolean(parse_boolean(&value)), position: 1}]),
            FieldType::Date => {
                match value {
                    Json::String(string) => {
                        let date_parsed = match string.parse::<DateTime<UTC>>() {
                            Ok(date_parsed) => date_parsed,
                            Err(error) => {
                                // TODO: Handle this properly
                                return None;
                            }
                        };

                        Some(vec![Token{term: Term::DateTime(date_parsed), position: 1}])
                    }
                    Json::U64(num) => {
                        // TODO needs to be interpreted as milliseconds since epoch
                        // This would really help: https://github.com/lifthrasiir/rust-chrono/issues/74
                        None
                    }
                    _ => None
                }
            }
        }
    }

    pub fn process_value_for_query(&self, value: Json) -> Option<Vec<Token>> {
        // Currently not different from process_value_for_index
        self.process_value_for_index(value)
    }
}

#[derive(Debug)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

impl Mapping {
    pub fn from_json(json: &Json) -> Mapping {
        let json = json.as_object().unwrap();
        let properties_json = json.get("properties").unwrap().as_object().unwrap();

        // Parse fields
        let mut fields = HashMap::new();
        for (field_name, field_mapping_json) in properties_json.iter() {
            fields.insert(field_name.clone(),
                          FieldMapping::from_json(field_mapping_json));
        }

        Mapping { fields: fields }
    }
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
            }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl FieldMapping {
    pub fn from_json(json: &Json) -> FieldMapping {
        let json = json.as_object().unwrap();
        let mut field_mapping = FieldMapping::default();

        for (key, value) in json.iter() {
            match key.as_ref() {
                "type" => {
                    let type_name = value.as_string().unwrap();

                    field_mapping.data_type = match type_name.as_ref() {
                        "string" => FieldType::String,
                        "integer" => FieldType::Integer,
                        "boolean" => FieldType::Boolean,
                        "date" => FieldType::Date,
                        _ => {
                            // TODO; make this an error
                            warn!("unimplemented type name! {}", type_name);
                            FieldType::default()
                        }
                    };
                }
                "index" => {
                    let index = value.as_string().unwrap();
                    if index == "not_analyzed" {
                        field_mapping.analyzer = Analyzer::None;
                    } else {
                        // TODO: Implement other variants and make this an error
                        warn!("unimplemented index setting! {}", index);
                    }
                }
                "index_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        if s == &"edgengram_analyzer" {
                            field_mapping.analyzer = Analyzer::EdgeNGram;
                        }
                    }
                }
                "boost" => {
                    field_mapping.boost = value.as_f64().unwrap();
                }
                "store" => {
                    field_mapping.is_stored = parse_boolean(value);
                }
                "include_in_all" => {
                    field_mapping.is_in_all = parse_boolean(value);
                }
                _ => warn!("unimplemented field mapping key! {}", key),
            }

        }

        field_mapping
    }
}

#[derive(Debug)]
pub struct MappingRegistry {
    mappings: HashMap<String, Mapping>,
}

impl MappingRegistry {
    pub fn new() -> MappingRegistry {
        MappingRegistry {
            mappings: HashMap::new(),
        }
    }

    pub fn get_field(&self, name: &str) -> Option<&FieldMapping> {
        for mapping in self.mappings.values() {
            if let Some(ref field_mapping) = mapping.fields.get(name) {
                return Some(field_mapping);
            }
        }

        None
    }
}

impl Deref for MappingRegistry {
    type Target = HashMap<String, Mapping>;

    fn deref(&self) -> &HashMap<String, Mapping> {
        &self.mappings
    }
}

impl DerefMut for MappingRegistry {
    fn deref_mut(&mut self) -> &mut HashMap<String, Mapping> {
        &mut self.mappings
    }
}
<|endoftext|>


<commit_before>extern crate decorum;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate nalgebra;
extern crate num;
extern crate plexus;
extern crate rand;

mod camera;
mod pipeline;
mod renderer;

use decorum::R32;
use nalgebra::{Matrix4, Point3, Scalar};
use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlWindow, WindowBuilder, WindowEvent};
use num::traits::FloatConst;
use plexus::buffer::MeshBuffer;
use plexus::generate::sphere::UVSphere;
use plexus::geometry::{Attribute, Geometry};
use plexus::graph::Mesh;
use plexus::prelude::*;

use camera::Camera;
use pipeline::{Color4, Transform, Vertex};
use renderer::{GlutinRenderer, Renderer};

impl<T> Attribute for Color4<T>
where
    T: Scalar,
{
}

struct FaceColorGeometry;

impl Geometry for FaceColorGeometry {
    type Vertex = Point3<f32>;
    type Edge = ();
    type Face = Color4<f32>;
}

fn new_mesh_buffer() -> MeshBuffer<u32, Vertex> {
    let mut mesh = UVSphere::<R32>::with_unit_radius(32, 32)
        .polygons_with_position()
        .map_vertices(|position| -> Point3<R32> { position.into() })
        .collect::<Mesh<FaceColorGeometry>>();
    for mut face in mesh.faces_mut() {
        face.geometry = Color4::random();
    }
    mesh.to_mesh_buffer_by_face_with(|face, vertex| Vertex::new(&vertex.geometry, &face.geometry))
        .unwrap()
}

fn new_camera(aspect: f32) -> Camera<f32> {
    let mut camera = Camera::new(aspect, 45.0, -1.0, 2.0);
    camera.look_at(&Point3::new(2.0, 1.0, 2.0), &Point3::origin());
    camera
}

fn new_renderer(width: u32, height: u32) -> (EventsLoop, Renderer<GlutinRenderer>) {
    let seat = EventsLoop::new();
    let window = GlWindow::new(
        WindowBuilder::new()
            .with_title("Plexus Viewer")
            .with_dimensions(width, height),
        ContextBuilder::new(),
        &seat,
    ).unwrap();
    (seat, Renderer::from_glutin_window(window))
}

fn main() {
    let (mut seat, mut renderer) = new_renderer(1024, 576);
    let mut camera = new_camera(1024.0 / 576.0);
    let mesh = new_mesh_buffer();
    seat.run_forever(|event| {
        match event {
            Event::WindowEvent {
                event: WindowEvent::Closed,
                ..
            } => {
                return ControlFlow::Break;
            }
            Event::WindowEvent {
                event: WindowEvent::Resized(width, height),
                ..
            } => {
                camera = new_camera(width as f32 / height as f32);
                renderer.update_frame_buffer_view();
            }
            _ => {}
        }
        renderer.clear();
        renderer
            .set_transform(&Transform::new(&camera.transform(), &Matrix4::identity()))
            .unwrap();
        renderer.draw_mesh_buffer(&mesh);
        renderer.flush().unwrap();
        ControlFlow::Continue
    });
}
<commit_msg>Remove unused import.<commit_after>extern crate decorum;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate nalgebra;
extern crate num;
extern crate plexus;
extern crate rand;

mod camera;
mod pipeline;
mod renderer;

use decorum::R32;
use nalgebra::{Matrix4, Point3, Scalar};
use glutin::{ContextBuilder, ControlFlow, Event, EventsLoop, GlWindow, WindowBuilder, WindowEvent};
use plexus::buffer::MeshBuffer;
use plexus::generate::sphere::UVSphere;
use plexus::geometry::{Attribute, Geometry};
use plexus::graph::Mesh;
use plexus::prelude::*;

use camera::Camera;
use pipeline::{Color4, Transform, Vertex};
use renderer::{GlutinRenderer, Renderer};

impl<T> Attribute for Color4<T>
where
    T: Scalar,
{
}

struct FaceColorGeometry;

impl Geometry for FaceColorGeometry {
    type Vertex = Point3<f32>;
    type Edge = ();
    type Face = Color4<f32>;
}

fn new_mesh_buffer() -> MeshBuffer<u32, Vertex> {
    let mut mesh = UVSphere::<R32>::with_unit_radius(32, 32)
        .polygons_with_position()
        .map_vertices(|position| -> Point3<R32> { position.into() })
        .collect::<Mesh<FaceColorGeometry>>();
    for mut face in mesh.faces_mut() {
        face.geometry = Color4::random();
    }
    mesh.to_mesh_buffer_by_face_with(|face, vertex| Vertex::new(&vertex.geometry, &face.geometry))
        .unwrap()
}

fn new_camera(aspect: f32) -> Camera<f32> {
    let mut camera = Camera::new(aspect, 45.0, -1.0, 2.0);
    camera.look_at(&Point3::new(2.0, 1.0, 2.0), &Point3::origin());
    camera
}

fn new_renderer(width: u32, height: u32) -> (EventsLoop, Renderer<GlutinRenderer>) {
    let seat = EventsLoop::new();
    let window = GlWindow::new(
        WindowBuilder::new()
            .with_title("Plexus Viewer")
            .with_dimensions(width, height),
        ContextBuilder::new(),
        &seat,
    ).unwrap();
    (seat, Renderer::from_glutin_window(window))
}

fn main() {
    let (mut seat, mut renderer) = new_renderer(1024, 576);
    let mut camera = new_camera(1024.0 / 576.0);
    let mesh = new_mesh_buffer();
    seat.run_forever(|event| {
        match event {
            Event::WindowEvent {
                event: WindowEvent::Closed,
                ..
            } => {
                return ControlFlow::Break;
            }
            Event::WindowEvent {
                event: WindowEvent::Resized(width, height),
                ..
            } => {
                camera = new_camera(width as f32 / height as f32);
                renderer.update_frame_buffer_view();
            }
            _ => {}
        }
        renderer.clear();
        renderer
            .set_transform(&Transform::new(&camera.transform(), &Matrix4::identity()))
            .unwrap();
        renderer.draw_mesh_buffer(&mesh);
        renderer.flush().unwrap();
        ControlFlow::Continue
    });
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::peer_manager::PeerManagerError;
use failure::{err_msg, Backtrace, Context, Fail};
use futures::channel::mpsc;
use protobuf::error::ProtobufError;
use std::{
    fmt::{self, Display},
    io,
};
use tokio::timer;
use types::validator_verifier::VerifyError;

/// Errors propagated from the network module.
#[derive(Debug)]
pub struct NetworkError {
    inner: Context<NetworkErrorKind>,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum NetworkErrorKind {
    #[fail(display = "IO error")]
    IoError,

    #[fail(display = "Error parsing protobuf message")]
    ProtobufParseError,

    #[fail(display = "Invalid signature error")]
    SignatureError,

    #[fail(display = "Failed to parse multiaddrs")]
    MultiaddrError,

    #[fail(display = "Error sending on mpsc channel")]
    MpscSendError,

    #[fail(display = "Error setting timeout")]
    TimerError,

    #[fail(display = "Operation timed out")]
    TimedOut,

    #[fail(display = "Unknown tokio::timer Error variant")]
    UnknownTimerError,

    #[fail(display = "PeerManager error")]
    PeerManagerError,

    #[fail(display = "Parsing error")]
    ParsingError,

    #[fail(display = "Failed to connect to peer")]
    NotConnected,
}

impl Fail for NetworkError {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl Display for NetworkError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &self.inner)
    }
}

impl NetworkError {
    pub fn kind(&self) -> NetworkErrorKind {
        *self.inner.get_context()
    }
}

impl From<NetworkErrorKind> for NetworkError {
    fn from(kind: NetworkErrorKind) -> NetworkError {
        NetworkError {
            inner: Context::new(kind),
        }
    }
}

impl From<Context<NetworkErrorKind>> for NetworkError {
    fn from(inner: Context<NetworkErrorKind>) -> NetworkError {
        NetworkError { inner }
    }
}

impl From<io::Error> for NetworkError {
    fn from(err: io::Error) -> NetworkError {
        err.context(NetworkErrorKind::IoError).into()
    }
}

impl From<VerifyError> for NetworkError {
    fn from(err: VerifyError) -> NetworkError {
        err.context(NetworkErrorKind::SignatureError).into()
    }
}

impl From<ProtobufError> for NetworkError {
    fn from(err: ProtobufError) -> NetworkError {
        err.context(NetworkErrorKind::ProtobufParseError).into()
    }
}

impl From<parity_multiaddr::Error> for NetworkError {
    fn from(err: parity_multiaddr::Error) -> NetworkError {
        err.context(NetworkErrorKind::MultiaddrError).into()
    }
}

impl From<mpsc::SendError> for NetworkError {
    fn from(err: mpsc::SendError) -> NetworkError {
        err.context(NetworkErrorKind::MpscSendError).into()
    }
}

impl From<PeerManagerError> for NetworkError {
    fn from(err: PeerManagerError) -> NetworkError {
        match err {
            PeerManagerError::IoError(_) => err.context(NetworkErrorKind::IoError).into(),
            PeerManagerError::NotConnected(_) => err.context(NetworkErrorKind::NotConnected).into(),
            err => err.context(NetworkErrorKind::PeerManagerError).into(),
        }
    }
}

impl From<timer::timeout::Error<NetworkError>> for NetworkError {
    fn from(err: timer::timeout::Error<NetworkError>) -> NetworkError {
        if err.is_elapsed() {
            Context::new(NetworkErrorKind::TimedOut).into()
        } else if err.is_timer() {
            err.into_timer()
                .unwrap()
                .context(NetworkErrorKind::TimerError)
                .into()
        } else if err.is_inner() {
            err.into_inner().unwrap()
        } else {
            err_msg(err)
                .context(NetworkErrorKind::UnknownTimerError)
                .into()
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use failure::AsFail;

    // This test demos a causal error chain that can be created using the `context` method of `Fail`
    // types.
    #[test]
    fn causal_chain() {
        let base_error = ::failure::err_msg("First error");
        let first_level_error = base_error.context(NetworkErrorKind::TimedOut);
        let second_level_error = first_level_error.context(NetworkErrorKind::PeerManagerError);
        let network_error: NetworkError = second_level_error.into();
        // When called without RUST_BACKTRACE=1, the debug mode should print the following:
        // NetworkError { inner: ErrorMessage { msg: "First error" }
        // Operation timed out
        // PeerManager error }
        eprintln!("{:?}", network_error);
        // The display mode output is just the outermost error:
        // PeerManager error
        eprintln!("{}", network_error);
        // Alternatively, we can iterate over the individual failures in the causal chain to get
        // the following output:
        // Error: PeerManager error
        // Error: Operation timed out
        // Error: First error
        for e in network_error.as_fail().iter_chain() {
            eprintln!("Error: {}", e);
        }
    }
}
<commit_msg>[network] update error message to be more accurate<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::peer_manager::PeerManagerError;
use failure::{err_msg, Backtrace, Context, Fail};
use futures::channel::mpsc;
use protobuf::error::ProtobufError;
use std::{
    fmt::{self, Display},
    io,
};
use tokio::timer;
use types::validator_verifier::VerifyError;

/// Errors propagated from the network module.
#[derive(Debug)]
pub struct NetworkError {
    inner: Context<NetworkErrorKind>,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum NetworkErrorKind {
    #[fail(display = "IO error")]
    IoError,

    #[fail(display = "Error parsing protobuf message")]
    ProtobufParseError,

    #[fail(display = "Invalid signature error")]
    SignatureError,

    #[fail(display = "Failed to parse multiaddrs")]
    MultiaddrError,

    #[fail(display = "Error sending on mpsc channel")]
    MpscSendError,

    #[fail(display = "Error setting timeout")]
    TimerError,

    #[fail(display = "Operation timed out")]
    TimedOut,

    #[fail(display = "Unknown tokio::timer Error variant")]
    UnknownTimerError,

    #[fail(display = "PeerManager error")]
    PeerManagerError,

    #[fail(display = "Parsing error")]
    ParsingError,

    #[fail(display = "Peer not connected")]
    NotConnected,
}

impl Fail for NetworkError {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl Display for NetworkError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", &self.inner)
    }
}

impl NetworkError {
    pub fn kind(&self) -> NetworkErrorKind {
        *self.inner.get_context()
    }
}

impl From<NetworkErrorKind> for NetworkError {
    fn from(kind: NetworkErrorKind) -> NetworkError {
        NetworkError {
            inner: Context::new(kind),
        }
    }
}

impl From<Context<NetworkErrorKind>> for NetworkError {
    fn from(inner: Context<NetworkErrorKind>) -> NetworkError {
        NetworkError { inner }
    }
}

impl From<io::Error> for NetworkError {
    fn from(err: io::Error) -> NetworkError {
        err.context(NetworkErrorKind::IoError).into()
    }
}

impl From<VerifyError> for NetworkError {
    fn from(err: VerifyError) -> NetworkError {
        err.context(NetworkErrorKind::SignatureError).into()
    }
}

impl From<ProtobufError> for NetworkError {
    fn from(err: ProtobufError) -> NetworkError {
        err.context(NetworkErrorKind::ProtobufParseError).into()
    }
}

impl From<parity_multiaddr::Error> for NetworkError {
    fn from(err: parity_multiaddr::Error) -> NetworkError {
        err.context(NetworkErrorKind::MultiaddrError).into()
    }
}

impl From<mpsc::SendError> for NetworkError {
    fn from(err: mpsc::SendError) -> NetworkError {
        err.context(NetworkErrorKind::MpscSendError).into()
    }
}

impl From<PeerManagerError> for NetworkError {
    fn from(err: PeerManagerError) -> NetworkError {
        match err {
            PeerManagerError::IoError(_) => err.context(NetworkErrorKind::IoError).into(),
            PeerManagerError::NotConnected(_) => err.context(NetworkErrorKind::NotConnected).into(),
            err => err.context(NetworkErrorKind::PeerManagerError).into(),
        }
    }
}

impl From<timer::timeout::Error<NetworkError>> for NetworkError {
    fn from(err: timer::timeout::Error<NetworkError>) -> NetworkError {
        if err.is_elapsed() {
            Context::new(NetworkErrorKind::TimedOut).into()
        } else if err.is_timer() {
            err.into_timer()
                .unwrap()
                .context(NetworkErrorKind::TimerError)
                .into()
        } else if err.is_inner() {
            err.into_inner().unwrap()
        } else {
            err_msg(err)
                .context(NetworkErrorKind::UnknownTimerError)
                .into()
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use failure::AsFail;

    // This test demos a causal error chain that can be created using the `context` method of `Fail`
    // types.
    #[test]
    fn causal_chain() {
        let base_error = ::failure::err_msg("First error");
        let first_level_error = base_error.context(NetworkErrorKind::TimedOut);
        let second_level_error = first_level_error.context(NetworkErrorKind::PeerManagerError);
        let network_error: NetworkError = second_level_error.into();
        // When called without RUST_BACKTRACE=1, the debug mode should print the following:
        // NetworkError { inner: ErrorMessage { msg: "First error" }
        // Operation timed out
        // PeerManager error }
        eprintln!("{:?}", network_error);
        // The display mode output is just the outermost error:
        // PeerManager error
        eprintln!("{}", network_error);
        // Alternatively, we can iterate over the individual failures in the causal chain to get
        // the following output:
        // Error: PeerManager error
        // Error: Operation timed out
        // Error: First error
        for e in network_error.as_fail().iter_chain() {
            eprintln!("Error: {}", e);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use Diagnostic;
use DiagnosticStyledString;

use Level;
use Handler;
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
use syntax_pos::{MultiSpan, Span};

/// Used for emitting structured error messages and other diagnostic information.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a> {
    handler: &'a Handler,
    diagnostic: Diagnostic,
}

/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way.  *However,* many of the methods are intended to
/// be used in a chained way, and hence ought to return `self`. In
/// that case, we can't just naively forward to the method on the
/// `diagnostic`, because the return type would be a `&Diagnostic`
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
/// it easy to declare such methods on the builder.
macro_rules! forward {
    // Forward pattern for &self -> &Self
    (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => {
        pub fn $n(&self, $($name: $ty),*) -> &Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self
    (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
        pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
    // type parameter. No obvious way to make this more generic.
    (pub fn $n:ident<S: Into<MultiSpan>>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
        pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };
}

impl<'a> Deref for DiagnosticBuilder<'a> {
    type Target = Diagnostic;

    fn deref(&self) -> &Diagnostic {
        &self.diagnostic
    }
}

impl<'a> DerefMut for DiagnosticBuilder<'a> {
    fn deref_mut(&mut self) -> &mut Diagnostic {
        &mut self.diagnostic
    }
}

impl<'a> DiagnosticBuilder<'a> {
    /// Emit the diagnostic.
    pub fn emit(&mut self) {
        if self.cancelled() {
            return;
        }

        match self.level {
            Level::Bug |
            Level::Fatal |
            Level::PhaseFatal |
            Level::Error => {
                self.handler.bump_err_count();
            }

            Level::Warning |
            Level::Note |
            Level::Help |
            Level::Cancelled => {
            }
        }

        self.handler.emitter.borrow_mut().emit(&self);
        self.cancel();
        self.handler.panic_if_treat_err_as_bug();

        // if self.is_fatal() {
        //     panic!(FatalError);
        // }
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.diagnostic.span_label(span, label);
        self
    }

    forward!(pub fn note_expected_found(&mut self,
                                        label: &fmt::Display,
                                        expected: DiagnosticStyledString,
                                        found: DiagnosticStyledString)
                                        -> &mut Self);

    forward!(pub fn note_expected_found_extra(&mut self,
                                              label: &fmt::Display,
                                              expected: DiagnosticStyledString,
                                              found: DiagnosticStyledString,
                                              expected_extra: &fmt::Display,
                                              found_extra: &fmt::Display)
                                              -> &mut Self);

    forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                                  sp: S,
                                                  msg: &str)
                                                  -> &mut Self);
    forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
    forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
    forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                                  sp: S,
                                                  msg: &str)
                                                  -> &mut Self);
    forward!(pub fn span_suggestion(&mut self,
                                    sp: Span,
                                    msg: &str,
                                    suggestion: String)
                                    -> &mut Self);
    forward!(pub fn span_suggestions(&mut self,
                                     sp: Span,
                                     msg: &str,
                                     suggestions: Vec<String>)
                                     -> &mut Self);
    forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
    forward!(pub fn code(&mut self, s: String) -> &mut Self);

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
        DiagnosticBuilder::new_with_code(handler, level, None, message)
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    pub fn new_with_code(handler: &'a Handler,
                         level: Level,
                         code: Option<String>,
                         message: &str)
                         -> DiagnosticBuilder<'a> {
        DiagnosticBuilder {
            handler: handler,
            diagnostic: Diagnostic::new_with_code(level, code, message)
        }
    }

    pub fn into_diagnostic(mut self) -> Diagnostic {
        // annoyingly, the Drop impl means we can't actually move
        let result = self.diagnostic.clone();
        self.cancel();
        result
    }
}

impl<'a> Debug for DiagnosticBuilder<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.diagnostic.fmt(f)
    }
}

/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
/// we emit a bug.
impl<'a> Drop for DiagnosticBuilder<'a> {
    fn drop(&mut self) {
        if !panicking() && !self.cancelled() {
            let mut db = DiagnosticBuilder::new(self.handler,
                                                Level::Bug,
                                                "Error constructed but not emitted");
            db.emit();
            panic!();
        }
    }
}

<commit_msg>Rollup merge of #41942 - tommyip:master, r=Mark-Simulacrum<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use Diagnostic;
use DiagnosticStyledString;

use Level;
use Handler;
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
use syntax_pos::{MultiSpan, Span};

/// Used for emitting structured error messages and other diagnostic information.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a> {
    handler: &'a Handler,
    diagnostic: Diagnostic,
}

/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way.  *However,* many of the methods are intended to
/// be used in a chained way, and hence ought to return `self`. In
/// that case, we can't just naively forward to the method on the
/// `diagnostic`, because the return type would be a `&Diagnostic`
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
/// it easy to declare such methods on the builder.
macro_rules! forward {
    // Forward pattern for &self -> &Self
    (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => {
        pub fn $n(&self, $($name: $ty),*) -> &Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self
    (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
        pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
    // type parameter. No obvious way to make this more generic.
    (pub fn $n:ident<S: Into<MultiSpan>>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
        pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };
}

impl<'a> Deref for DiagnosticBuilder<'a> {
    type Target = Diagnostic;

    fn deref(&self) -> &Diagnostic {
        &self.diagnostic
    }
}

impl<'a> DerefMut for DiagnosticBuilder<'a> {
    fn deref_mut(&mut self) -> &mut Diagnostic {
        &mut self.diagnostic
    }
}

impl<'a> DiagnosticBuilder<'a> {
    /// Emit the diagnostic.
    pub fn emit(&mut self) {
        if self.cancelled() {
            return;
        }

        match self.level {
            Level::Bug |
            Level::Fatal |
            Level::PhaseFatal |
            Level::Error => {
                self.handler.bump_err_count();
            }

            Level::Warning |
            Level::Note |
            Level::Help |
            Level::Cancelled => {
            }
        }

        self.handler.emitter.borrow_mut().emit(&self);
        self.cancel();

        if self.level == Level::Error {
            self.handler.panic_if_treat_err_as_bug();
        }

        // if self.is_fatal() {
        //     panic!(FatalError);
        // }
    }

    /// Add a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
        self.diagnostic.span_label(span, label);
        self
    }

    forward!(pub fn note_expected_found(&mut self,
                                        label: &fmt::Display,
                                        expected: DiagnosticStyledString,
                                        found: DiagnosticStyledString)
                                        -> &mut Self);

    forward!(pub fn note_expected_found_extra(&mut self,
                                              label: &fmt::Display,
                                              expected: DiagnosticStyledString,
                                              found: DiagnosticStyledString,
                                              expected_extra: &fmt::Display,
                                              found_extra: &fmt::Display)
                                              -> &mut Self);

    forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                                  sp: S,
                                                  msg: &str)
                                                  -> &mut Self);
    forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
    forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
    forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
                                                  sp: S,
                                                  msg: &str)
                                                  -> &mut Self);
    forward!(pub fn span_suggestion(&mut self,
                                    sp: Span,
                                    msg: &str,
                                    suggestion: String)
                                    -> &mut Self);
    forward!(pub fn span_suggestions(&mut self,
                                     sp: Span,
                                     msg: &str,
                                     suggestions: Vec<String>)
                                     -> &mut Self);
    forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
    forward!(pub fn code(&mut self, s: String) -> &mut Self);

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
        DiagnosticBuilder::new_with_code(handler, level, None, message)
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    pub fn new_with_code(handler: &'a Handler,
                         level: Level,
                         code: Option<String>,
                         message: &str)
                         -> DiagnosticBuilder<'a> {
        DiagnosticBuilder {
            handler: handler,
            diagnostic: Diagnostic::new_with_code(level, code, message)
        }
    }

    pub fn into_diagnostic(mut self) -> Diagnostic {
        // annoyingly, the Drop impl means we can't actually move
        let result = self.diagnostic.clone();
        self.cancel();
        result
    }
}

impl<'a> Debug for DiagnosticBuilder<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.diagnostic.fmt(f)
    }
}

/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
/// we emit a bug.
impl<'a> Drop for DiagnosticBuilder<'a> {
    fn drop(&mut self) {
        if !panicking() && !self.cancelled() {
            let mut db = DiagnosticBuilder::new(self.handler,
                                                Level::Bug,
                                                "Error constructed but not emitted");
            db.emit();
            panic!();
        }
    }
}

<|endoftext|>