<commit_before>//! Procedurally generating the game world.

use world::{Chunk, ChunkIndex, ChunkProvider, HeightType, HexPillar};
use world::{CHUNK_SIZE, GroundMaterial, PILLAR_STEP_HEIGHT, PillarSection, Prop, PropType};
use rand::Rand;
use gen::PlantGenerator;
use noise::{PermutationTable, open_simplex2, open_simplex3};
use gen::seeded_rng;

enum Biome {
    GrassLand,
    Desert,
    Snow,
    Forest,
    RainForest,
    Savanna,
    Stone,
    WeihnachtsmannLand,
}

/// Land "fill noise" scaling in x, y, and z direction.
const LAND_NOISE_SCALE: (f32, f32, f32) = (0.03, 0.03, 0.05);

/// Main type to generate the game world. Implements the `ChunkProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
    terrain_table: PermutationTable,
    plant_table: PermutationTable,
    temperature_table: PermutationTable,
    humidity_table: PermutationTable,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        let mut terrain_rng = seeded_rng(seed, 0, ());
        let mut plant_rng = seeded_rng(seed, 1, ());
        let mut temperature_rng = seeded_rng(seed, 2, ());
        let mut humidity_rng = seeded_rng(seed, 3, ());

        WorldGenerator {
            seed: seed,
            terrain_table: PermutationTable::rand(&mut terrain_rng),
            plant_table: PermutationTable::rand(&mut plant_rng),
            temperature_table: PermutationTable::rand(&mut temperature_rng),
            humidity_table: PermutationTable::rand(&mut humidity_rng),
        }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }

    fn biome_from_climate(temperature: f32, humidity: f32) -> Biome {
        match (temperature, humidity) {
            (0.0...0.2, 0.0...0.2) => Biome::Stone,
            (0.0...0.2, 0.2...0.4) => Biome::Snow,
            (0.0...0.2, 0.4...1.0) => Biome::Snow,
            (0.2...0.4, 0.0...0.2) => Biome::GrassLand,
            (0.2...0.4, 0.2...0.4) => Biome::GrassLand,
            (0.2...0.4, 0.4...1.0) => Biome::Forest,
            (0.4...1.0, 0.0...0.2) => Biome::Desert,
            (0.4...1.0, 0.2...0.4) => Biome::Savanna,
            (0.4...1.0, 0.4...1.0) => Biome::RainForest,
            _ => Biome::WeihnachtsmannLand,

        }
    }

    fn plant_threshold_from_biome(biome: &Biome) -> f32 {
        0.05 +
        match *biome {
            Biome::GrassLand => 0.3,
            Biome::Desert => 0.465,
            Biome::Snow => 0.3,
            Biome::Forest => 0.2,
            Biome::RainForest => 0.1,
            Biome::Savanna => 0.375,
            Biome::Stone => 0.45,
            Biome::WeihnachtsmannLand => 1.0,
        }
    }

    fn steepness_from_biome(biome: &Biome) -> f32 {
        match *biome {
            Biome::GrassLand => 40.0,
            Biome::Desert => 200.0,
            Biome::Snow => 30.0,
            Biome::Forest => 35.0,
            Biome::RainForest => 25.0,
            Biome::Savanna => 50.0,
            Biome::Stone => 15.0,
            Biome::WeihnachtsmannLand => 5.0,
        }
    }
}

impl ChunkProvider for WorldGenerator {
    fn load_chunk(&self, index: ChunkIndex) -> Option<Chunk> {
        const WORLDGEN_HEIGHT: usize = 256;
        // Create a 3D-Array of booleans indicating which pillar sections to fill
        // (Map height is unlimited in theory, but we'll limit worldgen to 64 height
        // units)
        let mut fill = [[[false; WORLDGEN_HEIGHT]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize];

        Some(Chunk::with_pillars(index, |pos| {

            let real_pos = pos.to_real();
            let x = real_pos.x;
            let y = real_pos.y;
            // Pillar pos relative to first pillar
            let rel_q = pos.q - index.0.q * CHUNK_SIZE as i32;
            let rel_r = pos.r - index.0.r * CHUNK_SIZE as i32;

            // noises
            let mut temperature_noise = (open_simplex2::<f32>(&self.temperature_table,
                                                              &[(x as f32) * 0.0015,
                                                                (y as f32) * 0.0015]) +
                                         0.6) / 2.0;
            temperature_noise += 0.05 *
                                 open_simplex2::<f32>(&self.temperature_table,
                                                      &[(x as f32) * 0.15, (y as f32) * 0.15]);

            let mut humidity_noise = (open_simplex2::<f32>(&self.humidity_table,
                                                           &[(x as f32) * 0.0015,
                                                             (y as f32) * 0.0015]) +
                                      0.6) / 2.0;
            humidity_noise += 0.05 *
                              open_simplex2::<f32>(&self.humidity_table,
                                                   &[(x as f32) * 0.15, (y as f32) * 0.15]);

            let current_biome = WorldGenerator::biome_from_climate(temperature_noise,
                                                                   humidity_noise);

            for i in 0..WORLDGEN_HEIGHT {
                if i == 0 {
                    fill[rel_q as usize][rel_r as usize][i as usize] = true;
                    continue;
                }

                let z = i as f32 * PILLAR_STEP_HEIGHT;
                let fill_noise = open_simplex3::<f32>(&self.terrain_table,
                                                      &[x * LAND_NOISE_SCALE.0,
                                                        y * LAND_NOISE_SCALE.1,
                                                        z * LAND_NOISE_SCALE.2]);

                // The noise is (theoretically) in the range -1..1
                // Map the noise to a range of 0..1
                let fill_noise = (fill_noise + 1.0) / 2.0;

                // Calculate threshold to fill this "block". The lower the threshold, the more
                // likely this voxel is filled, so it should increase with height.
                let height_pct = i as f32 / WORLDGEN_HEIGHT as f32;

                // The threshold is calculated using a sigmoid function. These are the
                // parameters used:

                /// Minimum threshold to prevent threshold to reach 0,
                /// needed to have any caves at all
                const MIN_THRESH: f32 = 0.6;
                /// Threshold at half value (max. steepness, avg. terrain
                /// height)
                const THRESH_MID: f32 = 0.5;

                // "Steepness" of the sigmoid function.
                let thresh_steepness: f32 = WorldGenerator::steepness_from_biome(&current_biome);

                let sig_thresh = 1.0 /
                                 (1.0 + f32::exp(-thresh_steepness * (height_pct - THRESH_MID)));

                let threshold = (sig_thresh + MIN_THRESH) / (1.0 + MIN_THRESH);

                fill[rel_q as usize][rel_r as usize][i as usize] = fill_noise > threshold;
            }

            let column = &fill[rel_q as usize][rel_r as usize];

            // Create sections for all connected `true`s in the array
            let mut sections = Vec::new();
            let mut low = 0;
            let mut height = None;
            for i in 0..WORLDGEN_HEIGHT {
                let material = match current_biome {
                    Biome::GrassLand => GroundMaterial::Grass,
                    Biome::Desert => GroundMaterial::Sand,
                    Biome::Snow => GroundMaterial::Snow,
                    Biome::Forest => GroundMaterial::Mulch,
                    Biome::RainForest => GroundMaterial::Jungle,
                    Biome::Savanna => GroundMaterial::Dirt,
                    Biome::Stone => GroundMaterial::Stone,
                    Biome::WeihnachtsmannLand => GroundMaterial::Color(1.0, 0.0, 0.0),
                };

                match (height, column[i]) {

                    (Some(h), true) => {
                        // Next one's still solid, increase section height
                        height = Some(h + 1);
                    }
                    (Some(h), false) => {
                        // Create a section of height `h` and start over
                        sections.push(PillarSection::new(material,
                                                         HeightType::from_units(low),
                                                         HeightType::from_units(low + h)));
                        height = None;
                    }
                    (None, true) => {
                        low = i as u16;
                        height = Some(1);
                    }
                    (None, false) => {}
                };
            }

            if let Some(h) = height {
                // Create the topmost pillar
                sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                 HeightType::from_units(low),
                                                 HeightType::from_units(low + h)));
            }

            let mut props = Vec::new();

            // plants
            let plant_noise = open_simplex2::<f32>(&self.plant_table,
                                                   &[(x as f32) * 0.25, (y as f32) * 0.25]);

            if plant_noise > 1.0 {
                // WorldGenerator::plant_threshold_from_biome(&current_biome) {
                let mut rng = super::seeded_rng(self.seed, "TREE", (pos.q, pos.r));
                let gen = PlantGenerator::rand(&mut rng);

                // put the tree at the highest position
                let height = match sections.last() {
                    Some(section) => section.top,
                    None => HeightType::from_units(0),
                };

                props.push(Prop {
                    baseline: height,
                    prop: PropType::Plant(gen.generate(&mut rng)),
                });
            }

            HexPillar::new(sections, props)
        }))
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        // All chunks can be generated from nothing
        true
    }
}
<commit_msg>do another little clean up<commit_after>//! Procedurally generating the game world.

