<commit_before>//! Read points from las files.

use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::path::Path;

use byteorder::LittleEndian;
use byteorder::ReadBytesExt;

use num::FromPrimitive;

use Result;
use header::Header;
use point::Classification;
use point::Point;
use point::ScanDirection;
use vlr::Vlr;

pub struct Reader<R: Read + Seek> {
    header: Header,
    reader: R,
    vlrs: Vec<Vlr>,
}

impl<R: Read + Seek> Reader<R> {
    /// Creates a reader for a `Read` object.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let stream = std::fs::File::open("data/1.2_0.las").unwrap();
    /// let reader = Reader::new(stream);
    /// ```
    pub fn new(mut reader: R) -> Result<Reader<R>> {
        let header = try!(Header::new(&mut reader));
        try!(reader.seek(SeekFrom::Start(header.header_size as u64)));
        let vlrs = try!(Vlr::read_n_from(&mut reader, header.number_of_variable_length_records as usize));
        Ok(Reader {
            header: header,
            reader: reader,
            vlrs: vlrs,
        })
    }

    /// Returns the `Header`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let reader = Reader::open("data/1.2_0.las").unwrap();
    /// let header = reader.header();
    /// assert_eq!(*b"LASF", header.file_signature);
    /// ```
    pub fn header(&self) -> &Header { &self.header }

    /// Returns a `Vec` of the file's `Vlr`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let mut reader = Reader::open("data/1.2_0.las").unwrap();
    /// let vlrs = reader.vlrs();
    /// assert_eq!(2, vlrs.len());
    /// ```
    pub fn vlrs(&self) -> &Vec<Vlr> { &self.vlrs }

    /// Returns a vector of all the points in the lasfile.
    ///
    /// Only use this method if you really do want to load all the points into memory at once.
    /// Otherwise, use the provided iterator methods to scan through the points in a more efficient
    /// manner.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let mut reader = Reader::open("data/1.2_0.las").unwrap();
    /// let points = reader.points().unwrap();
    /// assert_eq!(1, points.len());
    /// ```
    pub fn points(&mut self) -> Result<Vec<Point>> {
        Ok(try!(self.points_iter()).collect())
    }

    /// Creates an interator over this reader's points.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// # use las::point::Point;
    /// let mut reader = Reader::open("data/1.2_0.las").unwrap();
    /// let points: Vec<Point> = reader.points_iter().unwrap().collect();
    /// assert_eq!(1, points.len());
    /// ```
    pub fn points_iter(&mut self) -> Result<PointsIterator<R>> {
        try!(self.reader.seek(SeekFrom::Start(self.header.offset_to_point_data as u64)));
        Ok(PointsIterator {
            reader: self,
        })
    }

    /// Reads and returns the next point from the reader.
    fn next_point(&mut self) -> Result<Point> {
        let mut point: Point = Default::default();
        point.x = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.x +
            self.header.offset.x;
        point.y = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.y +
            self.header.offset.y;
        point.z = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.z +
            self.header.offset.z;
        point.intensity = try!(self.reader.read_u16::<LittleEndian>());
        let byte = try!(self.reader.read_u8());
        point.return_number = byte & 0b00000111;
        point.number_of_returns = byte >> 3 & 0b00000111;
        point.scan_direction = match ScanDirection::from_u8(byte >> 6 & 0b00000001) {
            Some(scan_direction) => scan_direction,
            None => unreachable!(),
        };
        point.edge_of_flight_line = (byte >> 7 & 0b00000001) == 1;
        point.classification = match Classification::from_u8(try!(self.reader.read_u8())) {
            Some(classification) => classification,
            None => Default::default(),
        };
        point.scan_angle_rank = try!(self.reader.read_i8());
        point.user_data = try!(self.reader.read_u8());
        point.point_source_id = try!(self.reader.read_u16::<LittleEndian>());

        match self.header.point_data_format_id {
            1 | 3 => point.gps_time = Some(try!(self.reader.read_f64::<LittleEndian>())),
            _ => (),
        }

        match self.header.point_data_format_id {
            2 | 3 => {
                point.red = Some(try!(self.reader.read_u16::<LittleEndian>()));
                point.green = Some(try!(self.reader.read_u16::<LittleEndian>()));
                point.blue = Some(try!(self.reader.read_u16::<LittleEndian>()));
            },
            _ => (),
        }

        Ok(point)
    }
}

impl Reader<BufReader<File>> {
    /// Opens a reader for a given file path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let reader = Reader::open("data/1.2_0.las");
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let reader = try!(File::open(path));
        Ok(try!(Reader::new(BufReader::new(reader))))
    }
}

/// Iterator over the points of a reader.
///
/// The iterator starts at the first point and reads through to the end.
pub struct PointsIterator<'a, R: 'a + Read + Seek> {
    reader: &'a mut Reader<R>,
}

impl<'a, R: Read + Seek> Iterator for PointsIterator<'a, R> {
    type Item = Point;

    fn next(&mut self) -> Option<Point> {
        self.reader.next_point().ok()
    }
}

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

    use point::Classification;
    use point::Point;
    use point::ScanDirection;

    const POINT0: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: None,
        red: None,
        green: None,
        blue: None,
    };

    const POINT1: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: Some(1205902800.0),
        red: None,
        green: None,
        blue: None,
    };

    const POINT2: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: None,
        red: Some(255),
        green: Some(12),
        blue: Some(234),
    };

    const POINT3: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: Some(1205902800.0),
        red: Some(255),
        green: Some(12),
        blue: Some(234),
    };

    fn check_file(filename: &str, reference_point: &Point) {
        let mut reader = Reader::open(filename).unwrap();
        let point = &reader.points().unwrap()[0];
        assert_eq!(reference_point, point);
    }

    #[test]
    fn points() {
        let mut reader = Reader::open("data/1.2_0.las").unwrap();
        let points: Vec<Point> = reader.points_iter().unwrap().collect();
        assert_eq!(1, points.len());
    }

    #[test]
    fn vlrs() {
        let reader = Reader::open("data/1.2_0.las").unwrap();
        let vlrs = reader.vlrs();

        let vlr = &vlrs[0];
        assert_eq!(0, vlr.reserved);
        assert_eq!("LASF_Projection", vlr.user_id);
        assert_eq!(34735, vlr.record_id);
        assert_eq!(64, vlr.record_length_after_header);
        assert_eq!("", vlr.description);
    }

    #[test]
    fn las10_0() {
        check_file("data/1.0_0.las", &POINT0);
    }

    #[test]
    fn las10_1() {
        check_file("data/1.0_1.las", &POINT1);
    }

    #[test]
    fn las11_0() {
        check_file("data/1.1_0.las", &POINT0);
    }

    #[test]
    fn las11_1() {
        check_file("data/1.1_1.las", &POINT1);
    }

    #[test]
    fn las12_0() {
        check_file("data/1.2_0.las", &POINT0);
    }

    #[test]
    fn las12_1() {
        check_file("data/1.2_1.las", &POINT1);
    }

    #[test]
    fn las12_2() {
        check_file("data/1.2_2.las", &POINT2);
    }

    #[test]
    fn las12_3() {
        check_file("data/1.2_3.las", &POINT3);
    }
}
<commit_msg>Use IntoIter instead of refs<commit_after>//! Read points from las files.

use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::path::Path;

use byteorder::LittleEndian;
use byteorder::ReadBytesExt;

use num::FromPrimitive;

use Result;
use header::Header;
use point::Classification;
use point::Point;
use point::ScanDirection;
use vlr::Vlr;

pub struct Reader<R: Read + Seek> {
    header: Header,
    reader: R,
    vlrs: Vec<Vlr>,
}

impl<R: Read + Seek> Reader<R> {
    /// Creates a reader for a `Read` object.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let stream = std::fs::File::open("data/1.2_0.las").unwrap();
    /// let reader = Reader::new(stream);
    /// ```
    pub fn new(mut reader: R) -> Result<Reader<R>> {
        let header = try!(Header::new(&mut reader));
        try!(reader.seek(SeekFrom::Start(header.header_size as u64)));
        let vlrs = try!(Vlr::read_n_from(&mut reader, header.number_of_variable_length_records as usize));
        try!(reader.seek(SeekFrom::Start(header.offset_to_point_data as u64)));
        Ok(Reader {
            header: header,
            reader: reader,
            vlrs: vlrs,
        })
    }

    /// Returns the `Header`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let reader = Reader::open("data/1.2_0.las").unwrap();
    /// let header = reader.header();
    /// assert_eq!(*b"LASF", header.file_signature);
    /// ```
    pub fn header(&self) -> &Header { &self.header }

    /// Returns a `Vec` of the file's `Vlr`s.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let mut reader = Reader::open("data/1.2_0.las").unwrap();
    /// let vlrs = reader.vlrs();
    /// assert_eq!(2, vlrs.len());
    /// ```
    pub fn vlrs(&self) -> &Vec<Vlr> { &self.vlrs }

