<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;
use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --input=<pbf-file> --level=<admin-level>...

Options:
    -h, --help                               Show this message.
    -i <pbf-file>, --input=<pbf-file>        OSM PBF file.
    -l <admin-level>, --level=<admin-level>  Admin levels to keep.
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
    if admins.is_empty() {
        return;
    }
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => {
                    info!("adminstrative regione without coordinates for relation {}.",
                          relation.id);
                    continue;
                }
            };
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(ref l) if !levels.contains(&l) => continue,
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    info!("adminstrative regione without name for relation {}:  admin_level {} \
                           ignored .",
                          relation.id,
                          level);
                    continue;
                }
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn main() {
    env_logger::init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    let levels = args.flag_level.iter().cloned().collect();
    let mut res = administartive_regions(&args.flag_input, &levels);
    update_coordinates(&args.flag_input, &mut res);
}
<commit_msg>mimirsbrunn: corrections<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;
use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --input=<pbf-file> --level=<admin-level>...

Options:
    -h, --help                               Show this message.
    -i <pbf-file>, --input=<pbf-file>        OSM PBF file.
    -l <admin-level>, --level=<admin-level>  Admin levels to keep.
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
    if admins.is_empty() {
        return;
    }
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => {
                    info!("adminstrative regione without coordinates for relation {}.",
                          relation.id);
                    continue;
                }
            };
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(ref l) if !levels.contains(&l) => continue,
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    info!("adminstrative region without name for relation {}:  admin_level {} \
                           ignore .",
                          relation.id,
                          level);
                    continue;
                }
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn main() {
    env_logger::init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    let levels = args.flag_level.iter().cloned().collect();
    let mut res = administartive_regions(&args.flag_input, &levels);
    update_coordinates(&args.flag_input, &mut res);
}
<|endoftext|>