use world::{Chunk, ChunkIndex, ChunkProvider, HeightType, HexPillar};
use world::{CHUNK_SIZE, GroundMaterial, PILLAR_STEP_HEIGHT, PillarSection, Prop, PropType};
use rand::Rand;
use gen::PlantGenerator;
use noise::{PermutationTable, open_simplex2, open_simplex3};
use gen::seeded_rng;

enum Biome {
    GrassLand,
    Desert,
    Snow,
    Forest,
    RainForest,
    Savanna,
    Stone,
    WeihnachtsmannLand,
}

/// Land "fill noise" scaling in x, y, and z direction.
const LAND_NOISE_SCALE: (f32, f32, f32) = (0.03, 0.03, 0.05);

/// Main type to generate the game world. Implements the `ChunkProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
    terrain_table: PermutationTable,
    plant_table: PermutationTable,
    temperature_table: PermutationTable,
    humidity_table: PermutationTable,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        let mut terrain_rng = seeded_rng(seed, 0, ());
        let mut plant_rng = seeded_rng(seed, 1, ());
        let mut temperature_rng = seeded_rng(seed, 2, ());
        let mut humidity_rng = seeded_rng(seed, 3, ());

        WorldGenerator {
            seed: seed,
            terrain_table: PermutationTable::rand(&mut terrain_rng),
            plant_table: PermutationTable::rand(&mut plant_rng),
            temperature_table: PermutationTable::rand(&mut temperature_rng),
            humidity_table: PermutationTable::rand(&mut humidity_rng),
        }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }

    fn biome_from_climate(temperature: f32, humidity: f32) -> Biome {
        match (temperature, humidity) {
            (0.0...0.2, 0.0...0.2) => Biome::Stone,
            (0.0...0.2, 0.2...0.4) => Biome::Snow,
            (0.0...0.2, 0.4...1.0) => Biome::Snow,
            (0.2...0.4, 0.0...0.2) => Biome::GrassLand,
            (0.2...0.4, 0.2...0.4) => Biome::GrassLand,
            (0.2...0.4, 0.4...1.0) => Biome::Forest,
            (0.4...1.0, 0.0...0.2) => Biome::Desert,
            (0.4...1.0, 0.2...0.4) => Biome::Savanna,
            (0.4...1.0, 0.4...1.0) => Biome::RainForest,
            _ => Biome::WeihnachtsmannLand,

        }
    }

    fn plant_threshold_from_biome(biome: &Biome) -> f32 {
        0.05 +
        match *biome {
            Biome::GrassLand => 0.3,
            Biome::Desert => 0.465,
            Biome::Snow => 0.3,
            Biome::Forest => 0.2,
            Biome::RainForest => 0.1,
            Biome::Savanna => 0.375,
            Biome::Stone => 0.45,
            Biome::WeihnachtsmannLand => 1.0,
        }
    }

    fn steepness_from_biome(biome: &Biome) -> f32 {
        match *biome {
            Biome::GrassLand => 40.0,
            Biome::Desert => 200.0,
            Biome::Snow => 30.0,
            Biome::Forest => 35.0,
            Biome::RainForest => 25.0,
            Biome::Savanna => 50.0,
            Biome::Stone => 15.0,
            Biome::WeihnachtsmannLand => 5.0,
        }
    }

    fn material_from_biome(biome: &Biome) -> GroundMaterial {
        match *biome {
            Biome::GrassLand => GroundMaterial::Grass,
            Biome::Desert => GroundMaterial::Sand,
            Biome::Snow => GroundMaterial::Snow,
            Biome::Forest => GroundMaterial::Mulch,
            Biome::RainForest => GroundMaterial::Jungle,
            Biome::Savanna => GroundMaterial::Dirt,
            Biome::Stone => GroundMaterial::Stone,
            Biome::WeihnachtsmannLand => GroundMaterial::Color(1.0, 0.0, 0.0),
        }
    }
}