    /// Returns a vector of all the points in the lasfile.
    ///
    /// Only use this method if you really do want to load all the points into memory at once.
    /// Otherwise, use the provided iterator methods to scan through the points in a more efficient
    /// manner.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let mut reader = Reader::open("data/1.2_0.las").unwrap();
    /// let points = reader.points().unwrap();
    /// assert_eq!(1, points.len());
    /// ```
    pub fn points(self) -> Result<Vec<Point>> {
        Ok(self.into_iter().collect())
    }

    fn next_point(&mut self) -> Result<Point> {
        let mut point: Point = Default::default();
        point.x = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.x +
            self.header.offset.x;
        point.y = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.y +
            self.header.offset.y;
        point.z = try!(self.reader.read_u32::<LittleEndian>()) as f64 * self.header.scale.z +
            self.header.offset.z;
        point.intensity = try!(self.reader.read_u16::<LittleEndian>());
        let byte = try!(self.reader.read_u8());
        point.return_number = byte & 0b00000111;
        point.number_of_returns = byte >> 3 & 0b00000111;
        point.scan_direction = match ScanDirection::from_u8(byte >> 6 & 0b00000001) {
            Some(scan_direction) => scan_direction,
            None => unreachable!(),
        };
        point.edge_of_flight_line = (byte >> 7 & 0b00000001) == 1;
        point.classification = match Classification::from_u8(try!(self.reader.read_u8())) {
            Some(classification) => classification,
            None => Default::default(),
        };
        point.scan_angle_rank = try!(self.reader.read_i8());
        point.user_data = try!(self.reader.read_u8());
        point.point_source_id = try!(self.reader.read_u16::<LittleEndian>());

        match self.header.point_data_format_id {
            1 | 3 => point.gps_time = Some(try!(self.reader.read_f64::<LittleEndian>())),
            _ => (),
        }

        match self.header.point_data_format_id {
            2 | 3 => {
                point.red = Some(try!(self.reader.read_u16::<LittleEndian>()));
                point.green = Some(try!(self.reader.read_u16::<LittleEndian>()));
                point.blue = Some(try!(self.reader.read_u16::<LittleEndian>()));
            },
            _ => (),
        }

        Ok(point)
    }
}

impl Reader<BufReader<File>> {
    /// Opens a reader for a given file path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::reader::Reader;
    /// let reader = Reader::open("data/1.2_0.las");
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let reader = try!(File::open(path));
        Ok(try!(Reader::new(BufReader::new(reader))))
    }
}

impl<R: Read + Seek> IntoIterator for Reader<R> {
    type Item = Point;
    type IntoIter = PointsIterator<R>;

    fn into_iter(self) -> Self::IntoIter {
        PointsIterator { reader: self }
    }
}

/// Iterator over the points of a reader.
///
/// The iterator starts at the first point and reads through to the end.
pub struct PointsIterator<R: Read + Seek> {
    reader: Reader<R>,
}

impl<R: Read + Seek> Iterator for PointsIterator<R> {
    type Item = Point;

    fn next(&mut self) -> Option<Point> {
        self.reader.next_point().ok()
    }
}

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

    use point::Classification;
    use point::Point;
    use point::ScanDirection;

    const POINT0: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: None,
        red: None,
        green: None,
        blue: None,
    };

    const POINT1: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: Some(1205902800.0),
        red: None,
        green: None,
        blue: None,
    };

    const POINT2: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: None,
        red: Some(255),
        green: Some(12),
        blue: Some(234),
    };

    const POINT3: Point = Point {
        x: 470692.44,
        y: 4602888.90,
        z: 16.0,
        intensity: 0,
        return_number: 2,
        number_of_returns: 0,
        scan_direction: ScanDirection::Backward,
        edge_of_flight_line: false,
        classification: Classification::Ground,
        scan_angle_rank: -13,
        user_data: 0,
        point_source_id: 0,
        gps_time: Some(1205902800.0),
        red: Some(255),
        green: Some(12),
        blue: Some(234),
    };

    fn check_file(filename: &str, reference_point: &Point) {
        let reader = Reader::open(filename).unwrap();
        let point = &reader.points().unwrap()[0];
        assert_eq!(reference_point, point);
    }

    #[test]
    fn points() {
        let reader = Reader::open("data/1.2_0.las").unwrap();
        let points: Vec<Point> = reader.into_iter().collect();
        assert_eq!(1, points.len());
    }

    #[test]
    fn vlrs() {
        let reader = Reader::open("data/1.2_0.las").unwrap();
        let vlrs = reader.vlrs();

        let vlr = &vlrs[0];
        assert_eq!(0, vlr.reserved);
        assert_eq!("LASF_Projection", vlr.user_id);
        assert_eq!(34735, vlr.record_id);
        assert_eq!(64, vlr.record_length_after_header);
        assert_eq!("", vlr.description);
    }

    #[test]
    fn las10_0() {
        check_file("data/1.0_0.las", &POINT0);
    }

    #[test]
    fn las10_1() {
        check_file("data/1.0_1.las", &POINT1);
    }

    #[test]
    fn las11_0() {
        check_file("data/1.1_0.las", &POINT0);
    }

    #[test]
    fn las11_1() {
        check_file("data/1.1_1.las", &POINT1);
    }

    #[test]
    fn las12_0() {
        check_file("data/1.2_0.las", &POINT0);
    }

    #[test]
    fn las12_1() {
        check_file("data/1.2_1.las", &POINT1);
    }

    #[test]
    fn las12_2() {
        check_file("data/1.2_2.las", &POINT2);
    }

    #[test]
    fn las12_3() {
        check_file("data/1.2_3.las", &POINT3);
    }
}
<|endoftext|>


<commit_before>use super::errors::ParseErr;
use num_cpus;

/// Receives an input that is either an integer, or percent. If the string ends with `%`, it will
/// be calculated as a percent of the total number of CPU cores. Otherwise, the number provided
/// will be considered the number of jobs to run in parallel.
pub fn parse(value: &str) -> Result<usize, ParseErr> {
    if value.chars().rev().next().unwrap() == '%' {
        // If the last character is `%`, then all but the last character are the value.
        value[0..value.chars().count()-1].parse::<usize>()
            .map(|percent| (num_cpus::get() * percent) / 100)
            .map_err(|_| ParseErr::JobsNaN(value.to_owned()))

    } else {
        value.parse::<usize>().map_err(|_| ParseErr::JobsNaN(value.to_owned()))
    }
}

#[test]
fn test_parse() {
    let ncores = num_cpus::get();
    assert_eq!((ncores * 50) / 100,  parse("50%" ).unwrap());
    assert_eq!((ncores * 100) / 100, parse("100%").unwrap());
    assert_eq!((ncores * 150) / 100, parse("150%").unwrap());
    assert_eq!(4,                    parse("4"   ).unwrap());
}
<commit_msg>Implement Jobs +/- Modifiers You may now write the job arguments with + and - operators - +50% is equivalent to 150% - -50% is equivalent to 50% - +2 is equivalent to num_cpus + 2 - -2 is equivalent to num_cpus - 2 - If the negative modifier is less than number of CPU cores, set 1<commit_after>use super::errors::ParseErr;
use num_cpus;