<commit_before>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            let mut besti = 0;
            let mut best = f64::MAX;
            for i in 0..num {
                p[i] = start + (i + 1) * ((end - start) / (num + 1));
                vp[i] = f(p[i]);
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<commit_msg>Extract a reused calculation that doesn't change<commit_after>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            let mut besti = 0;
            let mut best = f64::MAX;
            let multiplier = (end - start) / (num + 1);
            for i in 0..num {
                p[i] = start + (i + 1) * multiplier;
                vp[i] = f(p[i]);
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<|endoftext|>


<commit_before>use super::function;
use crate::{
    analysis::enums::Info,
    codegen::general::{
        self, cfg_deprecated, derives, version_condition, version_condition_no_doc,
        version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{enum_member_name, use_glib_if_needed, use_glib_type},
    traits::*,
    version::Version,
};
use std::{
    collections::HashSet,
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.enumerations.is_empty() {
        return;
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.enum_imports)?;
        writeln!(w)?;

        mod_rs.push("\nmod enums;".into());
        for enum_analysis in &env.analysis.enumerations {
            let config = &env.config.objects[&enum_analysis.full_name];
            let enum_ = enum_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::enums::{};", enum_.name));
            generate_enum(env, w, enum_, config, enum_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_enum(
    env: &Env,
    w: &mut dyn Write,
    enum_: &Enumeration,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        value: String,
        version: Option<Version>,
        deprecated_version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();
    let sys_crate_name = env.main_sys_crate_name();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if is_alias || !generate || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: enum_member_name(&member.name),
            c_name: member.c_identifier.clone(),
            value: member.value.clone(),
            version,
            deprecated_version,
        });
    }

    cfg_deprecated(w, env, enum_.deprecated_version, false, 0)?;
    version_condition(w, env, enum_.version, false, 0)?;
    if config.must_use {
        writeln!(w, "#[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    } else {
        writeln!(w, "#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]")?;
    }
    writeln!(w, "#[derive(Clone, Copy)]")?;
    writeln!(w, "#[non_exhaustive]")?;

    writeln!(w, "pub enum {} {{", enum_.name)?;
    for member in &members {
        cfg_deprecated(w, env, member.deprecated_version, false, 1)?;
        version_condition(w, env, member.version, false, 1)?;
        writeln!(w, "\t{},", member.name)?;
    }
    writeln!(
        w,
        "\
    #[doc(hidden)]
    __Unknown(i32),
}}"
    )?;

    let functions = analysis.functions();

    if !functions.is_empty() {
        writeln!(w)?;
        version_condition(w, env, enum_.version, false, 0)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in functions {
            function::generate(w, env, func_analysis, false, false, 1)?;
        }
        writeln!(w, "}}")?;
    }

    writeln!(w)?;

    if config.generate_display_trait {
        // Generate Display trait implementation.
        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl fmt::Display for {0} {{\n\
             \tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\twrite!(f, \"{0}::{{}}\", match *self {{",
            enum_.name
        )?;
        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\t{0}::{1} => \"{1}\",", enum_.name, member.name)?;
        }
        writeln!(
            w,
            "\t\t\t_ => \"Unknown\",\n\
             \t\t}})\n\
             \t}}\n\
             }}\n"
        )?;
    }

    // Generate ToGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn to_glib(&self) -> {sys_crate_name}::{ffi_name} {{
        match *self {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\t{}::{} => {}::{},",
            enum_.name, member.name, sys_crate_name, member.c_name
        )?;
    }
    writeln!(w, "\t\t\t{}::__Unknown(value) => value,", enum_.name)?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    // Generate FromGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    fn from_glib(value: {sys_crate_name}::{ffi_name}) -> Self {{
        {assert}match value {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\t{} => {}::{},",
            member.value, enum_.name, member.name
        )?;
    }
    writeln!(w, "\t\t\tvalue => {}::__Unknown(value),", enum_.name)?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    // Generate ErrorDomain trait implementation.
    if let Some(ref domain) = enum_.error_domain {
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> Quark {{
        {assert}",
            name = enum_.name,
            assert = assert
        )?;

        match domain {
            ErrorDomain::Quark(ref quark) => {
                writeln!(
                    w,
                    "        static QUARK: once_cell::sync::Lazy<{0}ffi::GQuark> = once_cell::sync::Lazy::new(|| unsafe {{
            {0}ffi::g_quark_from_static_string(b\"{1}\\0\".as_ptr() as *const _)
        }});
        from_glib(*QUARK)",
                    use_glib_if_needed(env, ""),
                    quark,
                )?;
            }
            ErrorDomain::Function(ref f) => {
                writeln!(
                    w,
                    "        unsafe {{ from_glib({sys_crate_name}::{get_quark}()) }}",
                    sys_crate_name = sys_crate_name,
                    get_quark = f
                )?;
            }
        }

        writeln!(
            w,
            "    }}

    fn code(self) -> i32 {{
        self.to_glib()
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            assert = assert
        )?;

        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(
                w,
                "\t\t\t{} => Some({}::{}),",
                member.value, enum_.name, member.name
            )?;
        }
        if has_failed_member {
            writeln!(w, "\t\t\t_ => Some({}::Failed),", enum_.name)?;
        } else {
            writeln!(w, "\t\t\tvalue => Some({}::__Unknown(value)),", enum_.name)?;
        }

        writeln!(
            w,
            "\
        }}
    }}
}}
"
        )?;
    }

    // Generate StaticType trait implementation.
    if let Some(ref get_type) = enum_.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(enum_.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = enum_.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValueOptional<'a> for {name} {{
    unsafe fn from_value_optional(value: &{gvalue}) -> Option<Self> {{
        Some(FromValue::from_value(value))
    }}
}}",
            name = enum_.name,
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValue<'a> for {name} {{
    unsafe fn from_value(value: &{gvalue}) -> Self {{
        from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_enum"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl SetValue for {name} {{
    unsafe fn set_value(value: &mut {gvalue}, this: &Self) {{
        {glib}(value.to_glib_none_mut().0, this.to_glib())
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_enum"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;
    }

    Ok(())
}
<commit_msg>codegen/enums: Add missing trait_impls::generate call<commit_after>use super::{function, trait_impls};
use crate::{
    analysis::enums::Info,
    codegen::general::{
        self, cfg_deprecated, derives, version_condition, version_condition_no_doc,
        version_condition_string,
    },
    config::gobjects::GObject,
    env::Env,
    file_saver,
    library::*,
    nameutil::{enum_member_name, use_glib_if_needed, use_glib_type},
    traits::*,
    version::Version,
};
use std::{
    collections::HashSet,
    io::{prelude::*, Result},
    path::Path,
};

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    if env.analysis.enumerations.is_empty() {
        return;
    }

    let path = root_path.join("enums.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &env.analysis.enum_imports)?;
        writeln!(w)?;

        mod_rs.push("\nmod enums;".into());
        for enum_analysis in &env.analysis.enumerations {
            let config = &env.config.objects[&enum_analysis.full_name];
            let enum_ = enum_analysis.type_(&env.library);

            if let Some(cfg) = version_condition_string(env, enum_.version, false, 0) {
                mod_rs.push(cfg);
            }
            mod_rs.push(format!("pub use self::enums::{};", enum_.name));
            generate_enum(env, w, enum_, config, enum_analysis)?;
        }

        Ok(())
    });
}