impl ChunkProvider for WorldGenerator {
    fn load_chunk(&self, index: ChunkIndex) -> Option<Chunk> {
        const WORLDGEN_HEIGHT: usize = 256;
        // Create a 3D-Array of booleans indicating which pillar sections to fill
        // (Map height is unlimited in theory, but we'll limit worldgen to 64 height
        // units)
        let mut fill = [[[false; WORLDGEN_HEIGHT]; CHUNK_SIZE as usize]; CHUNK_SIZE as usize];

        Some(Chunk::with_pillars(index, |pos| {

            let real_pos = pos.to_real();
            let x = real_pos.x;
            let y = real_pos.y;
            // Pillar pos relative to first pillar
            let rel_q = pos.q - index.0.q * CHUNK_SIZE as i32;
            let rel_r = pos.r - index.0.r * CHUNK_SIZE as i32;

            // noises
            let mut temperature_noise = (open_simplex2::<f32>(&self.temperature_table,
                                                              &[(x as f32) * 0.0015,
                                                                (y as f32) * 0.0015]) +
                                         0.6) / 2.0;
            temperature_noise += 0.05 *
                                 open_simplex2::<f32>(&self.temperature_table,
                                                      &[(x as f32) * 0.15, (y as f32) * 0.15]);

            let mut humidity_noise = (open_simplex2::<f32>(&self.humidity_table,
                                                           &[(x as f32) * 0.0015,
                                                             (y as f32) * 0.0015]) +
                                      0.6) / 2.0;
            humidity_noise += 0.05 *
                              open_simplex2::<f32>(&self.humidity_table,
                                                   &[(x as f32) * 0.15, (y as f32) * 0.15]);

            let current_biome = WorldGenerator::biome_from_climate(temperature_noise,
                                                                   humidity_noise);

            for i in 0..WORLDGEN_HEIGHT {
                if i == 0 {
                    fill[rel_q as usize][rel_r as usize][i as usize] = true;
                    continue;
                }

                let z = i as f32 * PILLAR_STEP_HEIGHT;
                let fill_noise = open_simplex3::<f32>(&self.terrain_table,
                                                      &[x * LAND_NOISE_SCALE.0,
                                                        y * LAND_NOISE_SCALE.1,
                                                        z * LAND_NOISE_SCALE.2]);

                // The noise is (theoretically) in the range -1..1
                // Map the noise to a range of 0..1
                let fill_noise = (fill_noise + 1.0) / 2.0;

                // Calculate threshold to fill this "block". The lower the threshold, the more
                // likely this voxel is filled, so it should increase with height.
                let height_pct = i as f32 / WORLDGEN_HEIGHT as f32;

                // The threshold is calculated using a sigmoid function. These are the
                // parameters used:

                /// Minimum threshold to prevent threshold to reach 0,
                /// needed to have any caves at all
                const MIN_THRESH: f32 = 0.6;
                /// Threshold at half value (max. steepness, avg. terrain
                /// height)
                const THRESH_MID: f32 = 0.5;

                // "Steepness" of the sigmoid function.
                let thresh_steepness: f32 = WorldGenerator::steepness_from_biome(&current_biome);

                let sig_thresh = 1.0 /
                                 (1.0 + f32::exp(-thresh_steepness * (height_pct - THRESH_MID)));

                let threshold = (sig_thresh + MIN_THRESH) / (1.0 + MIN_THRESH);

                fill[rel_q as usize][rel_r as usize][i as usize] = fill_noise > threshold;
            }

            let column = &fill[rel_q as usize][rel_r as usize];

            // Create sections for all connected `true`s in the array
            let mut sections = Vec::new();
            let mut low = 0;
            let mut height = None;
            for i in 0..WORLDGEN_HEIGHT {
                let material = WorldGenerator::material_from_biome(&current_biome);

                match (height, column[i]) {

                    (Some(h), true) => {
                        // Next one's still solid, increase section height
                        height = Some(h + 1);
                    }
                    (Some(h), false) => {
                        // Create a section of height `h` and start over
                        sections.push(PillarSection::new(material,
                                                         HeightType::from_units(low),
                                                         HeightType::from_units(low + h)));
                        height = None;
                    }
                    (None, true) => {
                        low = i as u16;
                        height = Some(1);
                    }
                    (None, false) => {}
                };
            }

            if let Some(h) = height {
                // Create the topmost pillar
                sections.push(PillarSection::new(GroundMaterial::Dirt,
                                                 HeightType::from_units(low),
                                                 HeightType::from_units(low + h)));
            }

            let mut props = Vec::new();

            // plants
            let plant_noise = open_simplex2::<f32>(&self.plant_table,
                                                   &[(x as f32) * 0.25, (y as f32) * 0.25]);

            if plant_noise > 1.0 {
                // WorldGenerator::plant_threshold_from_biome(&current_biome) {
                let mut rng = super::seeded_rng(self.seed, "TREE", (pos.q, pos.r));
                let gen = PlantGenerator::rand(&mut rng);

                // put the tree at the highest position
                let height = match sections.last() {
                    Some(section) => section.top,
                    None => HeightType::from_units(0),
                };

                props.push(Prop {
                    baseline: height,
                    prop: PropType::Plant(gen.generate(&mut rng)),
                });
            }

            HexPillar::new(sections, props)
        }))
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        // All chunks can be generated from nothing
        true
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Player {
    A,
    B,
    C,
}

fn main() {
    loop {
        // randomly select player
        let player_number = rand::thread_rng().gen_range(0, 3);
        match player_number {
            0 => println!("player A:"),
            1 => println!("player B:"),
            2 => println!("player C:"),
            _ => break,
        }
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
    }
}
<commit_msg>Select player first (before entering the loop).<commit_after>extern crate rand;

use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Player {
    A,
    B,
    C,
}

fn main() {
    // randomly select player
    let player_number = rand::thread_rng().gen_range(0, 3);
    match player_number {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Uknown player {}", player_number),
    }
    loop {
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
    }
}
<|endoftext|>


<commit_before>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}
impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}
<commit_msg>Added starting point of Selection operator<commit_after>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use schema;
use buffer;