/// Receives an input that is either an integer, or percent. If the string ends with `%`, it will
/// be calculated as a percent of the total number of CPU cores. Otherwise, the number provided
/// will be considered the number of jobs to run in parallel.
pub fn parse(value: &str) -> Result<usize, ParseErr> {
    match (value.bytes().next().unwrap(), value.bytes().last().unwrap()) {
        (b'+', b'%') => {
            value[1..value.bytes().count()-1].parse::<usize>()
            .map(|percent| {
                let ncpus = num_cpus::get();
                ncpus + ((ncpus * percent) / 100)
            })
            .map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
        (b'-', b'%') => {
            value[1..value.bytes().count()-1].parse::<usize>()
                .map(|percent| {
                    let ncpus = num_cpus::get();
                    let modifier = (ncpus * percent) / 100;
                    if modifier > ncpus { 1 } else { ncpus - modifier }
                })
                .map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
        (_, b'%') => {
            value[0..value.bytes().count()-1].parse::<usize>()
                .map(|percent| (num_cpus::get() * percent) / 100)
                .map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
        (b'+', _) => {
            value[1..value.bytes().count()].parse::<usize>()
                .map(|value| num_cpus::get() + value)
                .map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
        (b'-', _) => {
            value[1..value.bytes().count()].parse::<usize>()
            .map(|value| {
                let ncpus = num_cpus::get();
                if value > ncpus { 1 } else { ncpus - value }
            })
            .map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
        _ => {
            value.parse::<usize>().map_err(|_| ParseErr::JobsNaN(value.to_owned()))
        },
    }
}

#[test]
fn job_parsing() {
    let ncores = num_cpus::get();
    assert_eq!((ncores * 50) / 100,  parse("50%" ).unwrap());
    assert_eq!((ncores * 100) / 100, parse("100%").unwrap());
    assert_eq!((ncores * 150) / 100, parse("150%").unwrap());
    assert_eq!(4,                    parse("4"   ).unwrap());
    assert_eq!((ncores * 150) / 100, parse("+50%").unwrap());
    assert_eq!((ncores * 50) / 100,  parse("-50%").unwrap());
    assert_eq!(ncores - 2,           parse("-2"  ).unwrap());
    assert_eq!(ncores + 2,           parse("+2"  ).unwrap());
}
<|endoftext|>


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

use crate::command_buffer::synced::CommandBufferState;
use crate::pipeline::graphics::vertex_input::VertexInputRate;
use crate::pipeline::GraphicsPipeline;
use crate::DeviceSize;
use std::error;
use std::fmt;

pub(in super::super) fn check_vertex_buffers(
    current_state: CommandBufferState,
    pipeline: &GraphicsPipeline,
    vertices: Option<(u32, u32)>,
    instances: Option<(u32, u32)>,
) -> Result<(), CheckVertexBufferError> {
    let vertex_input = pipeline.vertex_input_state();
    let mut max_vertex_count: Option<u32> = None;
    let mut max_instance_count: Option<u32> = None;

    for (&binding_num, binding_desc) in &vertex_input.bindings {
        let vertex_buffer = match current_state.vertex_buffer(binding_num) {
            Some(x) => x,
            None => return Err(CheckVertexBufferError::BufferNotBound { binding_num }),
        };

        let mut num_elements = (vertex_buffer.size() / binding_desc.stride as DeviceSize)
            .try_into()
            .unwrap_or(u32::MAX);

        match binding_desc.input_rate {
            VertexInputRate::Vertex => {
                max_vertex_count = Some(if let Some(x) = max_vertex_count {
                    x.min(num_elements)
                } else {
                    num_elements
                });
            }
            VertexInputRate::Instance { divisor } => {
                if divisor == 0 {
                    // A divisor of 0 means the same instance data is used for all instances,
                    // so we can draw any number of instances from a single element.
                    // The buffer must contain at least one element though.
                    if num_elements != 0 {
                        num_elements = u32::MAX;
                    }
                } else {
                    // If divisor is 2, we use only half the amount of data from the source buffer,
                    // so the number of instances that can be drawn is twice as large.
                    num_elements = num_elements.saturating_mul(divisor);
                }

                max_instance_count = Some(if let Some(x) = max_instance_count {
                    x.min(num_elements)
                } else {
                    num_elements
                });
            }
        };
    }

    if let Some((first_vertex, vertex_count)) = vertices {
        if let Some(max_vertex_count) = max_vertex_count {
            if first_vertex + vertex_count > max_vertex_count {
                return Err(CheckVertexBufferError::TooManyVertices {
                    vertex_count,
                    max_vertex_count,
                });
            }
        }
    }

    if let Some((first_instance, instance_count)) = instances {
        if let Some(max_instance_count) = max_instance_count {
            if first_instance + instance_count > max_instance_count {
                return Err(CheckVertexBufferError::TooManyInstances {
                    instance_count,
                    max_instance_count,
                }
                .into());
            }
        }

        if pipeline.subpass().render_pass().views_used() != 0 {
            let max_instance_index = pipeline
                .device()
                .physical_device()
                .properties()
                .max_multiview_instance_index
                .unwrap_or(0);

            if first_instance + instance_count > max_instance_index + 1 {
                return Err(CheckVertexBufferError::TooManyInstances {
                    instance_count,
                    max_instance_count: max_instance_index + 1, // TODO: this can overflow
                }
                .into());
            }
        }
    }

    Ok(())
}

/// Error that can happen when checking whether the vertex buffers are valid.
#[derive(Debug, Copy, Clone)]
pub enum CheckVertexBufferError {
    /// No buffer was bound to a binding slot needed by the pipeline.
    BufferNotBound { binding_num: u32 },

    /// The "vertex buffer" usage must be enabled on the buffer.
    BufferMissingUsage {
        /// Index of the buffer that is missing usage.
        binding_num: u32,
    },

    /// A draw command requested too many vertices.
    TooManyVertices {
        /// The used amount of vertices.
        vertex_count: u32,
        /// The allowed amount of vertices.
        max_vertex_count: u32,
    },

    /// A draw command requested too many instances.
    ///
    /// When the `multiview` feature is used the maximum amount of instances may be reduced
    /// because the implementation may use instancing internally to implement `multiview`.
    TooManyInstances {
        /// The used amount of instances.
        instance_count: u32,
        /// The allowed amount of instances.
        max_instance_count: u32,
    },
}

impl error::Error for CheckVertexBufferError {}

impl fmt::Display for CheckVertexBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                CheckVertexBufferError::BufferNotBound { .. } => {
                    "no buffer was bound to a binding slot needed by the pipeline"
                }
                CheckVertexBufferError::BufferMissingUsage { .. } => {
                    "the vertex buffer usage is missing on a vertex buffer"
                }
                CheckVertexBufferError::TooManyVertices { .. } => {
                    "the draw command requested too many vertices"
                }
                CheckVertexBufferError::TooManyInstances { .. } => {
                    "the draw command requested too many instances"
                }
            }
        )
    }
}
<commit_msg>Fixed potential overflow in multiview vertex buffer validation (#1855)<commit_after>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::command_buffer::synced::CommandBufferState;
use crate::pipeline::graphics::vertex_input::VertexInputRate;
use crate::pipeline::GraphicsPipeline;
use crate::DeviceSize;
use std::error;
use std::fmt;

pub(in super::super) fn check_vertex_buffers(
    current_state: CommandBufferState,
    pipeline: &GraphicsPipeline,
    vertices: Option<(u32, u32)>,
    instances: Option<(u32, u32)>,
) -> Result<(), CheckVertexBufferError> {
    let vertex_input = pipeline.vertex_input_state();
    let mut max_vertex_count: Option<u32> = None;
    let mut max_instance_count: Option<u32> = None;

    for (&binding_num, binding_desc) in &vertex_input.bindings {
        let vertex_buffer = match current_state.vertex_buffer(binding_num) {
            Some(x) => x,
            None => return Err(CheckVertexBufferError::BufferNotBound { binding_num }),
        };

        let mut num_elements = (vertex_buffer.size() / binding_desc.stride as DeviceSize)
            .try_into()
            .unwrap_or(u32::MAX);

        match binding_desc.input_rate {
            VertexInputRate::Vertex => {
                max_vertex_count = Some(if let Some(x) = max_vertex_count {
                    x.min(num_elements)
                } else {
                    num_elements
                });
            }
            VertexInputRate::Instance { divisor } => {
                if divisor == 0 {
                    // A divisor of 0 means the same instance data is used for all instances,
                    // so we can draw any number of instances from a single element.
                    // The buffer must contain at least one element though.
                    if num_elements != 0 {
                        num_elements = u32::MAX;
                    }
                } else {
                    // If divisor is 2, we use only half the amount of data from the source buffer,
                    // so the number of instances that can be drawn is twice as large.
                    num_elements = num_elements.saturating_mul(divisor);
                }

                max_instance_count = Some(if let Some(x) = max_instance_count {
                    x.min(num_elements)
                } else {
                    num_elements
                });
            }
        };
    }

    if let Some((first_vertex, vertex_count)) = vertices {
        if let Some(max_vertex_count) = max_vertex_count {
            if first_vertex + vertex_count > max_vertex_count {
                return Err(CheckVertexBufferError::TooManyVertices {
                    vertex_count,
                    max_vertex_count,
                });
            }
        }
    }

    if let Some((first_instance, instance_count)) = instances {
        if let Some(max_instance_count) = max_instance_count {
            if first_instance + instance_count > max_instance_count {
                return Err(CheckVertexBufferError::TooManyInstances {
                    instance_count,
                    max_instance_count,
                }
                .into());
            }
        }

        if pipeline.subpass().render_pass().views_used() != 0 {
            let max_instance_index = pipeline
                .device()
                .physical_device()
                .properties()
                .max_multiview_instance_index
                .unwrap_or(0);

            // The condition is somewhat convoluted to avoid integer overflows.
            let out_of_range = first_instance > max_instance_index
                || (instance_count > 0 && instance_count - 1 > max_instance_index - first_instance);
            if out_of_range {
                return Err(CheckVertexBufferError::TooManyInstances {
                    instance_count,
                    max_instance_count: max_instance_index + 1, // TODO: this can overflow
                }
                .into());
            }
        }
    }

    Ok(())
}

/// Error that can happen when checking whether the vertex buffers are valid.
#[derive(Debug, Copy, Clone)]
pub enum CheckVertexBufferError {
    /// No buffer was bound to a binding slot needed by the pipeline.
    BufferNotBound { binding_num: u32 },

    /// The "vertex buffer" usage must be enabled on the buffer.
    BufferMissingUsage {
        /// Index of the buffer that is missing usage.
        binding_num: u32,
    },

    /// A draw command requested too many vertices.
    TooManyVertices {
        /// The used amount of vertices.
        vertex_count: u32,
        /// The allowed amount of vertices.
        max_vertex_count: u32,
    },

    /// A draw command requested too many instances.
    ///
    /// When the `multiview` feature is used the maximum amount of instances may be reduced
    /// because the implementation may use instancing internally to implement `multiview`.
    TooManyInstances {
        /// The used amount of instances.
        instance_count: u32,
        /// The allowed amount of instances.
        max_instance_count: u32,
    },
}

impl error::Error for CheckVertexBufferError {}

impl fmt::Display for CheckVertexBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                CheckVertexBufferError::BufferNotBound { .. } => {
                    "no buffer was bound to a binding slot needed by the pipeline"
                }
                CheckVertexBufferError::BufferMissingUsage { .. } => {
                    "the vertex buffer usage is missing on a vertex buffer"
                }
                CheckVertexBufferError::TooManyVertices { .. } => {
                    "the draw command requested too many vertices"
                }
                CheckVertexBufferError::TooManyInstances { .. } => {
                    "the draw command requested too many instances"
                }
            }
        )
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    let mut child = Command::new("cargo")
        .arg("build")
        .arg("--package=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()?;
    child.wait();

    if ::std::path::Path::new("../../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../target/debug/varlink-certification").exists() {
        return Ok("exec:../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<commit_msg>varlink-certification/src/test.rs: ignore cargo build exec failure<commit_after>use std::io;
use std::process::{Command, Stdio};
use std::{thread, time};
use {ErrorKind, Result};

fn run_self_test(address: String) -> io::Result<()> {
    let client_address = address.clone();

    let child = thread::spawn(move || {
        if let Err(e) = ::run_server(address, 4) {
            match e.kind() {
                ::varlink::ErrorKind::Timeout => {}
                _ => panic!("error: {}", e),
            }
        }
    });

    // give server time to start
    thread::sleep(time::Duration::from_secs(1));

    let ret = ::run_client(client_address);
    if let Err(e) = ret {
        panic!("error: {:?}", e);
    }
    if let Err(e) = child.join() {
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            format!("{:#?}", e),
        ))
    } else {
        Ok(())
    }
}

#[test]
fn test_unix() {
    assert!(run_self_test("unix:/tmp/org.varlink.certification".into()).is_ok());
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_unix_abstract() {
    assert!(run_self_test("unix:@org.varlink.certification".into()).is_ok());
}

#[test]
fn test_tcp() {
    assert!(run_self_test("tcp:0.0.0.0:23456".into()).is_ok());
}

fn get_exec() -> Result<String> {
    if let Ok(mut child) = Command::new("cargo")
        .arg("build")
        .arg("--package=varlink-certification")
        .arg("--bin=varlink-certification")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
    {
        let _ = child.wait();
    }

    if ::std::path::Path::new("../../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../../target/debug/varlink-certification").exists() {
        return Ok("exec:../../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("../target/debug/varlink-certification").exists() {
        return Ok("exec:../target/debug/varlink-certification".into());
    }

    if ::std::path::Path::new("./target/debug/varlink-certification").exists() {
        return Ok("exec:./target/debug/varlink-certification".into());
    }

    Err(ErrorKind::Io_Error(io::ErrorKind::NotFound).into())
}

#[test]
fn test_exec() {
    match get_exec() {
        Err(_) => {
            eprintln!("test test::test_exec ... skipping, no varlink-certification binary found");
            return;
        }
        Ok(address) => assert!(::run_client(address).is_ok()),
    }
}

#[test]
fn test_wrong_address_1() {
    assert!(::run_server("tcpd:0.0.0.0:12345".into(), 1).is_err());
}
<|endoftext|>


<commit_before>use crate::header::{Charset, QualityItem, ACCEPT_CHARSET};

header! {
    /// `Accept-Charset` header, defined in
    /// [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.3)
    ///
    /// The `Accept-Charset` header field can be sent by a user agent to
    /// indicate what charsets are acceptable in textual response content.
    /// This field allows user agents capable of understanding more
    /// comprehensive or special-purpose charsets to signal that capability
    /// to an origin server that is capable of representing information in
    /// those charsets.
    ///
    /// # ABNF
    ///
    /// ```text
    /// Accept-Charset = 1#( ( charset / "*" ) [ weight ] )
    /// ```
    ///
    /// # Example values
    /// * `iso-8859-5, unicode-1-1;q=0.8`
    ///
    /// # Examples
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, qitem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![qitem(Charset::Us_Ascii)])
    /// );
    /// # }
    /// ```
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, q, QualityItem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![
    ///         QualityItem::new(Charset::Us_Ascii, q(900)),
    ///         QualityItem::new(Charset::Iso_8859_10, q(200)),
    ///     ])
    /// );
    /// # }
    /// ```
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, qitem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![qitem(Charset::Ext("utf-8".to_owned()))])
    /// );
    /// # }
    /// ```
    (AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+

    test_accept_charset {
        /// Test case from RFC
        test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
    }
}
<commit_msg>Fix doc comment<commit_after>use crate::header::{Charset, QualityItem, ACCEPT_CHARSET};

header! {
    /// `Accept-Charset` header, defined in
    /// [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.3)
    ///
    /// The `Accept-Charset` header field can be sent by a user agent to
    /// indicate what charsets are acceptable in textual response content.
    /// This field allows user agents capable of understanding more
    /// comprehensive or special-purpose charsets to signal that capability
    /// to an origin server that is capable of representing information in
    /// those charsets.
    ///
    /// # ABNF
    ///
    /// ```text
    /// Accept-Charset = 1#( ( charset / "*" ) [ weight ] )
    /// ```
    ///
    /// # Example values
    /// * `iso-8859-5, unicode-1-1;q=0.8`
    ///
    /// # Examples
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, qitem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![qitem(Charset::Us_Ascii)])
    /// );
    /// # }
    /// ```
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, q, QualityItem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![
    ///         QualityItem::new(Charset::Us_Ascii, q(900)),
    ///         QualityItem::new(Charset::Iso_8859_10, q(200)),
    ///     ])
    /// );
    /// # }
    /// ```
    /// ```rust
    /// # extern crate actix_http;
    /// use actix_http::Response;
    /// use actix_http::http::header::{AcceptCharset, Charset, qitem};
    ///
    /// # fn main() {
    /// let mut builder = Response::Ok();
    /// builder.set(
    ///     AcceptCharset(vec![qitem(Charset::Ext("utf-8".to_owned()))])
    /// );
    /// # }
    /// ```
    (AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+

    test_accept_charset {
        // Test case from RFC
        test_header!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
    }
}
<|endoftext|>


<commit_before>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This example implements the `sha256sum` program in Rust using the Streambuffer library. Compare
// with `sha256sum_streambuffer` which uses the IO primitives in the standard library.
//
// Printing hashes in the order the files were specified is left as an excercise for the reader.

use std::collections::VecDeque;
use std::cmp;
use std::env;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use streambuffer::StreamBuffer;

extern crate crypto;
extern crate streambuffer;

struct State {
    fname: String,
    fstream: StreamBuffer,
    offset: usize,
    hasher: Sha256
}

/// Continues hashing until that would block. Returns the state if hashing is not done, plus a
/// boolean indicating whether progress was made.
fn hash(mut state: State) -> Option<(State, bool)> {
    let mut made_progress = false;
    loop {
        let bytes_left = state.fstream.len() - state.offset;
        let chunk_len = cmp::min(bytes_left, state.fstream.chunk_len_hint());

        // Keep on hashing slices until a slice is not resident.
        match state.fstream.try_slice(state.offset, chunk_len) {
            Some(slice) => {
                state.hasher.input(slice);
                state.offset += chunk_len;
                made_progress = true;

                if state.offset == state.fstream.len() {
                    // Match the output format of `sha256sum`, which has two spaces between
                    // the hash and name.
                    println!("{}  {}", state.hasher.result_str(), state.fname);
                    return None;
                }
            }
            None => break
        }
    }

    // Not done yet, try again later when more data is resident.
    Some((state, made_progress))
}

fn open_new(files: &mut VecDeque<String>) -> State {
    let fname = files.pop_front().unwrap();
    let fstream = StreamBuffer::open(&fname).expect("failed to open file");
    State {
        fname: fname,
        fstream: fstream,
        offset: 0,
        hasher: Sha256::new(),
    }
}

fn main() {
    let mut files: VecDeque<String> = env::args().skip(1).collect();
    let mut queue = VecDeque::new();

    loop {
        match queue.pop_front() {
            Some(state) => match hash(state) {
                Some((state, made_progress)) => {
                    if !made_progress && !files.is_empty() {
                        // If no progress was made, we are going through the queue too quickly.
                        // Open a new file so we have more to do. Push to the front, so that we
                        // immediately kick off the prefetch (or continue to make progress if the
                        // file happened to be resident already).
                        queue.push_front(open_new(&mut files));
                    }
                    queue.push_back(state);
                }
                None => {
                    // The file is done. It would be possible to open a new file here to keep the
                    // queue full, but it is probably better not to do that; new files will be
                    // opened if no progress is made, so this keeps the open files to a minimum.
                }
            },
            None => {
                if files.is_empty() {
                    // All tasks are done, and there are no new files. End of the program.
                    return;
                } else {
                    queue.push_front(open_new(&mut files));
                }
            }
        }
    }
}

<commit_msg>Simplify sha256sum Streambuffer example<commit_after>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This example implements the `sha256sum` program in Rust using the Streambuffer library. Compare
// with `sha256sum_streambuffer` which uses the IO primitives in the standard library.

use std::env;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use streambuffer::StreamBuffer;

extern crate crypto;
extern crate streambuffer;

fn main() {
    for fname in env::args().skip(1) {
        let fstream = StreamBuffer::open(&fname).expect("failed to open file");
        let mut hasher = Sha256::new();
        hasher.input(fstream.as_slice());

        // Match the output format of `sha256sum`, which has two spaces between the hash and name.
        println!("{}  {}", hasher.result_str(), fname);
    }
}

<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::{self, File};
use std::path::{self, Path, PathBuf};

use tar::Archive;
use flate2::{GzBuilder, Compression};
use flate2::read::GzDecoder;

use core::{SourceId, Package, PackageId};
use sources::PathSource;
use util::{self, CargoResult, human, internal, ChainError, Config};
use ops;

struct Bomb { path: Option<PathBuf> }

impl Drop for Bomb {
    fn drop(&mut self) {
        match self.path.as_ref() {
            Some(path) => { let _ = fs::remove_file(path); }
            None => {}
        }
    }
}

pub fn package(manifest_path: &Path,
               config: &Config,
               verify: bool,
               list: bool,
               metadata: bool) -> CargoResult<Option<PathBuf>> {
    let mut src = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                            config));
    let pkg = try!(src.root_package());

    if metadata {
        try!(check_metadata(&pkg, config));
    }

    if list {
        let root = pkg.root();
        let mut list: Vec<_> = try!(src.list_files(&pkg)).iter().map(|file| {
            util::without_prefix(&file, &root).unwrap().to_path_buf()
        }).collect();
        list.sort();
        for file in list.iter() {
            println!("{}", file.display());
        }
        return Ok(None)
    }

    let filename = format!("package/{}-{}.crate", pkg.name(), pkg.version());
    let target_dir = config.target_dir(&pkg);
    let dst = target_dir.join(&filename);
    if fs::metadata(&dst).is_ok() { return Ok(Some(dst)) }

    let mut bomb = Bomb { path: Some(dst.clone()) };

    try!(config.shell().status("Packaging", pkg.package_id().to_string()));
    try!(tar(&pkg, &src, config, &dst).chain_error(|| {
        human("failed to prepare local package for uploading")
    }));
    if verify {
        try!(run_verify(config, &pkg, &dst).chain_error(|| {
            human("failed to verify package tarball")
        }))
    }
    Ok(Some(bomb.path.take().unwrap()))
}

// check that the package has some piece of metadata that a human can
// use to tell what the package is about.
#[allow(deprecated)] // connect => join in 1.3
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
    let md = pkg.manifest().metadata();

    let mut missing = vec![];

    macro_rules! lacking {
        ($( $($field: ident)||* ),*) => {{
            $(
                if $(md.$field.as_ref().map_or(true, |s| s.is_empty()))&&* {
                    $(missing.push(stringify!($field).replace("_", "-"));)*
                }
            )*
        }}
    }
    lacking!(description, license || license_file, documentation || homepage || repository);

    if !missing.is_empty() {
        let mut things = missing[..missing.len() - 1].connect(", ");
        // things will be empty if and only if length == 1 (i.e. the only case
        // to have no `or`).
        if !things.is_empty() {
            things.push_str(" or ");
        }
        things.push_str(&missing.last().unwrap());

        try!(config.shell().warn(
            &format!("warning: manifest has no {things}. \
                    See http://doc.crates.io/manifest.html#package-metadata for more info.",
                    things = things)))
    }
    Ok(())
}

fn tar(pkg: &Package, src: &PathSource, config: &Config,
       dst: &Path) -> CargoResult<()> {

    if fs::metadata(&dst).is_ok() {
        return Err(human(format!("destination already exists: {}",
                                 dst.display())))
    }

    try!(fs::create_dir_all(dst.parent().unwrap()));

    let tmpfile = try!(File::create(dst));

    // Prepare the encoder and its header
    let filename = Path::new(dst.file_name().unwrap());
    let encoder = GzBuilder::new().filename(try!(util::path2bytes(filename)))
                                  .write(tmpfile, Compression::Best);

    // Put all package files into a compressed archive
    let ar = Archive::new(encoder);
    let root = pkg.root();
    for file in try!(src.list_files(pkg)).iter() {
        if &**file == dst { continue }
        let relative = util::without_prefix(&file, &root).unwrap();
        let relative = try!(relative.to_str().chain_error(|| {
            human(format!("non-utf8 path in source directory: {}",
                          relative.display()))
        }));
        let mut file = try!(File::open(file));
        try!(config.shell().verbose(|shell| {
            shell.status("Archiving", &relative)
        }));
        let path = format!("{}-{}{}{}", pkg.name(), pkg.version(),
                           path::MAIN_SEPARATOR, relative);
        try!(ar.append_file(&path, &mut file).chain_error(|| {
            internal(format!("could not archive source file `{}`", relative))
        }));
    }
    try!(ar.finish());
    Ok(())
}

fn run_verify(config: &Config, pkg: &Package, tar: &Path)
              -> CargoResult<()> {
    try!(config.shell().status("Verifying", pkg));

    let f = try!(GzDecoder::new(try!(File::open(tar))));
    let dst = pkg.root().join(&format!("target/package/{}-{}",
                                       pkg.name(), pkg.version()));
    if fs::metadata(&dst).is_ok() {
        try!(fs::remove_dir_all(&dst));
    }
    let mut archive = Archive::new(f);
    try!(archive.unpack(dst.parent().unwrap()));
    let manifest_path = dst.join("Cargo.toml");

    // When packages are uploaded to the registry, all path dependencies are
    // implicitly converted to registry-based dependencies, so we rewrite those
    // dependencies here.
    //
    // We also make sure to point all paths at `dst` instead of the previous
    // location that the package was originally read from. In locking the
    // `SourceId` we're telling it that the corresponding `PathSource` will be
    // considered updated and we won't actually read any packages.
    let registry = try!(SourceId::for_central(config));
    let precise = Some("locked".to_string());
    let new_src = try!(SourceId::for_path(&dst)).with_precise(precise);
    let new_pkgid = try!(PackageId::new(pkg.name(), pkg.version(), &new_src));
    let new_summary = pkg.summary().clone().map_dependencies(|d| {
        if !d.source_id().is_path() { return d }
        d.clone_inner().set_source_id(registry.clone()).into_dependency()
    });
    let mut new_manifest = pkg.manifest().clone();
    new_manifest.set_summary(new_summary.override_id(new_pkgid));
    let new_pkg = Package::new(new_manifest, &manifest_path);

    // Now that we've rewritten all our path dependencies, compile it!
    try!(ops::compile_pkg(&new_pkg, &ops::CompileOptions {
        config: config,
        jobs: None,
        target: None,
        features: &[],
        no_default_features: false,
        spec: None,
        filter: ops::CompileFilter::Everything,
        exec_engine: None,
        release: false,
        mode: ops::CompileMode::Build,
        target_rustc_args: None,
    }));

    Ok(())
}
<commit_msg>Add a warning when packaging crates with wildcard dependencies<commit_after>use std::io::prelude::*;
use std::fs::{self, File};
use std::path::{self, Path, PathBuf};

use semver::VersionReq;
use tar::Archive;
use flate2::{GzBuilder, Compression};
use flate2::read::GzDecoder;

use core::{SourceId, Package, PackageId};
use core::dependency::Kind;
use sources::PathSource;
use util::{self, CargoResult, human, internal, ChainError, Config};
use ops;

struct Bomb { path: Option<PathBuf> }

impl Drop for Bomb {
    fn drop(&mut self) {
        match self.path.as_ref() {
            Some(path) => { let _ = fs::remove_file(path); }
            None => {}
        }
    }
}

pub fn package(manifest_path: &Path,
               config: &Config,
               verify: bool,
               list: bool,
               metadata: bool) -> CargoResult<Option<PathBuf>> {
    let mut src = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                            config));
    let pkg = try!(src.root_package());

    if metadata {
        try!(check_metadata(&pkg, config));
    }

    try!(check_dependencies(&pkg, config));

    if list {
        let root = pkg.root();
        let mut list: Vec<_> = try!(src.list_files(&pkg)).iter().map(|file| {
            util::without_prefix(&file, &root).unwrap().to_path_buf()
        }).collect();
        list.sort();
        for file in list.iter() {
            println!("{}", file.display());
        }
        return Ok(None)
    }

    let filename = format!("package/{}-{}.crate", pkg.name(), pkg.version());
    let target_dir = config.target_dir(&pkg);
    let dst = target_dir.join(&filename);
    if fs::metadata(&dst).is_ok() { return Ok(Some(dst)) }

    let mut bomb = Bomb { path: Some(dst.clone()) };

    try!(config.shell().status("Packaging", pkg.package_id().to_string()));
    try!(tar(&pkg, &src, config, &dst).chain_error(|| {
        human("failed to prepare local package for uploading")
    }));
    if verify {
        try!(run_verify(config, &pkg, &dst).chain_error(|| {
            human("failed to verify package tarball")
        }))
    }
    Ok(Some(bomb.path.take().unwrap()))
}