#[allow(clippy::write_literal)]
fn generate_enum(
    env: &Env,
    w: &mut dyn Write,
    enum_: &Enumeration,
    config: &GObject,
    analysis: &Info,
) -> Result<()> {
    struct Member {
        name: String,
        c_name: String,
        value: String,
        version: Option<Version>,
        deprecated_version: Option<Version>,
    }

    let mut members: Vec<Member> = Vec::new();
    let mut vals: HashSet<String> = HashSet::new();
    let sys_crate_name = env.main_sys_crate_name();

    for member in &enum_.members {
        let member_config = config.members.matched(&member.name);
        let is_alias = member_config.iter().any(|m| m.alias);
        let generate = member_config.iter().all(|m| m.status.need_generate());
        if is_alias || !generate || vals.contains(&member.value) {
            continue;
        }
        vals.insert(member.value.clone());
        let deprecated_version = member_config
            .iter()
            .filter_map(|m| m.deprecated_version)
            .next();
        let version = member_config.iter().filter_map(|m| m.version).next();
        members.push(Member {
            name: enum_member_name(&member.name),
            c_name: member.c_identifier.clone(),
            value: member.value.clone(),
            version,
            deprecated_version,
        });
    }

    cfg_deprecated(w, env, enum_.deprecated_version, false, 0)?;
    version_condition(w, env, enum_.version, false, 0)?;
    if config.must_use {
        writeln!(w, "#[must_use]")?;
    }

    if let Some(ref d) = config.derives {
        derives(w, &d, 1)?;
    } else {
        writeln!(w, "#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]")?;
    }
    writeln!(w, "#[derive(Clone, Copy)]")?;
    writeln!(w, "#[non_exhaustive]")?;

    writeln!(w, "pub enum {} {{", enum_.name)?;
    for member in &members {
        cfg_deprecated(w, env, member.deprecated_version, false, 1)?;
        version_condition(w, env, member.version, false, 1)?;
        writeln!(w, "\t{},", member.name)?;
    }
    writeln!(
        w,
        "\
    #[doc(hidden)]
    __Unknown(i32),
}}"
    )?;

    let functions = analysis.functions();

    if !functions.is_empty() {
        writeln!(w)?;
        version_condition(w, env, enum_.version, false, 0)?;
        write!(w, "impl {} {{", analysis.name)?;
        for func_analysis in functions {
            function::generate(w, env, func_analysis, false, false, 1)?;
        }
        writeln!(w, "}}")?;
    }

    trait_impls::generate(
        w,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        None,
    )?;

    writeln!(w)?;

    if config.generate_display_trait {
        // Generate Display trait implementation.
        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl fmt::Display for {0} {{\n\
             \tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
             \t\twrite!(f, \"{0}::{{}}\", match *self {{",
            enum_.name
        )?;
        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(w, "\t\t\t{0}::{1} => \"{1}\",", enum_.name, member.name)?;
        }
        writeln!(
            w,
            "\t\t\t_ => \"Unknown\",\n\
             \t\t}})\n\
             \t}}\n\
             }}\n"
        )?;
    }

    // Generate ToGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl ToGlib for {name} {{
    type GlibType = {sys_crate_name}::{ffi_name};

    fn to_glib(&self) -> {sys_crate_name}::{ffi_name} {{
        match *self {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\t{}::{} => {}::{},",
            enum_.name, member.name, sys_crate_name, member.c_name
        )?;
    }
    writeln!(w, "\t\t\t{}::__Unknown(value) => value,", enum_.name)?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    let assert = if env.config.generate_safety_asserts {
        "skip_assert_initialized!();\n\t\t"
    } else {
        ""
    };

    // Generate FromGlib trait implementation.
    version_condition(w, env, enum_.version, false, 0)?;
    writeln!(
        w,
        "#[doc(hidden)]
impl FromGlib<{sys_crate_name}::{ffi_name}> for {name} {{
    fn from_glib(value: {sys_crate_name}::{ffi_name}) -> Self {{
        {assert}match value {{",
        sys_crate_name = sys_crate_name,
        name = enum_.name,
        ffi_name = enum_.c_type,
        assert = assert
    )?;
    for member in &members {
        version_condition_no_doc(w, env, member.version, false, 3)?;
        writeln!(
            w,
            "\t\t\t{} => {}::{},",
            member.value, enum_.name, member.name
        )?;
    }
    writeln!(w, "\t\t\tvalue => {}::__Unknown(value),", enum_.name)?;
    writeln!(
        w,
        "\
        }}
    }}
}}
"
    )?;

    // Generate ErrorDomain trait implementation.
    if let Some(ref domain) = enum_.error_domain {
        let has_failed_member = members.iter().any(|m| m.name == "Failed");

        version_condition(w, env, enum_.version, false, 0)?;
        writeln!(
            w,
            "impl ErrorDomain for {name} {{
    fn domain() -> Quark {{
        {assert}",
            name = enum_.name,
            assert = assert
        )?;

        match domain {
            ErrorDomain::Quark(ref quark) => {
                writeln!(
                    w,
                    "        static QUARK: once_cell::sync::Lazy<{0}ffi::GQuark> = once_cell::sync::Lazy::new(|| unsafe {{
            {0}ffi::g_quark_from_static_string(b\"{1}\\0\".as_ptr() as *const _)
        }});
        from_glib(*QUARK)",
                    use_glib_if_needed(env, ""),
                    quark,
                )?;
            }
            ErrorDomain::Function(ref f) => {
                writeln!(
                    w,
                    "        unsafe {{ from_glib({sys_crate_name}::{get_quark}()) }}",
                    sys_crate_name = sys_crate_name,
                    get_quark = f
                )?;
            }
        }

        writeln!(
            w,
            "    }}

    fn code(self) -> i32 {{
        self.to_glib()
    }}

    fn from(code: i32) -> Option<Self> {{
        {assert}match code {{",
            assert = assert
        )?;

        for member in &members {
            version_condition_no_doc(w, env, member.version, false, 3)?;
            writeln!(
                w,
                "\t\t\t{} => Some({}::{}),",
                member.value, enum_.name, member.name
            )?;
        }
        if has_failed_member {
            writeln!(w, "\t\t\t_ => Some({}::Failed),", enum_.name)?;
        } else {
            writeln!(w, "\t\t\tvalue => Some({}::__Unknown(value)),", enum_.name)?;
        }

        writeln!(
            w,
            "\
        }}
    }}
}}
"
        )?;
    }

    // Generate StaticType trait implementation.
    if let Some(ref get_type) = enum_.glib_get_type {
        let configured_functions = config.functions.matched("get_type");
        let version = std::iter::once(enum_.version)
            .chain(configured_functions.iter().map(|f| f.version))
            .max()
            .flatten();

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl StaticType for {name} {{
    fn static_type() -> Type {{
        unsafe {{ from_glib({sys_crate_name}::{get_type}()) }}
    }}
}}",
            sys_crate_name = sys_crate_name,
            name = enum_.name,
            get_type = get_type
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValueOptional<'a> for {name} {{
    unsafe fn from_value_optional(value: &{gvalue}) -> Option<Self> {{
        Some(FromValue::from_value(value))
    }}
}}",
            name = enum_.name,
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl<'a> FromValue<'a> for {name} {{
    unsafe fn from_value(value: &{gvalue}) -> Self {{
        from_glib({glib}(value.to_glib_none().0))
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_get_enum"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;

        version_condition(w, env, version, false, 0)?;
        writeln!(
            w,
            "impl SetValue for {name} {{
    unsafe fn set_value(value: &mut {gvalue}, this: &Self) {{
        {glib}(value.to_glib_none_mut().0, this.to_glib())
    }}
}}",
            name = enum_.name,
            glib = use_glib_type(env, "gobject_ffi::g_value_set_enum"),
            gvalue = use_glib_type(env, "Value"),
        )?;
        writeln!(w)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use aes::block_cipher::generic_array::GenericArray;
use aes::{BlockCipher, NewBlockCipher};
use arrayvec::{Array, ArrayVec};
use std::io::Read;
use std::{any, fmt, io};

/// Internal block size of an AES cipher.
const AES_BLOCK_SIZE: usize = 16;

/// AES-128.
#[derive(Debug)]
pub struct Aes128;
/// AES-192
#[derive(Debug)]
pub struct Aes192;
/// AES-256.
#[derive(Debug)]
pub struct Aes256;

/// An AES cipher kind.
pub trait AesKind {
    /// Key type.
    type Key: Array<Item = u8>;
    /// Cipher used to decrypt.
    type Cipher;
}

impl AesKind for Aes256 {
    type Key = [u8; 32];

    type Cipher = aes::Aes256;
}

/// An AES-CTR key stream generator.
///
/// Implements the slightly non-standard AES-CTR variant used by WinZip AES encryption.
///
/// Typical AES-CTR implementations combine a nonce with a 64 bit counter. WinZIP AES instead uses
/// no nonce and also uses a different byte order (little endian) than NIST (big endian).
///
/// The stream implements the `Read` trait; encryption or decryption is performed by XOR-ing the
/// bytes from the key stream with the ciphertext/plaintext.
struct AesCtrZipKeyStream<C: AesKind> {
    counter: u128,
    cipher: C::Cipher,
    buffer: ArrayVec<C::Key>,
}

impl<C> fmt::Debug for AesCtrZipKeyStream<C>
where
    C: AesKind,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "AesCtrZipKeyStream<{}>(counter: {})",
            any::type_name::<C>(),
            self.counter
        )
    }
}

impl<C> AesCtrZipKeyStream<C>
where
    C: AesKind,
    C::Cipher: NewBlockCipher,
{
    #[allow(dead_code)]
    /// Creates a new zip variant AES-CTR key stream.
    pub fn new(key: &C::Key) -> AesCtrZipKeyStream<C> {
        AesCtrZipKeyStream {
            counter: 1,
            cipher: C::Cipher::new_varkey(key.as_slice()).expect("key should have correct size"),
            buffer: ArrayVec::new(),
        }
    }
}

impl<C> AesCtrZipKeyStream<C>
where
    C: AesKind,
    C::Cipher: BlockCipher,
{
    /// Decrypt or encrypt given data.
    #[inline]
    fn crypt(&mut self, mut target: &mut [u8]) {
        while target.len() > 0 {
            if self.buffer.len() == 0 {
                // Note: AES block size is always 16 bytes, same as u128.
                let mut block = GenericArray::clone_from_slice(&self.counter.to_le_bytes());

                // TODO: Use trait.
                self.cipher.encrypt_block(&mut block);
                self.counter += 1;
                self.buffer = block.into_iter().collect();
            }

            let target_len = target.len().min(self.buffer.len());

            xor(&mut target[0..target_len], &self.buffer[0..target_len]);
            self.buffer.drain(0..target_len);
            target = &mut target[target_len..];
        }
    }
}

/// XORs a slice in place with another slice.
#[inline]
pub fn xor(dest: &mut [u8], src: &[u8]) {
    debug_assert_eq!(dest.len(), src.len());

    for (lhs, rhs) in dest.iter_mut().zip(src.iter()) {
        *lhs ^= *rhs;
    }
}

#[cfg(test)]
mod tests {
    use super::{xor, Aes256, AesCtrZipKeyStream};
    use std::io::Read;

    #[test]
    fn crypt_simple_example() {
        let ciphertext: [u8; 5] = [0xdc, 0x99, 0x93, 0x5e, 0xbf];
        let expected_plaintext = &[b'a', b's', b'd', b'f', b'\n'];
        let key = [
            0xd1, 0x51, 0xa6, 0xab, 0x53, 0x68, 0xd7, 0xb7, 0xbf, 0x49, 0xf7, 0xf5, 0x8a, 0x4e,
            0x10, 0x36, 0x25, 0x1c, 0x13, 0xba, 0x12, 0x45, 0x37, 0x65, 0xa9, 0xe4, 0xed, 0x9f,
            0x4a, 0xa8, 0xda, 0x3b,
        ];

        let mut key_stream = AesCtrZipKeyStream::<Aes256>::new(&key);

        let mut plaintext = ciphertext;
        key_stream.crypt(&mut plaintext);
        assert_eq!(&plaintext, expected_plaintext);
    }
}
<commit_msg>Optimize AES code, use less copies<commit_after>use aes::block_cipher::generic_array::GenericArray;
use aes::{BlockCipher, NewBlockCipher};
use byteorder::WriteBytesExt;
use std::{any, fmt};

/// Internal block size of an AES cipher.
const AES_BLOCK_SIZE: usize = 16;

/// AES-128.
#[derive(Debug)]
pub struct Aes128;
/// AES-192
#[derive(Debug)]
pub struct Aes192;
/// AES-256.
#[derive(Debug)]
pub struct Aes256;

/// An AES cipher kind.
pub trait AesKind {
    /// Key type.
    type Key: AsRef<[u8]>;
    /// Cipher used to decrypt.
    type Cipher;
}

impl AesKind for Aes256 {
    type Key = [u8; 32];
    type Cipher = aes::Aes256;
}

/// An AES-CTR key stream generator.
///
/// Implements the slightly non-standard AES-CTR variant used by WinZip AES encryption.
///
/// Typical AES-CTR implementations combine a nonce with a 64 bit counter. WinZIP AES instead uses
/// no nonce and also uses a different byte order (little endian) than NIST (big endian).
///
/// The stream implements the `Read` trait; encryption or decryption is performed by XOR-ing the
/// bytes from the key stream with the ciphertext/plaintext.
pub struct AesCtrZipKeyStream<C: AesKind> {
    /// Current AES counter.
    counter: u128,
    /// AES cipher instance.
    cipher: C::Cipher,
    /// Stores the currently available keystream bytes.
    buffer: [u8; AES_BLOCK_SIZE],
    /// Number of bytes already used up from `buffer`.
    pos: usize,
}

impl<C> fmt::Debug for AesCtrZipKeyStream<C>
where
    C: AesKind,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "AesCtrZipKeyStream<{}>(counter: {})",
            any::type_name::<C>(),
            self.counter
        )
    }
}