#[deriving(Show, Eq, Hash)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan<'a, 'b> {
	relation: schema::Relation,
	segment: &'a mut schema::SPSegment<'b>,
	current: uint,
}

impl<'a, 'b> TableScan<'a, 'b> {
	fn new(rel: schema::Relation, seg: &'a mut schema::SPSegment<'b>) -> TableScan<'a, 'b> {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl<'a, 'b> Operatorish<Vec<Register>> for TableScan<'a, 'b> {
}

impl<'a, 'b> Iterator<Vec<Register>> for TableScan<'a, 'b> {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let tup = self.relation.get(self.segment, self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			println!("res: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

enum Selectable {
	Varchar(~str),
	Integer,
}

struct Select<T> {
	input: T,
	selections: Vec<(uint, Selectable)>,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, select: Vec<(uint, Selectable)>) -> Select<T> {
		Select {
			input: input,
			selections: select,
		}
	}
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment {id: 1, manager: &mut manager};

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));

	{
		let mut ts = TableScan::new(relation.clone(), &mut seg);
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), &mut seg);
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}
<|endoftext|>


<commit_before>// FIXME: This is a huge hack to find the static version of the library
// instead of the shared. It looks in a very specific place that only has
// relevance to servo.
#[link_args = "../harfbuzz/src/.libs/libharfbuzz.a -lpango-1.0"]
#[no_link]
native mod m { }
<commit_msg>Mac has different linking needs<commit_after>// FIXME: This is a huge hack to find the static version of the library
// instead of the shared. It looks in a very specific place that only has
// relevance to servo.

#[cfg(target_os = "linux")]
#[link_args = "../harfbuzz/src/.libs/libharfbuzz.a -lpango-1.0"]
#[no_link]
native mod m { }

#[cfg(target_os = "macos")]
#[link_args = "../harfbuzz/src/.libs/libharfbuzz.a -lstdc++"]
#[no_link]
native mod m { }
<|endoftext|>


<commit_before>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::MAX as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # use std::convert::TryFrom;
    /// # let foo = 1;
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr<'_>) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.kind;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if let Some(cv) = result {
            if let Some(to_type) = cv.to_type {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()", to_type, snippet),
                    applicability,
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr<'a>,
    to_type: Option<&'a str>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr<'_>) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    #[must_use]
    fn try_new(from: &str, to: &str) -> Option<Self> {
        if UINTS.contains(&from) {
            Some(Self::FromUnsigned)
        } else if SINTS.contains(&from) {
            if UINTS.contains(&to) {
                Some(Self::SignedToUnsigned)
            } else if SINTS.contains(&to) {
                Some(Self::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::MAX as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");

         then {
             Conversion::try_new(candidate, from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::MIN as from_type)`
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.kind;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::MIN as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") {
        Conversion::try_new(candidate, from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast<'a>(
    expr: &'a Expr<'_>,
    types: &'a [&str],
    func: &'a str,
    assoc_const: &'a str,
) -> Option<(&'a str, &'a str)> {
    // `to_type::max_value() as from_type`
    // or `to_type::MAX as from_type`
    let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
        // to_type::max_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
        if let TyKind::Path(ref from_type_path) = &from_type.kind;
        if let Some(from_sym) = int_ty_to_sym(from_type_path);

        then {
            Some((limit, from_sym))
        } else {
            None
        }
    };

    // `from_type::from(to_type::max_value())`
    let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::max_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
            // `to_type::max_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.kind;
            if let Some(from_sym) = get_implementing_type(path, INTS, "from");

            then {
                Some((limit, from_sym))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        match limit.kind {
            // `from_type::from(_)`
            ExprKind::Call(path, _) => {
                if let ExprKind::Path(ref path) = path.kind {
                    // `to_type`
                    if let Some(to_type) = get_implementing_type(path, types, func) {
                        return Some((from_type, to_type));
                    }
                }
            },
            // `to_type::MAX`
            ExprKind::Path(ref path) => {
                if let Some(to_type) = get_implementing_type(path, types, assoc_const) {
                    return Some((from_type, to_type));
                }
            },
            _ => {},
        }
    };
    None
}

/// Gets the type which implements the called function
fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name.as_str() == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind;
        if let [int] = &*tp.segments;
        let name = &int.ident.name.as_str();

        then {
            candidates.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;
        let name = &ty.ident.name.as_str();

        then {
            INTS.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

// Constants
const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
<commit_msg>Stabilize Option::zip<commit_after>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::MAX as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # use std::convert::TryFrom;
    /// # let foo = 1;
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr<'_>) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.kind;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if let Some(cv) = result {
            if let Some(to_type) = cv.to_type {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()", to_type, snippet),
                    applicability,
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr<'_>, right: &'a Expr<'_>) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        upper.zip(lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr<'a>,
    to_type: Option<&'a str>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        match (self.to_type, other.to_type) {
            (Some(l), Some(r)) => l == r,
            _ => true,
        }
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr<'_>) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    #[must_use]
    fn try_new(from: &str, to: &str) -> Option<Self> {
        if UINTS.contains(&from) {
            Some(Self::FromUnsigned)
        } else if SINTS.contains(&from) {
            if UINTS.contains(&to) {
                Some(Self::SignedToUnsigned)
            } else if SINTS.contains(&to) {
                Some(Self::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::MAX as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");

         then {
             Conversion::try_new(candidate, from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::MIN as from_type)`
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
    fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.kind;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::MIN as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") {
        Conversion::try_new(candidate, from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast<'a>(
    expr: &'a Expr<'_>,
    types: &'a [&str],
    func: &'a str,
    assoc_const: &'a str,
) -> Option<(&'a str, &'a str)> {
    // `to_type::max_value() as from_type`
    // or `to_type::MAX as from_type`
    let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
        // to_type::max_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
        if let TyKind::Path(ref from_type_path) = &from_type.kind;
        if let Some(from_sym) = int_ty_to_sym(from_type_path);

        then {
            Some((limit, from_sym))
        } else {
            None
        }
    };

    // `from_type::from(to_type::max_value())`
    let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::max_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
            // `to_type::max_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.kind;
            if let Some(from_sym) = get_implementing_type(path, INTS, "from");

            then {
                Some((limit, from_sym))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        match limit.kind {
            // `from_type::from(_)`
            ExprKind::Call(path, _) => {
                if let ExprKind::Path(ref path) = path.kind {
                    // `to_type`
                    if let Some(to_type) = get_implementing_type(path, types, func) {
                        return Some((from_type, to_type));
                    }
                }
            },
            // `to_type::MAX`
            ExprKind::Path(ref path) => {
                if let Some(to_type) = get_implementing_type(path, types, assoc_const) {
                    return Some((from_type, to_type));
                }
            },
            _ => {},
        }
    };
    None
}

/// Gets the type which implements the called function
fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name.as_str() == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.kind;
        if let [int] = &*tp.segments;
        let name = &int.ident.name.as_str();

        then {
            candidates.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;
        let name = &ty.ident.name.as_str();

        then {
            INTS.iter().find(|c| name == *c).cloned()
        } else {
            None
        }
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

// Constants
const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;

use super::FILTER_NEXT;

/// lint use of `filter().next()` for `Iterators`
pub(super) fn check<'tcx>(
    cx: &LateContext<'tcx>,
    expr: &'tcx hir::Expr<'_>,
    recv: &'tcx hir::Expr<'_>,
    filter_arg: &'tcx hir::Expr<'_>,
) {
    // lint if caller of `.filter().next()` is an Iterator
    if is_trait_method(cx, expr, sym::Iterator) {
        let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                   `.find(..)` instead";
        let filter_snippet = snippet(cx, filter_arg.span, "..");
        if filter_snippet.lines().count() <= 1 {
            let iter_snippet = snippet(cx, recv.span, "..");
            // add note if not multi-line
            span_lint_and_sugg(
                cx,
                FILTER_NEXT,
                expr.span,
                msg,
                "try this",
                format!("{}.find({})", iter_snippet, filter_snippet),
                Applicability::MachineApplicable,
            );
        } else {
            span_lint(cx, FILTER_NEXT, expr.span, msg);
        }
    }
}
<commit_msg>Fix false positive on `filter_next`<commit_after>use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::snippet;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;

use super::FILTER_NEXT;

/// lint use of `filter().next()` for `Iterators`
pub(super) fn check<'tcx>(
    cx: &LateContext<'tcx>,
    expr: &'tcx hir::Expr<'_>,
    recv: &'tcx hir::Expr<'_>,
    filter_arg: &'tcx hir::Expr<'_>,
) {
    // lint if caller of `.filter().next()` is an Iterator
    let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
        implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[])
    });
    if recv_impls_iterator {
        let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                   `.find(..)` instead";
        let filter_snippet = snippet(cx, filter_arg.span, "..");
        if filter_snippet.lines().count() <= 1 {
            let iter_snippet = snippet(cx, recv.span, "..");
            // add note if not multi-line
            span_lint_and_sugg(
                cx,
                FILTER_NEXT,
                expr.span,
                msg,
                "try this",
                format!("{}.find({})", iter_snippet, filter_snippet),
                Applicability::MachineApplicable,
            );
        } else {
            span_lint(cx, FILTER_NEXT, expr.span, msg);
        }
    }
}
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use std::convert::TryFrom as _;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);
    match Api::try_from(raw_api) {
        Ok(api) => api.into_token_stream().into(),
        Err(err) => err.to_compile_error().into(),
    }
}
<commit_msg>Update ruma_api! docs<commit_after>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use std::convert::TryFrom as _;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```rust
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
/// *   `#[ruma_api(query_map)]`: Instead of individual query fields, one query_map field, of any
///     type that implements `IntoIterator<Item = (String, String)>` (e.g.
///     `HashMap<String, String>`, can be used for cases where an endpoint supports arbitrary query
///     parameters.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);
    match Api::try_from(raw_api) {
        Ok(api) => api.into_token_stream().into(),
        Err(err) => err.to_compile_error().into(),
    }
}
<|endoftext|>


<commit_before>use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::fmt::{LowerHex, Debug};

use scroll::{self, Pread};
use scroll::ctx::TryFromCtx;
use error;

use pe::section_table;
use pe::utils;
use pe::data_directories;

pub const IMPORT_BY_ORDINAL_32: u32 = 0x8000_0000;
pub const IMPORT_BY_ORDINAL_64: u64 = 0x8000_0000_0000_0000;
pub const IMPORT_RVA_MASK_32: u32 = 0x8fff_ffff;
pub const IMPORT_RVA_MASK_64: u64 = 0x0000_0000_8fff_ffff;

pub trait Bitfield<'a>: PartialEq + Eq + LowerHex + Debug + TryFromCtx<'a, scroll::Endian, Error=scroll::Error, Size=usize> {
    fn is_ordinal(&self) -> bool;
    fn to_ordinal(&self) -> u16;
    fn to_rva(&self) -> u32;
    fn size_of() -> usize;
    fn is_zero(&self) -> bool;
    fn vec_to_import_address_table(Vec<Self>) -> ImportAddressTable;
}

impl<'a> Bitfield<'a> for u64 {
    fn is_ordinal(&self) -> bool { self & IMPORT_BY_ORDINAL_64 == IMPORT_BY_ORDINAL_64 }
    fn to_ordinal(&self) -> u16 { (0xffff & self) as u16 }
    fn to_rva(&self) -> u32 { (self & IMPORT_RVA_MASK_64) as u32 }
    fn size_of() -> usize { 8 }
    fn is_zero(&self) -> bool { *self == 0 }
    fn vec_to_import_address_table(table: Vec<u64>) -> ImportAddressTable { ImportAddressTable::PE64(table) }
}

impl<'a> Bitfield<'a> for u32 {
    fn is_ordinal(&self) -> bool { self & IMPORT_BY_ORDINAL_32 == IMPORT_BY_ORDINAL_32 }
    fn to_ordinal(&self) -> u16 { (0xffff & self) as u16 }
    fn to_rva(&self) -> u32 { (self & IMPORT_RVA_MASK_32) as u32 }
    fn size_of() -> usize { 4 }
    fn is_zero(&self) -> bool { *self == 0 }
    fn vec_to_import_address_table(table: Vec<u32>) -> ImportAddressTable { ImportAddressTable::PE32(table) }
}

#[derive(Debug, Clone)]
pub struct HintNameTableEntry<'a> {
    pub hint: u16,
    pub name: &'a str,
}

impl<'a> HintNameTableEntry<'a> {
    fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<Self> {
        let offset = &mut offset;
        let hint = bytes.gread_with(offset, scroll::LE)?;
        let name = bytes.pread::<&'a str>(*offset)?;
        Ok(HintNameTableEntry { hint: hint, name: name })
    }
}

#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
    OrdinalNumber(u16),
    HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
}

pub type ImportLookupTable<'a> = Vec<SyntheticImportLookupTableEntry<'a>>;

impl<'a> SyntheticImportLookupTableEntry<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a [u8], mut offset: usize, sections: &[section_table::SectionTable])
                                                                      -> error::Result<ImportLookupTable<'a>> {
        let le = scroll::LE;
        let offset = &mut offset;
        let mut table = Vec::new();
        loop {
            let bitfield: T = bytes.gread_with(offset, le)?;
            if bitfield.is_zero() {
                debug!("imports done");
                break;
            } else {
                let entry = {
                    debug!("bitfield {:#x}", bitfield);
                    use self::SyntheticImportLookupTableEntry::*;
                    if bitfield.is_ordinal() {
                        let ordinal = bitfield.to_ordinal();
                        debug!("importing by ordinal {:#x}", ordinal);
                        OrdinalNumber(ordinal)
                    } else {
                        let rva = bitfield.to_rva();
                        let hentry = {
                            debug!("searching for RVA {:#x}", rva);
                            if let Some(offset) = utils::find_offset(rva as usize, sections) {
                                debug!("offset {:#x}", offset);
                                HintNameTableEntry::parse(bytes, offset)?
                            } else {
                                warn!("Entry {} has bad RVA: {:#x}", table.len(), rva);
                                continue
                            }
                        };
                        HintNameTableRVA ((rva, hentry))
                    }
                };
                table.push(entry);
            }
        }
        Ok(table)
    }
}