// check that the package has some piece of metadata that a human can
// use to tell what the package is about.
#[allow(deprecated)] // connect => join in 1.3
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
    let md = pkg.manifest().metadata();

    let mut missing = vec![];

    macro_rules! lacking {
        ($( $($field: ident)||* ),*) => {{
            $(
                if $(md.$field.as_ref().map_or(true, |s| s.is_empty()))&&* {
                    $(missing.push(stringify!($field).replace("_", "-"));)*
                }
            )*
        }}
    }
    lacking!(description, license || license_file, documentation || homepage || repository);

    if !missing.is_empty() {
        let mut things = missing[..missing.len() - 1].connect(", ");
        // things will be empty if and only if length == 1 (i.e. the only case
        // to have no `or`).
        if !things.is_empty() {
            things.push_str(" or ");
        }
        things.push_str(&missing.last().unwrap());

        try!(config.shell().warn(
            &format!("warning: manifest has no {things}. \
                    See http://doc.crates.io/manifest.html#package-metadata for more info.",
                    things = things)))
    }
    Ok(())
}

// Warn about wildcard deps which will soon be prohibited on crates.io
#[allow(deprecated)] // connect => join in 1.3
fn check_dependencies(pkg: &Package, config: &Config) -> CargoResult<()> {
    let wildcard = VersionReq::parse("*").unwrap();

    let mut wildcard_deps = vec![];
    for dep in pkg.dependencies() {
        if dep.kind() != Kind::Development && dep.version_req() == &wildcard {
            wildcard_deps.push(dep.name());
        }
    }

    if !wildcard_deps.is_empty() {
        let deps = wildcard_deps.connect(", ");
        try!(config.shell().warn(
            "warning: some dependencies have wildcard (\"*\") version constraints. \
             On December 11th, 2015, crates.io will begin rejecting packages with \
             wildcard dependency constraints. See \
             http://doc.crates.io/crates-io.html#using-crates.io-based-crates \
             for information on version constraints."));
        try!(config.shell().warn(
            &format!("dependencies for these crates have wildcard constraints: {}", deps)));
    }
    Ok(())
}