impl<C> AesCtrZipKeyStream<C>
where
    C: AesKind,
    C::Cipher: NewBlockCipher,
{
    /// Creates a new zip variant AES-CTR key stream.
    pub fn new(key: &C::Key) -> AesCtrZipKeyStream<C> {
        AesCtrZipKeyStream {
            counter: 1,
            cipher: C::Cipher::new_varkey(key.as_ref()).expect("key should have correct size"),
            buffer: [0u8; AES_BLOCK_SIZE],
            pos: AES_BLOCK_SIZE,
        }
    }
}

impl<C> AesCtrZipKeyStream<C>
where
    C: AesKind,
    C::Cipher: BlockCipher,
{
    /// Decrypt or encrypt given data.
    #[inline]
    fn crypt(&mut self, mut target: &mut [u8]) {
        while target.len() > 0 {
            if self.pos == AES_BLOCK_SIZE {
                // Note: AES block size is always 16 bytes, same as u128.
                self.buffer
                    .as_mut()
                    .write_u128::<byteorder::LittleEndian>(self.counter)
                    .expect("did not expect u128 le conversion to fail");
                self.cipher
                    .encrypt_block(GenericArray::from_mut_slice(&mut self.buffer));
                self.counter += 1;
                self.pos = 0;
            }

            let target_len = target.len().min(AES_BLOCK_SIZE - self.pos);

            xor(
                &mut target[0..target_len],
                &self.buffer[self.pos..(self.pos + target_len)],
            );
            target = &mut target[target_len..];
            self.pos += target_len;
        }
    }
}