// get until entry is 0
#[derive(Debug)]
pub enum ImportAddressTable {
    PE32(Vec<u32>),
    PE64(Vec<u64>)
}

#[repr(C)]
#[derive(Debug)]
#[derive(Pread, Pwrite, SizeWith)]
pub struct ImportDirectoryEntry {
    pub import_lookup_table_rva: u32,
    pub time_date_stamp: u32,
    pub forwarder_chain: u32,
    pub name_rva: u32,
    pub import_address_table_rva: u32,
}

pub const SIZEOF_IMPORT_DIRECTORY_ENTRY: usize = 20;

impl ImportDirectoryEntry {
    pub fn is_null (&self) -> bool {
        (self.import_lookup_table_rva == 0) &&
            (self.time_date_stamp == 0) &&
            (self.forwarder_chain == 0) &&
            (self.name_rva == 0) &&
            (self.import_address_table_rva == 0)
    }
}

#[derive(Debug)]
pub struct SyntheticImportDirectoryEntry<'a> {
    pub import_directory_entry: ImportDirectoryEntry,
    /// Computed
    pub name: &'a str,
    /// The import lookup table is a vector of either ordinals, or RVAs + import names
    pub import_lookup_table: Option<ImportLookupTable<'a>>,
    /// Computed
    pub import_address_table: ImportAddressTable,
}