fn tar(pkg: &Package, src: &PathSource, config: &Config,
       dst: &Path) -> CargoResult<()> {

    if fs::metadata(&dst).is_ok() {
        return Err(human(format!("destination already exists: {}",
                                 dst.display())))
    }

    try!(fs::create_dir_all(dst.parent().unwrap()));

    let tmpfile = try!(File::create(dst));

    // Prepare the encoder and its header
    let filename = Path::new(dst.file_name().unwrap());
    let encoder = GzBuilder::new().filename(try!(util::path2bytes(filename)))
                                  .write(tmpfile, Compression::Best);

    // Put all package files into a compressed archive
    let ar = Archive::new(encoder);
    let root = pkg.root();
    for file in try!(src.list_files(pkg)).iter() {
        if &**file == dst { continue }
        let relative = util::without_prefix(&file, &root).unwrap();
        let relative = try!(relative.to_str().chain_error(|| {
            human(format!("non-utf8 path in source directory: {}",
                          relative.display()))
        }));
        let mut file = try!(File::open(file));
        try!(config.shell().verbose(|shell| {
            shell.status("Archiving", &relative)
        }));
        let path = format!("{}-{}{}{}", pkg.name(), pkg.version(),
                           path::MAIN_SEPARATOR, relative);
        try!(ar.append_file(&path, &mut file).chain_error(|| {
            internal(format!("could not archive source file `{}`", relative))
        }));
    }
    try!(ar.finish());
    Ok(())
}