/// XORs a slice in place with another slice.
#[inline]
pub fn xor(dest: &mut [u8], src: &[u8]) {
    debug_assert_eq!(dest.len(), src.len());

    for (lhs, rhs) in dest.iter_mut().zip(src.iter()) {
        *lhs ^= *rhs;
    }
}

#[cfg(test)]
mod tests {
    use super::{Aes256, AesCtrZipKeyStream};

    #[test]
    fn crypt_simple_example() {
        let ciphertext: [u8; 5] = [0xdc, 0x99, 0x93, 0x5e, 0xbf];
        let expected_plaintext = &[b'a', b's', b'd', b'f', b'\n'];
        let key = [
            0xd1, 0x51, 0xa6, 0xab, 0x53, 0x68, 0xd7, 0xb7, 0xbf, 0x49, 0xf7, 0xf5, 0x8a, 0x4e,
            0x10, 0x36, 0x25, 0x1c, 0x13, 0xba, 0x12, 0x45, 0x37, 0x65, 0xa9, 0xe4, 0xed, 0x9f,
            0x4a, 0xa8, 0xda, 0x3b,
        ];

        let mut key_stream = AesCtrZipKeyStream::<Aes256>::new(&key);

        let mut plaintext = ciphertext;
        key_stream.crypt(&mut plaintext);
        assert_eq!(&plaintext, expected_plaintext);

        // Round-tripping should yield the ciphertext again.
        let mut key_stream = AesCtrZipKeyStream::<Aes256>::new(&key);
        key_stream.crypt(&mut plaintext);
        assert_eq!(plaintext, ciphertext);
    }
}
<|endoftext|>