impl<'a> SyntheticImportDirectoryEntry<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a [u8], import_directory_entry: ImportDirectoryEntry, sections: &[section_table::SectionTable]) -> error::Result<SyntheticImportDirectoryEntry<'a>> {
        const LE: scroll::Endian = scroll::LE;
        let name_rva = import_directory_entry.name_rva;
        let name = utils::try_name(bytes, name_rva as usize, sections)?;
        let import_lookup_table = {
            let import_lookup_table_rva = import_directory_entry.import_lookup_table_rva;
            debug!("Synthesizing lookup table imports for {} lib, with import lookup table rva: {:#x}", name, import_lookup_table_rva);
            if let Some(import_lookup_table_offset) = utils::find_offset(import_lookup_table_rva as usize, sections) {
                let import_lookup_table = SyntheticImportLookupTableEntry::parse::<T>(bytes, import_lookup_table_offset, sections)?;
                debug!("Successfully synthesized import lookup table entry: {:#?}", import_lookup_table);
                Some(import_lookup_table)
            } else {
                None
            }
        };

        let import_address_table_offset = &mut utils::find_offset(import_directory_entry.import_address_table_rva as usize, sections).ok_or(error::Error::Malformed(format!("Cannot map import_address_table_rva {:#x} into offset for {}", import_directory_entry.import_address_table_rva, name)))?;
        let mut import_address_table = Vec::new();
        loop {
            let import_address: T = bytes.gread_with(import_address_table_offset, LE)?;
            if import_address.is_zero() { break } else { import_address_table.push(import_address); }
        }
        Ok(SyntheticImportDirectoryEntry {
            import_directory_entry: import_directory_entry,
            name: name,
            import_lookup_table: import_lookup_table,
            import_address_table: T::vec_to_import_address_table(import_address_table)
        })
    }
}

#[derive(Debug)]
/// Contains a list of synthesized import data for this binary, e.g., which symbols from which libraries it is importing from
pub struct ImportData<'a> {
    pub import_data: Vec<SyntheticImportDirectoryEntry<'a>>,
}

impl<'a> ImportData<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a[u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ImportData<'a>> {
        let import_directory_table_rva = dd.virtual_address as usize;
        debug!("import_directory_table_rva {:#x}", import_directory_table_rva);
        let offset = &mut utils::find_offset(import_directory_table_rva, sections).ok_or(error::Error::Malformed(format!("Cannot create ImportData; cannot map import_directory_table_rva {:#x} into offset", import_directory_table_rva)))?;;
        debug!("import data offset {:#x}", offset);
        let mut import_data = Vec::new();
        loop {
            let import_directory_entry: ImportDirectoryEntry = bytes.gread_with(offset, scroll::LE)?;
            debug!("{:#?}", import_directory_entry);
            if import_directory_entry.is_null() {
                break;
            } else {
                let entry = SyntheticImportDirectoryEntry::parse::<T>(bytes, import_directory_entry, sections)?;
                debug!("entry {:#?}", entry);
                import_data.push(entry);
            }
        }
        debug!("finished ImportData");
        Ok(ImportData { import_data: import_data})
    }
}