fn run_verify(config: &Config, pkg: &Package, tar: &Path)
              -> CargoResult<()> {
    try!(config.shell().status("Verifying", pkg));

    let f = try!(GzDecoder::new(try!(File::open(tar))));
    let dst = pkg.root().join(&format!("target/package/{}-{}",
                                       pkg.name(), pkg.version()));
    if fs::metadata(&dst).is_ok() {
        try!(fs::remove_dir_all(&dst));
    }
    let mut archive = Archive::new(f);
    try!(archive.unpack(dst.parent().unwrap()));
    let manifest_path = dst.join("Cargo.toml");

    // When packages are uploaded to the registry, all path dependencies are
    // implicitly converted to registry-based dependencies, so we rewrite those
    // dependencies here.
    //
    // We also make sure to point all paths at `dst` instead of the previous
    // location that the package was originally read from. In locking the
    // `SourceId` we're telling it that the corresponding `PathSource` will be
    // considered updated and we won't actually read any packages.
    let registry = try!(SourceId::for_central(config));
    let precise = Some("locked".to_string());
    let new_src = try!(SourceId::for_path(&dst)).with_precise(precise);
    let new_pkgid = try!(PackageId::new(pkg.name(), pkg.version(), &new_src));
    let new_summary = pkg.summary().clone().map_dependencies(|d| {
        if !d.source_id().is_path() { return d }
        d.clone_inner().set_source_id(registry.clone()).into_dependency()
    });
    let mut new_manifest = pkg.manifest().clone();
    new_manifest.set_summary(new_summary.override_id(new_pkgid));
    let new_pkg = Package::new(new_manifest, &manifest_path);

    // Now that we've rewritten all our path dependencies, compile it!
    try!(ops::compile_pkg(&new_pkg, &ops::CompileOptions {
        config: config,
        jobs: None,
        target: None,
        features: &[],
        no_default_features: false,
        spec: None,
        filter: ops::CompileFilter::Everything,
        exec_engine: None,
        release: false,
        mode: ops::CompileMode::Build,
        target_rustc_args: None,
    }));

    Ok(())
}
<|endoftext|>


<commit_before>use std::any::type_name;

use crate::{
    css_engine::*,
    prelude::*,
    utils::{Brush, String16, Thickness},
};

use dces::prelude::{Component, Entity, EntityComponentManager};

/// The `WidgetContainer` wraps the entity of a widget and provides access to its properties, its children properties and its parent properties.
pub struct WidgetContainer<'a> {
    ecm: &'a mut EntityComponentManager<Tree, StringComponentStore>,
    current_node: Entity,
    theme: &'a ThemeValue,
}

impl<'a> WidgetContainer<'a> {
    /// Creates a new widget container for the given `entity`.
    pub fn new(
        root: Entity,
        ecm: &'a mut EntityComponentManager<Tree, StringComponentStore>,
        theme: &'a ThemeValue,
    ) -> Self {
        WidgetContainer {
            ecm,
            current_node: root,
            theme,
        }
    }

    /// Gets the entity of the widget.
    pub fn entity(&self) -> Entity {
        self.current_node
    }

    /// Gets the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get
(&self, key: &str) -> &P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property;
        }

        let name = self.get_name();

        panic!(
        "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
        name,
        self.current_node.0,
        type_name::
(),
        key
    );
    }

    /// Gets a mutable reference of the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get_mut
(&mut self, key: &str) -> &mut P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}, with key: {}",
            self.current_node.0,
            type_name::
(),
            key
        );
    }

    /// Clones the property. If the property does not exists for the widget the
    /// default of the property value will be returned,
    pub fn clone_or_default
(&self, key: &str) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property.clone();
        }

        P::default()
    }

    /// Clones the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn clone
(&self, key: &str) -> P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property.clone();
        }

        let name = self.get_name();

        panic!(
        "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
        name,
        self.current_node.0,
        type_name::
(),
        key
    );
    }

    /// Clones the property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_clone
(&self, key: &str) -> Option

    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return Some(property.clone());
        }

        None
    }

    /// Sets the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn set
(&mut self, key: &str, value: P)
    where
        P: Component + Clone,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
        {
            *property = value;
            return;
        }

        let name = self.get_name();

        panic!(
            "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
            name,
            self.current_node.0,
            type_name::
(),
            key
        );
    }

    /// Returns `true` if the widget has a property of type `P` otherwise `false`.
    pub fn has
(&self, key: &str) -> bool
    where
        P: Clone + Component,
    {
        self.ecm
            .component_store()
            .get::
(key, self.current_node)
            .is_ok()
    }

    /// Returns a reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get
(&self, key: &str) -> Option<&P> {
        self.ecm
            .component_store()
            .get::
(key, self.current_node)
            .ok()
    }

    /// Returns a mutable reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get_mut