<commit_before>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat and must have the appropiate rights for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// API call which will unban previously kicked members in a supergroup or channel. The bot
    /// must be an administrator and must have the appropiate rights for this call to succeed.
    pub fn unban_chat_member(&self, chat_id: &i64, user_id: &i64) -> Result<bool> {
        debug!("Calling unban_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let path = ["unbanChatMember"];
        let params = [("chat_id", chat_id), ("user_id", user_id)];
        self.call(&path, &params)
    }

    /// API call which will export an invite link to a supergroup or channel. The bot must be an
    /// administrator and must have the the appropiate rights for this call to succeed.
    pub fn export_chat_invite_link(&self, chat_id: &i64) -> Result<String> {
        debug!("Calling export_chat_invite_link...");
        let chat_id: &str = &chat_id.to_string();
        let path = ["exportChatInviteLink"];
        let params = [("chat_id", chat_id)];
        self.call(&path, &params)
    }

    /// The actual networking done for making API calls.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<commit_msg>Adding delete_chat_photo method<commit_after>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat and must have the appropiate rights for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// API call which will unban previously kicked members in a supergroup or channel. The bot
    /// must be an administrator and must have the appropiate rights for this call to succeed.
    pub fn unban_chat_member(&self, chat_id: &i64, user_id: &i64) -> Result<bool> {
        debug!("Calling unban_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let path = ["unbanChatMember"];
        let params = [("chat_id", chat_id), ("user_id", user_id)];
        self.call(&path, &params)
    }

    /// API call which will export an invite link to a supergroup or channel. The bot must be an
    /// administrator and must have the the appropiate rights for this call to succeed.
    pub fn export_chat_invite_link(&self, chat_id: &i64) -> Result<String> {
        debug!("Calling export_chat_invite_link...");
        let chat_id: &str = &chat_id.to_string();
        let path = ["exportChatInviteLink"];
        let params = [("chat_id", chat_id)];
        self.call(&path, &params)
    }

    /// API call which will delete a chat photo. Photos can't be changed for private chats. The bot
    /// must be an administrator and must have the appropiate rights for this call to succeed.
    pub fn delete_chat_photo(&self, chat_id: &i64) -> Result<bool> {
        debug!("Calling delete_chat_photo");
        let chat_id: &str = &chat_id.to_string();
        let path = ["deleteChatPhoto"];
        let params = [("chat_id", chat_id)];
        self.call(&path, &params)
    }

    /// The actual networking done for making API calls.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<|endoftext|>


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

//!
//! # Hub
//!
//! A hub provides a way to connect components into a tree. Hubs don't store changes, but can be used with things like
//! `ComponentEndPoint` to make component results user accessible.
//!

use super::super::tree::*;
use super::component::*;
use super::bus_publisher::*;
use super::immediate_publisher::*;

///
///
///
pub struct Hub {
    ///
    /// Passes changes between components
    ///
    bus: TreeChangeBus,

    ///
    /// Components attached to this hub
    ///
    components: Vec<ComponentRef>
}

impl Hub {
    ///
    /// Creates a new hub
    ///
    pub fn new() -> Hub {
        Hub { bus: TreeChangeBus::new(), components: vec![] }
    }

    ///
    /// Returns a consumer that will read from a particular address relative to this hub
    ///
    pub fn read_from<T: ToTreeAddress>(&mut self, address: &T) -> ConsumerRef {
        unimplemented!();
    }

    ///
    /// Returns a publisher that will write to a particular address relative to this hub
    ///
    pub fn publish_to<T: ToTreeAddress>(&mut self, address: &T) -> PublisherRef {
        let publisher           = ImmediatePublisher::new();
        let mut consumer        = publisher.create_consumer();
        let mut bus_publisher   = self.bus.create_publisher();
        let target_address      = address.to_tree_address();

        consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let relative_change = change.relative_to(&target_address);

            if let Some(relative_change) = relative_change {
                bus_publisher.publish(relative_change);
            }
        }));

        publisher
    }

    ///
    /// Attaches a component that reads from a particular address and publishes its results to another
    ///
    pub fn add_component<TComponent: ConvertToComponent, TFrom: ToTreeAddress, TTo: ToTreeAddress>(&mut self, component: TComponent, read_from: &TFrom, publish_to: &TTo) {
        let consumer    = self.read_from(read_from);
        let publisher   = self.publish_to(publish_to);

        self.components.push(component.into_component(consumer, publisher));
    }

    ///
    /// Pumps any messages waiting for this hub
    ///
    #[inline]
    pub fn pump(&mut self) {
        self.bus.pump();
    }

    ///
    /// Processes messages for this hub until there are no more to be processed
    ///
    #[inline]
    pub fn flush(&mut self) {
        self.bus.flush();
    }
}
<commit_msg>Update comments<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Hub
//!
//! A hub provides a way to connect components into a tree. Hubs don't store changes, but can be used with things like
//! `ComponentEndPoint` to make component results user accessible.
//!