#[derive(Debug)]
/// A synthesized symbol import, the name is pre-indexed, and the binary offset is computed, as well as which dll it belongs to
pub struct Import<'a> {
    pub name: Cow<'a, str>,
    pub dll: &'a str,
    pub ordinal: u16,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
}

impl<'a> Import<'a> {
    pub fn parse<T: Bitfield<'a>>(_bytes: &'a [u8], import_data: &ImportData<'a>, _sections: &[section_table::SectionTable]) -> error::Result<Vec<Import<'a>>> {
        let mut imports = Vec::new();
        for data in &import_data.import_data {
            if let Some(ref import_lookup_table) = data.import_lookup_table {
                let dll = data.name;
                let import_base = data.import_directory_entry.import_address_table_rva as usize;
                debug!("Getting imports from {}", &dll);
                for (i, entry) in import_lookup_table.iter().enumerate() {
                    let offset = import_base + (i * T::size_of());
                    use self::SyntheticImportLookupTableEntry::*;
                    let (rva, name, ordinal) =
                        match entry {
                            &HintNameTableRVA ((rva, ref hint_entry)) => {
                                // if hint_entry.name = "" && hint_entry.hint = 0 {
                                //     println!("<PE.Import> warning hint/name table rva from {} without hint {:#x}", dll, rva);
                                // }
                                (rva, Cow::Borrowed(hint_entry.name), hint_entry.hint.clone())
                            },
                            &OrdinalNumber(ordinal) => {
                                let name = format!("ORDINAL {}", ordinal);
                                (0x0, Cow::Owned(name), ordinal)
                            },
                        };
                    let import =
                        Import {
                            name: name,
                            ordinal: ordinal, dll: dll,
                            size: T::size_of(), offset: offset, rva: rva as usize
                        };
                    imports.push(import);
                }
            }
        }
        Ok (imports)
    }
}
<commit_msg>Store import addresses as u64 for both PE32 and PE32+<commit_after>use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::fmt::{LowerHex, Debug};

use scroll::{self, Pread};
use scroll::ctx::TryFromCtx;
use error;

use pe::section_table;
use pe::utils;
use pe::data_directories;

pub const IMPORT_BY_ORDINAL_32: u32 = 0x8000_0000;
pub const IMPORT_BY_ORDINAL_64: u64 = 0x8000_0000_0000_0000;
pub const IMPORT_RVA_MASK_32: u32 = 0x8fff_ffff;
pub const IMPORT_RVA_MASK_64: u64 = 0x0000_0000_8fff_ffff;

pub trait Bitfield<'a>: Into<u64> + PartialEq + Eq + LowerHex + Debug + TryFromCtx<'a, scroll::Endian, Error=scroll::Error, Size=usize> {
    fn is_ordinal(&self) -> bool;
    fn to_ordinal(&self) -> u16;
    fn to_rva(&self) -> u32;
    fn size_of() -> usize;
    fn is_zero(&self) -> bool;
}

impl<'a> Bitfield<'a> for u64 {
    fn is_ordinal(&self) -> bool { self & IMPORT_BY_ORDINAL_64 == IMPORT_BY_ORDINAL_64 }
    fn to_ordinal(&self) -> u16 { (0xffff & self) as u16 }
    fn to_rva(&self) -> u32 { (self & IMPORT_RVA_MASK_64) as u32 }
    fn size_of() -> usize { 8 }
    fn is_zero(&self) -> bool { *self == 0 }
}

impl<'a> Bitfield<'a> for u32 {
    fn is_ordinal(&self) -> bool { self & IMPORT_BY_ORDINAL_32 == IMPORT_BY_ORDINAL_32 }
    fn to_ordinal(&self) -> u16 { (0xffff & self) as u16 }
    fn to_rva(&self) -> u32 { (self & IMPORT_RVA_MASK_32) as u32 }
    fn size_of() -> usize { 4 }
    fn is_zero(&self) -> bool { *self == 0 }
}

#[derive(Debug, Clone)]
pub struct HintNameTableEntry<'a> {
    pub hint: u16,
    pub name: &'a str,
}

impl<'a> HintNameTableEntry<'a> {
    fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<Self> {
        let offset = &mut offset;
        let hint = bytes.gread_with(offset, scroll::LE)?;
        let name = bytes.pread::<&'a str>(*offset)?;
        Ok(HintNameTableEntry { hint: hint, name: name })
    }
}

#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
    OrdinalNumber(u16),
    HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
}

pub type ImportLookupTable<'a> = Vec<SyntheticImportLookupTableEntry<'a>>;

impl<'a> SyntheticImportLookupTableEntry<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a [u8], mut offset: usize, sections: &[section_table::SectionTable])
                                                                      -> error::Result<ImportLookupTable<'a>> {
        let le = scroll::LE;
        let offset = &mut offset;
        let mut table = Vec::new();
        loop {
            let bitfield: T = bytes.gread_with(offset, le)?;
            if bitfield.is_zero() {
                debug!("imports done");
                break;
            } else {
                let entry = {
                    debug!("bitfield {:#x}", bitfield);
                    use self::SyntheticImportLookupTableEntry::*;
                    if bitfield.is_ordinal() {
                        let ordinal = bitfield.to_ordinal();
                        debug!("importing by ordinal {:#x}", ordinal);
                        OrdinalNumber(ordinal)
                    } else {
                        let rva = bitfield.to_rva();
                        let hentry = {
                            debug!("searching for RVA {:#x}", rva);
                            if let Some(offset) = utils::find_offset(rva as usize, sections) {
                                debug!("offset {:#x}", offset);
                                HintNameTableEntry::parse(bytes, offset)?
                            } else {
                                warn!("Entry {} has bad RVA: {:#x}", table.len(), rva);
                                continue
                            }
                        };
                        HintNameTableRVA ((rva, hentry))
                    }
                };
                table.push(entry);
            }
        }
        Ok(table)
    }
}