(&mut self, key: &str) -> Option<&mut P> {
        self.ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
            .ok()
    }

    /// Checks if the given value is equal to the given property.
    pub fn eq
(&self, key: &str, other: &P) -> bool {
        if let Some(value) = self.try_get::
(key) {
            return value.eq(other);
        }

        false
    }

    fn update_internal_theme_by_state(&mut self, force: bool, entity: &Entity) {
        for child in &(self.ecm.entity_store().children.clone())[&entity] {
            self.update_internal_theme_by_state(force, child);
        }

        self.current_node = *entity;

        if let Some(selector) = self.try_clone::<Selector>("selector") {
            let mut update = false;

            if let Some(focus) = self.try_clone::<bool>("focused") {
                if focus && !selector.pseudo_classes.contains("focus") {
                    add_selector_to_widget("focus", self);
                    update = true;
                } else if !focus && selector.pseudo_classes.contains("focus") {
                    remove_selector_from_widget("focus", self);
                    update = true;
                }
            }

            if let Some(selected) = self.try_clone::<bool>("selected") {
                if selected && !selector.pseudo_classes.contains("selected") {
                    add_selector_to_widget("selected", self);
                    update = true;
                } else if !selected && selector.pseudo_classes.contains("selected") {
                    remove_selector_from_widget("selected", self);
                    update = true;
                }
            }

            if let Some(pressed) = self.try_clone::<bool>("pressed") {
                if pressed && !selector.pseudo_classes.contains("active") {
                    add_selector_to_widget("active", self);
                    update = true;
                } else if !pressed && selector.pseudo_classes.contains("active") {
                    remove_selector_from_widget("active", self);
                    update = true;
                }
            }

            if let Some(enabled) = self.try_clone::<bool>("enabled") {
                if !enabled && !selector.pseudo_classes.contains("disabled") {
                    add_selector_to_widget("disabled", self);
                    update = true;
                } else if enabled && selector.pseudo_classes.contains("disabled") {
                    remove_selector_from_widget("disabled", self);
                    update = true;
                }
            }

            if let Some(text) = self.try_clone::<String16>("text") {
                if text.is_empty() && !selector.pseudo_classes.contains("empty") {
                    add_selector_to_widget("empty", self);
                    update = true;
                } else if !text.is_empty() && selector.pseudo_classes.contains("empty") {
                    remove_selector_from_widget("empty", self);
                    update = true;
                }
            }

            if let Some(expanded) = self.try_clone::<bool>("expanded") {
                if expanded && !selector.pseudo_classes.contains("expanded") {
                    add_selector_to_widget("expanded", self);
                    update = true;
                } else if !expanded && selector.pseudo_classes.contains("expanded") {
                    remove_selector_from_widget("expanded", self);
                    update = true;
                }
            }

            if update || force {
                self.update_properties_by_theme();
            }
        }
    }

    /// Updates the theme by the inner state e.g. `selected` or `pressed`.
    pub fn update_theme_by_state(&mut self, force: bool) {
        self.update_internal_theme_by_state(force, &(self.current_node.clone()));
    }

    /// Update all properties for the theme.
    pub fn update_properties_by_theme(&mut self) {
        if !self.has::<Selector>("selector") {
            return;
        }

        let selector = self.clone::<Selector>("selector");

        if !selector.dirty() {
            return;
        }

        if self.has::<Brush>("foreground") {
            if let Some(color) = self.theme.brush("color", &selector) {
                self.set::<Brush>("foreground", color);
            }
        }

        if self.has::<Brush>("background") {
            if let Some(background) = self.theme.brush("background", &selector) {
                self.set::<Brush>("background", background);
            }
        }

        if self.has::<Brush>("border_brush") {
            if let Some(border_brush) = self.theme.brush("border-color", &selector) {
                self.set::<Brush>("border_brush", border_brush);
            }
        }

        if self.has::<f64>("border_radius") {
            if let Some(radius) = self.theme.uint("border-radius", &selector) {
                self.set::<f64>("border_radius", f64::from(radius));
            }
        }

        if self.has::<f32>("opacity") {
            if let Some(opacity) = self.theme.float("opacity", &selector) {
                self.set::<f32>("opacity", opacity);
            }
        }

        if self.has::<Thickness>("border_width") {
            if let Some(border_width) = self.theme.uint("border-width", &selector) {
                self.set::<Thickness>("border_width", Thickness::from(border_width as f64));
            }
        }

        self.update_font_properties_by_theme(&selector);

        if let Some(mut padding) = self.try_clone::<Thickness>("padding") {
            if let Some(pad) = self.theme.uint("padding", &selector) {
                padding.set_thickness(pad as f64);
            }

            if let Some(left) = self.theme.uint("padding-left", &selector) {
                padding.set_left(left as f64);
            }

            if let Some(top) = self.theme.uint("padding-top", &selector) {
                padding.set_top(top as f64);
            }

            if let Some(right) = self.theme.uint("padding-right", &selector) {
                padding.set_right(right as f64);
            }

            if let Some(bottom) = self.theme.uint("padding-bottom", &selector) {
                padding.set_bottom(bottom as f64);
            }
            self.set::<Thickness>("padding", padding);
        }

        if let Some(mut constraint) = self.try_clone::<Constraint>("constraint") {
            if let Some(width) = self.theme.uint("width", &selector) {
                constraint.set_width(width as f64);
            }

            if let Some(height) = self.theme.uint("height", &selector) {
                constraint.set_height(height as f64);
            }

            if let Some(min_width) = self.theme.uint("min-width", &selector) {
                constraint.set_min_width(min_width as f64);
            }

            if let Some(min_height) = self.theme.uint("min-height", &selector) {
                constraint.set_min_height(min_height as f64);
            }

            if let Some(max_width) = self.theme.uint("max-width", &selector) {
                constraint.set_max_width(max_width as f64);
            }

            if let Some(max_height) = self.theme.uint("max-height", &selector) {
                constraint.set_max_height(max_height as f64);
            }

            self.set::<Constraint>("constraint", constraint);
        }

        if self.has::<f64>("spacing") {
            if let Some(spacing) = self.theme.uint("spacing", &selector) {
                self.set::<f64>("spacing", spacing.into());
            }
        }

        self.get_mut::<Selector>("selector").set_dirty(true);
    }

    pub fn update_font_properties_by_theme(&mut self, selector: &Selector) {
        if self.has::<f64>("font_size") {
            if let Some(size) = self.theme.uint("font-size", selector) {
                self.set::<f64>("font_size", f64::from(size));
            }
        }

        if self.has::<String>("font_family") {
            if let Some(font_family) = self.theme.string("font-family", selector) {
                self.set::<String>("font_family", font_family);
            }
        }

        if self.has::<Brush>("icon_brush") {
            if let Some(color) = self.theme.brush("icon-color", selector) {
                self.set::<Brush>("icon_brush", color);
            }
        }

        if self.has::<f64>("icon_size") {
            if let Some(size) = self.theme.uint("icon-size", selector) {
                self.set::<f64>("icon_size", f64::from(size));
            }
        }

        if self.has::<String>("icon_family") {
            if let Some(font_family) = self.theme.string("icon-family", selector) {
                self.set::<String>("icon_family", font_family);
            }
        }
    }

    fn get_name(&self) -> String {
        if self.has::<String>("name") {
            self
            .ecm
            .component_store()
            .get::<String>("name", self.current_node)
            .unwrap()
            .clone()
        } else {
            String::from("unknown")
        }
    }
}
<commit_msg>widget_container: typo cleanup<commit_after>use std::any::type_name;

use crate::{
    css_engine::*,
    prelude::*,
    utils::{Brush, String16, Thickness},
};

use dces::prelude::{Component, Entity, EntityComponentManager};

/// The `WidgetContainer` wraps the entity of a widget and provides access to its properties, its children properties and its parent properties.
pub struct WidgetContainer<'a> {
    ecm: &'a mut EntityComponentManager<Tree, StringComponentStore>,
    current_node: Entity,
    theme: &'a ThemeValue,
}

impl<'a> WidgetContainer<'a> {
    /// Creates a new widget container for the given `entity`.
    pub fn new(
        root: Entity,
        ecm: &'a mut EntityComponentManager<Tree, StringComponentStore>,
        theme: &'a ThemeValue,
    ) -> Self {
        WidgetContainer {
            ecm,
            current_node: root,
            theme,
        }
    }

    /// Gets the entity of the widget.
    pub fn entity(&self) -> Entity {
        self.current_node
    }

    /// Gets the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get
(&self, key: &str) -> &P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property;
        }

        let name = self.get_name();

        panic!(
        "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
        name,
        self.current_node.0,
        type_name::
(),
        key
    );
    }

    /// Gets a mutable reference of the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contain the property.
    pub fn get_mut
(&mut self, key: &str) -> &mut P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}, with key: {}",
            self.current_node.0,
            type_name::
(),
            key
        );
    }

    /// Clones the property. If the property does not exists for the widget the
    /// default of the property value will be returned,
    pub fn clone_or_default