use super::super::tree::*;
use super::component::*;
use super::bus_publisher::*;
use super::immediate_publisher::*;

///
///
///
pub struct Hub {
    ///
    /// Passes changes between components
    ///
    bus: TreeChangeBus,

    ///
    /// Components attached to this hub
    ///
    components: Vec<ComponentRef>
}

impl Hub {
    ///
    /// Creates a new hub
    ///
    pub fn new() -> Hub {
        Hub { bus: TreeChangeBus::new(), components: vec![] }
    }

    ///
    /// Returns a consumer that will read from a particular address relative to this hub
    ///
    pub fn read_from<T: ToTreeAddress>(&mut self, address: &T) -> ConsumerRef {
        unimplemented!();
    }

    ///
    /// Returns a publisher that will write to a particular address relative to this hub
    ///
    pub fn publish_to<T: ToTreeAddress>(&mut self, address: &T) -> PublisherRef {
        // We use an immediate publish to relay changes to the tree
        let publisher           = ImmediatePublisher::new();
        let mut consumer        = publisher.create_consumer();

        // Whenever the user publishes to the immediate publisher, generate a tree publish event
        let mut bus_publisher   = self.bus.create_publisher();
        let target_address      = address.to_tree_address();

        consumer.subscribe(TreeAddress::Here, TreeExtent::SubTree, Box::new(move |change| {
            let relative_change = change.relative_to(&target_address);

            if let Some(relative_change) = relative_change {
                bus_publisher.publish(relative_change);
            }
        }));

        publisher
    }

    ///
    /// Attaches a component that reads from a particular address and publishes its results to another
    ///
    pub fn add_component<TComponent: ConvertToComponent, TFrom: ToTreeAddress, TTo: ToTreeAddress>(&mut self, component: TComponent, read_from: &TFrom, publish_to: &TTo) {
        let consumer    = self.read_from(read_from);
        let publisher   = self.publish_to(publish_to);

        self.components.push(component.into_component(consumer, publisher));
    }

    ///
    /// Pumps any messages waiting for this hub
    ///
    #[inline]
    pub fn pump(&mut self) {
        self.bus.pump();
    }

    ///
    /// Processes messages for this hub until there are no more to be processed
    ///
    #[inline]
    pub fn flush(&mut self) {
        self.bus.flush();
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::str::Chars;

pub struct TokenIter<'a> {
    chars: Chars<'a>,
    term_buffer: String,
}

fn append_char_lowercase(c: char, term_buffer: &mut String) {
    for c_lower in c.to_lowercase() {
        term_buffer.push(c_lower);
    }
}

pub trait StreamingIterator<'a, T> {
    fn next(&'a mut self) -> Option<T>;
}

impl<'a, 'b> TokenIter<'b> {
    fn consume_token(&'a mut self) -> Option<&'a str> {
        loop {
            match self.chars.next() {
                Some(c) => {
                    if c.is_alphanumeric() {
                        append_char_lowercase(c, &mut self.term_buffer);
                    }
                    else {
                        break;
                    }
                },
                None => {
                    break;
                }
            }
        }
        return Some(&self.term_buffer);
    }
}

impl<'a, 'b> StreamingIterator<'a, &'a str> for TokenIter<'b> {

    fn next(&'a mut self,) -> Option<&'a str> {
        self.term_buffer.clear();
        // skipping non-letter characters.
        loop {
            match self.chars.next() {
                Some(c) => {
                    if c.is_alphanumeric() {
                        append_char_lowercase(c, &mut self.term_buffer);
                        return self.consume_token();
                    }
                }
                None => { return None; }
            }
        }
    }
}

pub struct SimpleTokenizer;

impl SimpleTokenizer {
    pub fn new() -> SimpleTokenizer {
        SimpleTokenizer
    }