// get until entry is 0
pub type ImportAddressTable = Vec<u64>;

#[repr(C)]
#[derive(Debug)]
#[derive(Pread, Pwrite, SizeWith)]
pub struct ImportDirectoryEntry {
    pub import_lookup_table_rva: u32,
    pub time_date_stamp: u32,
    pub forwarder_chain: u32,
    pub name_rva: u32,
    pub import_address_table_rva: u32,
}

pub const SIZEOF_IMPORT_DIRECTORY_ENTRY: usize = 20;

impl ImportDirectoryEntry {
    pub fn is_null (&self) -> bool {
        (self.import_lookup_table_rva == 0) &&
            (self.time_date_stamp == 0) &&
            (self.forwarder_chain == 0) &&
            (self.name_rva == 0) &&
            (self.import_address_table_rva == 0)
    }
}

#[derive(Debug)]
pub struct SyntheticImportDirectoryEntry<'a> {
    pub import_directory_entry: ImportDirectoryEntry,
    /// Computed
    pub name: &'a str,
    /// The import lookup table is a vector of either ordinals, or RVAs + import names
    pub import_lookup_table: Option<ImportLookupTable<'a>>,
    /// Computed
    pub import_address_table: ImportAddressTable,
}

impl<'a> SyntheticImportDirectoryEntry<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a [u8], import_directory_entry: ImportDirectoryEntry, sections: &[section_table::SectionTable]) -> error::Result<SyntheticImportDirectoryEntry<'a>> {
        const LE: scroll::Endian = scroll::LE;
        let name_rva = import_directory_entry.name_rva;
        let name = utils::try_name(bytes, name_rva as usize, sections)?;
        let import_lookup_table = {
            let import_lookup_table_rva = import_directory_entry.import_lookup_table_rva;
            debug!("Synthesizing lookup table imports for {} lib, with import lookup table rva: {:#x}", name, import_lookup_table_rva);
            if let Some(import_lookup_table_offset) = utils::find_offset(import_lookup_table_rva as usize, sections) {
                let import_lookup_table = SyntheticImportLookupTableEntry::parse::<T>(bytes, import_lookup_table_offset, sections)?;
                debug!("Successfully synthesized import lookup table entry: {:#?}", import_lookup_table);
                Some(import_lookup_table)
            } else {
                None
            }
        };

        let import_address_table_offset = &mut utils::find_offset(import_directory_entry.import_address_table_rva as usize, sections).ok_or(error::Error::Malformed(format!("Cannot map import_address_table_rva {:#x} into offset for {}", import_directory_entry.import_address_table_rva, name)))?;
        let mut import_address_table = Vec::new();
        loop {
            let import_address = bytes.gread_with::<T>(import_address_table_offset, LE)?.into();
            if import_address == 0 { break } else { import_address_table.push(import_address); }
        }
        Ok(SyntheticImportDirectoryEntry {
            import_directory_entry: import_directory_entry,
            name: name,
            import_lookup_table: import_lookup_table,
            import_address_table: import_address_table
        })
    }
}

#[derive(Debug)]
/// Contains a list of synthesized import data for this binary, e.g., which symbols from which libraries it is importing from
pub struct ImportData<'a> {
    pub import_data: Vec<SyntheticImportDirectoryEntry<'a>>,
}

impl<'a> ImportData<'a> {
    pub fn parse<T: Bitfield<'a>>(bytes: &'a[u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ImportData<'a>> {
        let import_directory_table_rva = dd.virtual_address as usize;
        debug!("import_directory_table_rva {:#x}", import_directory_table_rva);
        let offset = &mut utils::find_offset(import_directory_table_rva, sections).ok_or(error::Error::Malformed(format!("Cannot create ImportData; cannot map import_directory_table_rva {:#x} into offset", import_directory_table_rva)))?;;
        debug!("import data offset {:#x}", offset);
        let mut import_data = Vec::new();
        loop {
            let import_directory_entry: ImportDirectoryEntry = bytes.gread_with(offset, scroll::LE)?;
            debug!("{:#?}", import_directory_entry);
            if import_directory_entry.is_null() {
                break;
            } else {
                let entry = SyntheticImportDirectoryEntry::parse::<T>(bytes, import_directory_entry, sections)?;
                debug!("entry {:#?}", entry);
                import_data.push(entry);
            }
        }
        debug!("finished ImportData");
        Ok(ImportData { import_data: import_data})
    }
}

#[derive(Debug)]
/// A synthesized symbol import, the name is pre-indexed, and the binary offset is computed, as well as which dll it belongs to
pub struct Import<'a> {
    pub name: Cow<'a, str>,
    pub dll: &'a str,
    pub ordinal: u16,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
}

impl<'a> Import<'a> {
    pub fn parse<T: Bitfield<'a>>(_bytes: &'a [u8], import_data: &ImportData<'a>, _sections: &[section_table::SectionTable]) -> error::Result<Vec<Import<'a>>> {
        let mut imports = Vec::new();
        for data in &import_data.import_data {
            if let Some(ref import_lookup_table) = data.import_lookup_table {
                let dll = data.name;
                let import_base = data.import_directory_entry.import_address_table_rva as usize;
                debug!("Getting imports from {}", &dll);
                for (i, entry) in import_lookup_table.iter().enumerate() {
                    let offset = import_base + (i * T::size_of());
                    use self::SyntheticImportLookupTableEntry::*;
                    let (rva, name, ordinal) =
                        match entry {
                            &HintNameTableRVA ((rva, ref hint_entry)) => {
                                // if hint_entry.name = "" && hint_entry.hint = 0 {
                                //     println!("<PE.Import> warning hint/name table rva from {} without hint {:#x}", dll, rva);
                                // }
                                (rva, Cow::Borrowed(hint_entry.name), hint_entry.hint.clone())
                            },
                            &OrdinalNumber(ordinal) => {
                                let name = format!("ORDINAL {}", ordinal);
                                (0x0, Cow::Owned(name), ordinal)
                            },
                        };
                    let import =
                        Import {
                            name: name,
                            ordinal: ordinal, dll: dll,
                            size: T::size_of(), offset: offset, rva: rva as usize
                        };
                    imports.push(import);
                }
            }
        }
        Ok (imports)
    }
}
<|endoftext|>