(&self, key: &str) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property.clone();
        }

        P::default()
    }

    /// Clones the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn clone
(&self, key: &str) -> P
    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return property.clone();
        }

        let name = self.get_name();

        panic!(
        "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
        name,
        self.current_node.0,
        type_name::
(),
        key
    );
    }

    /// Clones the property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_clone
(&self, key: &str) -> Option

    where
        P: Clone + Component,
    {
        if let Ok(property) = self.ecm.component_store().get::
(key, self.current_node) {
            return Some(property.clone());
        }

        None
    }

    /// Sets the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn set
(&mut self, key: &str, value: P)
    where
        P: Component + Clone,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
        {
            *property = value;
            return;
        }

        let name = self.get_name();

        panic!(
            "Widget: {} with entity: {} does not contain property with type {:?} for key: {}",
            name,
            self.current_node.0,
            type_name::
(),
            key
        );
    }

    /// Returns `true` if the widget has a property of type `P` otherwise `false`.
    pub fn has
(&self, key: &str) -> bool
    where
        P: Clone + Component,
    {
        self.ecm
            .component_store()
            .get::
(key, self.current_node)
            .is_ok()
    }

    /// Returns a reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get
(&self, key: &str) -> Option<&P> {
        self.ecm
            .component_store()
            .get::
(key, self.current_node)
            .ok()
    }

    /// Returns a mutable reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get_mut
(&mut self, key: &str) -> Option<&mut P> {
        self.ecm
            .component_store_mut()
            .get_mut::
(key, self.current_node)
            .ok()
    }

    /// Checks if the given value is equal to the given property.
    pub fn eq
(&self, key: &str, other: &P) -> bool {
        if let Some(value) = self.try_get::
(key) {
            return value.eq(other);
        }

        false
    }

    fn update_internal_theme_by_state(&mut self, force: bool, entity: &Entity) {
        for child in &(self.ecm.entity_store().children.clone())[&entity] {
            self.update_internal_theme_by_state(force, child);
        }

        self.current_node = *entity;

        if let Some(selector) = self.try_clone::<Selector>("selector") {
            let mut update = false;

            if let Some(focus) = self.try_clone::<bool>("focused") {
                if focus && !selector.pseudo_classes.contains("focus") {
                    add_selector_to_widget("focus", self);
                    update = true;
                } else if !focus && selector.pseudo_classes.contains("focus") {
                    remove_selector_from_widget("focus", self);
                    update = true;
                }
            }

            if let Some(selected) = self.try_clone::<bool>("selected") {
                if selected && !selector.pseudo_classes.contains("selected") {
                    add_selector_to_widget("selected", self);
                    update = true;
                } else if !selected && selector.pseudo_classes.contains("selected") {
                    remove_selector_from_widget("selected", self);
                    update = true;
                }
            }

            if let Some(pressed) = self.try_clone::<bool>("pressed") {
                if pressed && !selector.pseudo_classes.contains("active") {
                    add_selector_to_widget("active", self);
                    update = true;
                } else if !pressed && selector.pseudo_classes.contains("active") {
                    remove_selector_from_widget("active", self);
                    update = true;
                }
            }

            if let Some(enabled) = self.try_clone::<bool>("enabled") {
                if !enabled && !selector.pseudo_classes.contains("disabled") {
                    add_selector_to_widget("disabled", self);
                    update = true;
                } else if enabled && selector.pseudo_classes.contains("disabled") {
                    remove_selector_from_widget("disabled", self);
                    update = true;
                }
            }

            if let Some(text) = self.try_clone::<String16>("text") {
                if text.is_empty() && !selector.pseudo_classes.contains("empty") {
                    add_selector_to_widget("empty", self);
                    update = true;
                } else if !text.is_empty() && selector.pseudo_classes.contains("empty") {
                    remove_selector_from_widget("empty", self);
                    update = true;
                }
            }

            if let Some(expanded) = self.try_clone::<bool>("expanded") {
                if expanded && !selector.pseudo_classes.contains("expanded") {
                    add_selector_to_widget("expanded", self);
                    update = true;
                } else if !expanded && selector.pseudo_classes.contains("expanded") {
                    remove_selector_from_widget("expanded", self);
                    update = true;
                }
            }

            if update || force {
                self.update_properties_by_theme();
            }
        }
    }

    /// Updates the theme by the inner state e.g. `selected` or `pressed`.
    pub fn update_theme_by_state(&mut self, force: bool) {
        self.update_internal_theme_by_state(force, &(self.current_node.clone()));
    }

    /// Update all properties for the theme.
    pub fn update_properties_by_theme(&mut self) {
        if !self.has::<Selector>("selector") {
            return;
        }

        let selector = self.clone::<Selector>("selector");

        if !selector.dirty() {
            return;
        }

        if self.has::<Brush>("foreground") {
            if let Some(color) = self.theme.brush("color", &selector) {
                self.set::<Brush>("foreground", color);
            }
        }

        if self.has::<Brush>("background") {
            if let Some(background) = self.theme.brush("background", &selector) {
                self.set::<Brush>("background", background);
            }
        }

        if self.has::<Brush>("border_brush") {
            if let Some(border_brush) = self.theme.brush("border-color", &selector) {
                self.set::<Brush>("border_brush", border_brush);
            }
        }

        if self.has::<f64>("border_radius") {
            if let Some(radius) = self.theme.uint("border-radius", &selector) {
                self.set::<f64>("border_radius", f64::from(radius));
            }
        }

        if self.has::<f32>("opacity") {
            if let Some(opacity) = self.theme.float("opacity", &selector) {
                self.set::<f32>("opacity", opacity);
            }
        }

        if self.has::<Thickness>("border_width") {
            if let Some(border_width) = self.theme.uint("border-width", &selector) {
                self.set::<Thickness>("border_width", Thickness::from(border_width as f64));
            }
        }

        self.update_font_properties_by_theme(&selector);

        if let Some(mut padding) = self.try_clone::<Thickness>("padding") {
            if let Some(pad) = self.theme.uint("padding", &selector) {
                padding.set_thickness(pad as f64);
            }

            if let Some(left) = self.theme.uint("padding-left", &selector) {
                padding.set_left(left as f64);
            }

            if let Some(top) = self.theme.uint("padding-top", &selector) {
                padding.set_top(top as f64);
            }

            if let Some(right) = self.theme.uint("padding-right", &selector) {
                padding.set_right(right as f64);
            }

            if let Some(bottom) = self.theme.uint("padding-bottom", &selector) {
                padding.set_bottom(bottom as f64);
            }
            self.set::<Thickness>("padding", padding);
        }

        if let Some(mut constraint) = self.try_clone::<Constraint>("constraint") {
            if let Some(width) = self.theme.uint("width", &selector) {
                constraint.set_width(width as f64);
            }

            if let Some(height) = self.theme.uint("height", &selector) {
                constraint.set_height(height as f64);
            }

            if let Some(min_width) = self.theme.uint("min-width", &selector) {
                constraint.set_min_width(min_width as f64);
            }

            if let Some(min_height) = self.theme.uint("min-height", &selector) {
                constraint.set_min_height(min_height as f64);
            }

            if let Some(max_width) = self.theme.uint("max-width", &selector) {
                constraint.set_max_width(max_width as f64);
            }

            if let Some(max_height) = self.theme.uint("max-height", &selector) {
                constraint.set_max_height(max_height as f64);
            }

            self.set::<Constraint>("constraint", constraint);
        }

        if self.has::<f64>("spacing") {
            if let Some(spacing) = self.theme.uint("spacing", &selector) {
                self.set::<f64>("spacing", spacing.into());
            }
        }

        self.get_mut::<Selector>("selector").set_dirty(true);
    }

    pub fn update_font_properties_by_theme(&mut self, selector: &Selector) {
        if self.has::<f64>("font_size") {
            if let Some(size) = self.theme.uint("font-size", selector) {
                self.set::<f64>("font_size", f64::from(size));
            }
        }

        if self.has::<String>("font_family") {
            if let Some(font_family) = self.theme.string("font-family", selector) {
                self.set::<String>("font_family", font_family);
            }
        }

        if self.has::<Brush>("icon_brush") {
            if let Some(color) = self.theme.brush("icon-color", selector) {
                self.set::<Brush>("icon_brush", color);
            }
        }

        if self.has::<f64>("icon_size") {
            if let Some(size) = self.theme.uint("icon-size", selector) {
                self.set::<f64>("icon_size", f64::from(size));
            }
        }

        if self.has::<String>("icon_family") {
            if let Some(font_family) = self.theme.string("icon-family", selector) {
                self.set::<String>("icon_family", font_family);
            }
        }
    }

    fn get_name(&self) -> String {
        if self.has::<String>("name") {
            self
            .ecm
            .component_store()
            .get::<String>("name", self.current_node)
            .unwrap()
            .clone()
        } else {
            String::from("unknown")
        }
    }
}
<|endoftext|>