    pub fn tokenize<'a>(&self, text: &'a str) -> TokenIter<'a> {
        TokenIter {
           term_buffer: String::new(),
           chars: text.chars(),
        }
   }
}

#[test]
fn test_tokenizer() {
    let simple_tokenizer = SimpleTokenizer::new();
    let mut term_reader = simple_tokenizer.tokenize("hello, happy tax payer!");
    assert_eq!(term_reader.next().unwrap(), "hello");
    assert_eq!(term_reader.next().unwrap(), "happy");
    assert_eq!(term_reader.next().unwrap(), "tax");
    assert_eq!(term_reader.next().unwrap(), "payer");
    assert_eq!(term_reader.next(), None);
}

#[test]
fn test_tokenizer_empty() {
    let simple_tokenizer = SimpleTokenizer::new();
    let mut term_reader = simple_tokenizer.tokenize("");
    assert_eq!(term_reader.next(), None);
}
<commit_msg>Using ascii lowercase for better perf.<commit_after>extern crate regex;

use std::str::Chars;
use std::ascii::AsciiExt;

pub struct TokenIter<'a> {
    chars: Chars<'a>,
    term_buffer: String,
}

fn append_char_lowercase(c: char, term_buffer: &mut String) {
    term_buffer.push(c.to_ascii_lowercase());
    // for c_lower in c.to_lowercase() {
    //     term_buffer.push(c_lower);
    // }
}

pub trait StreamingIterator<'a, T> {
    fn next(&'a mut self) -> Option<T>;
}

impl<'a, 'b> TokenIter<'b> {
    fn consume_token(&'a mut self) -> Option<&'a str> {
        loop {
            match self.chars.next() {
                Some(c) => {
                    if c.is_alphanumeric() {
                        append_char_lowercase(c, &mut self.term_buffer);
                    }
                    else {
                        break;
                    }
                },
                None => {
                    break;
                }
            }
        }
        return Some(&self.term_buffer);
    }
}

impl<'a, 'b> StreamingIterator<'a, &'a str> for TokenIter<'b> {

    fn next(&'a mut self,) -> Option<&'a str> {
        self.term_buffer.clear();
        // skipping non-letter characters.
        loop {
            match self.chars.next() {
                Some(c) => {
                    if c.is_alphanumeric() {
                        append_char_lowercase(c, &mut self.term_buffer);
                        return self.consume_token();
                    }
                }
                None => { return None; }
            }
        }
    }
}

pub struct SimpleTokenizer;

impl SimpleTokenizer {
    pub fn new() -> SimpleTokenizer {
        SimpleTokenizer
    }

    pub fn tokenize<'a>(&self, text: &'a str) -> TokenIter<'a> {
        TokenIter {
           term_buffer: String::new(),
           chars: text.chars(),
        }
   }
}

#[test]
fn test_tokenizer() {
    let simple_tokenizer = SimpleTokenizer::new();
    let mut term_reader = simple_tokenizer.tokenize("hello, happy tax payer!");
    assert_eq!(term_reader.next().unwrap(), "hello");
    assert_eq!(term_reader.next().unwrap(), "happy");
    assert_eq!(term_reader.next().unwrap(), "tax");
    assert_eq!(term_reader.next().unwrap(), "payer");
    assert_eq!(term_reader.next(), None);
}

#[test]
fn test_tokenizer_empty() {
    let simple_tokenizer = SimpleTokenizer::new();
    let mut term_reader = simple_tokenizer.tokenize("");
    assert_eq!(term_reader.next(), None);
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - Question: Why can't Rust ensure/infer/elide this scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<commit_msg>An exmaple of the static lifetime<commit_after>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// This cannot be elided because Rust doesn't know to use lifetime of "a" or "b".
fn double_first_five<'a>(a: &'a String, b: &'a String) -> (&'a str, &'a str) {
    (&a[..5], &b[..5])
}

// Output borrows generally must have an input value from which it can borrow. The exception is
// the static lifetime.
fn output_only<'a>() -> (&'static u8, &'static u8) {
    static X: u8 = 8;
    static Y: u8 = 9;

    (&X, &Y)
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_ages<'a, T: Iterator>(iters: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    iters.flat_map(|b| b.into_iter())
         .collect()
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let another = "Timothy".to_owned();
    let a = 43;
    let vec_ages = vec![vec![Age(90), Age(80)],
                        vec![Age(2)]];

    let arr_ages = vec![[Age(90), Age(80)],
                        [Age(2), Age(45)]];

    assert_eq!(output_only(), (&8, &9));

    assert_eq!(first_five(&name), "Andre");
    assert_eq!(double_first_five(&name, &another), ("Andre", "Timot"));

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_ages(vec_ages.iter()), vec![&Age(90), &Age(80), &Age(2)]);
    assert_eq!(join_ages(arr_ages.iter()), vec![&Age(90), &Age(80), &Age(2), &Age(45)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - When we say "'a", we are talking about a scope in the calling environment.
// - Question: Why can't Rust ensure/infer/elide the struct scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<|endoftext|>