<commit_before>use core::layer::Layer;
use core::feature::Feature;
use core::grid::Extent;
use core::geom::GeometryType;
use core::geom;
use core::screen;
use mvt::vector_tile;
use mvt::geom_to_proto::{EncodableGeom,CommandSequence};

pub struct Tile<'a> {
    pub mvt_tile: vector_tile::Tile,
    tile_size: u32,
    extent: &'a Extent,
    feature_id: u64,
}

// --- conversion of geometries into screen coordinates

trait ScreenGeom<T> {
    fn from_geom(extent: &Extent, tile_size: u32, geom: T) -> Self;
}

impl ScreenGeom<geom::Point> for screen::Point {
    fn from_geom(extent: &Extent, tile_size: u32, point: geom::Point) -> Self {
        let x_span = extent.maxx - extent.minx;
        let y_span = extent.maxy - extent.miny;
        screen::Point {
            x: ((point.x-extent.minx) * tile_size as f64 / x_span) as i32,
            y: ((point.y-extent.miny) * tile_size as f64 / y_span) as i32
        }
    }
}

#[test]
fn test_point_to_screen_coords() {
    //let zh_mercator = geom::Point::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::new(960000.0, 6002729.0);
    //let zh_wgs84 = postgis::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = screen::Point::from_geom(&tile_extent, 4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}

// --- Tile creation functions

impl<'a> Tile<'a> {
    pub fn new(extent: &Extent, tile_size: u32) -> Tile {
        let mvt_tile = vector_tile::Tile::new();
        Tile {mvt_tile: mvt_tile, tile_size: tile_size, extent: extent, feature_id: 0 }
    }

    pub fn new_layer(&mut self, layer: Layer) -> vector_tile::Tile_Layer {
        vector_tile::Tile_Layer::new()
    }

    pub fn new_feature(&self, feature: Feature) -> vector_tile::Tile_Feature {
        vector_tile::Tile_Feature::new()
    }

    pub fn encode_geom(&self, geom: geom::GeometryType) -> CommandSequence {
        let screen_geom = match geom {
            GeometryType::Point(p) => screen::Point::from_geom(&self.extent, self.tile_size, p),
            _ => panic!("Geometry type not implemented yet")
        };
        screen_geom.encode()
    }

    pub fn add_layer(&mut self, mvt_layer: vector_tile::Tile_Layer) {

    }
}

#[test]
fn test_tile_values() {
    let mut value = vector_tile::Tile_Value::new();
    assert_eq!(value, Default::default());
    assert!(!value.has_string_value());
    value.set_string_value(String::from("Hello, world!"));
    println!("{:?}", value);
    assert!(value.has_string_value());
    assert_eq!(value.get_string_value(), String::from("Hello, world!"));
}

#[test]
fn test_read_pbf_file() {
    use std::fs::File;
    use std::io::BufReader;
    use protobuf::parse_from_reader;

    let f = File::open("src/test/tile.pbf").unwrap();
    // Command line decoding:
    // protoc --decode=vector_tile.Tile src/mvt/vector_tile.proto <src/test/tile.pbf
    let mut reader = BufReader::new(f);
    let tile = parse_from_reader::<vector_tile::Tile>(&mut reader).unwrap();
    println!("{:#?}", tile);
    let ref layer = tile.get_layers()[0];
    assert_eq!(layer.get_name(), "roads");
    let ref feature = layer.get_features()[1];
    assert_eq!(feature.get_field_type(), vector_tile::Tile_GeomType::POLYGON);
    let ref geometry = feature.get_geometry();
    assert_eq!(geometry, &[9,8236,4926,34,9,24,37,21,10,7,4,19,15]);
}

struct FeatureAttributes {
    keys: Vec<String>,
    values: Vec<String>,
}

impl FeatureAttributes {
    fn new() -> FeatureAttributes {
        FeatureAttributes { keys: Vec::<String>::new(), values: Vec::<String>::new() }
    }
    fn add_attribute(&mut self, key: String, value: String) -> (u32, u32) {
        let keyentry = self.keys.iter().position(|k| *k == key);
        let keyidx = match keyentry {
            None => {
                self.keys.push(key);
                self.keys.len()-1
            },
            Some(idx) => idx
        };
        let valentry = self.values.iter().position(|v| *v == value);
        let validx = match valentry {
            None => {
                self.values.push(value);
                self.values.len()-1
            },
            Some(idx) => idx
        };
        (keyidx as u32, validx as u32)
    }
}

#[test]
fn test_create_pbf() {
    // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#45-example
    let mut tile = vector_tile::Tile::new();

    let mut layer = vector_tile::Tile_Layer::new();
    layer.set_version(2);
    layer.set_name(String::from("points"));
    layer.set_extent(4096);

    let mut feature_id = 1;
    let mut feature = vector_tile::Tile_Feature::new();
    feature.set_id(feature_id);
    feature.set_field_type(vector_tile::Tile_GeomType::POINT);
    feature.set_geometry([9, 2410, 3080].to_vec());

    let mut attrs = FeatureAttributes::new();
    let (keyidx, validx) = attrs.add_attribute(
        String::from("hello"), String::from("world"));
    feature.mut_tags().push(keyidx);
    feature.mut_tags().push(validx);
    let (keyidx, validx) = attrs.add_attribute(
        String::from("h"), String::from("world"));
    feature.mut_tags().push(keyidx);
    feature.mut_tags().push(validx);
    let (keyidx, validx) = attrs.add_attribute(
        String::from("count"), String::from("1.23")); // FIXME: double_value
    feature.mut_tags().push(keyidx);
    feature.mut_tags().push(validx);

    layer.mut_features().push(feature);

    feature_id += 1;
    feature = vector_tile::Tile_Feature::new();
    feature.set_id(feature_id);
    feature.set_field_type(vector_tile::Tile_GeomType::POINT);
    feature.set_geometry([9, 2410, 3080].to_vec());

    let (keyidx, validx) = attrs.add_attribute(
        String::from("hello"), String::from("again"));
    feature.mut_tags().push(keyidx);
    feature.mut_tags().push(validx);
    let (keyidx, validx) = attrs.add_attribute(
        String::from("count"), String::from("2")); // FIXME: int_value
    feature.mut_tags().push(keyidx);
    feature.mut_tags().push(validx);

    layer.mut_features().push(feature);

    for key in attrs.keys.iter() {
        layer.mut_keys().push(key.clone());
    }
    for val in attrs.values.iter() {
        let mut value = vector_tile::Tile_Value::new();
        value.set_string_value(val.clone());
        layer.mut_values().push(value);
    }

    tile.mut_layers().push(layer);
    println!("{:#?}", tile);
    let expected = "Tile {
    layers: [
        Tile_Layer {
            version: Some(
                2
            ),
            name: Some(\"points\"),
            features: [
                Tile_Feature {
                    id: Some(
                        1
                    ),
                    tags: [
                        0,
                        0,
                        1,
                        0,
                        2,
                        1
                    ],
                    field_type: Some(
                        POINT
                    ),
                    geometry: [
                        9,
                        2410,
                        3080
                    ],
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Feature {
                    id: Some(
                        2
                    ),
                    tags: [
                        0,
                        2,
                        2,
                        3
                    ],
                    field_type: Some(
                        POINT
                    ),
                    geometry: [
                        9,
                        2410,
                        3080
                    ],
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                }
            ],
            keys: [
                \"hello\",
                \"h\",
                \"count\"
            ],
            values: [
                Tile_Value {
                    string_value: Some(\"world\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"1.23\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"again\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"2\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                }
            ],
            extent: Some(
                4096
            ),
            unknown_fields: UnknownFields {
                fields: None
            },
            cached_size: Cell { value: 0 }
        }
    ],
    unknown_fields: UnknownFields {
        fields: None
    },
    cached_size: Cell { value: 0 }
}";
    assert_eq!(expected, &*format!("{:#?}", tile));
}
<commit_msg>add_feature_attribute helper<commit_after>use core::layer::Layer;
use core::feature::Feature;
use core::grid::Extent;
use core::geom::GeometryType;
use core::geom;
use core::screen;
use mvt::vector_tile;
use mvt::geom_to_proto::{EncodableGeom,CommandSequence};

pub struct Tile<'a> {
    pub mvt_tile: vector_tile::Tile,
    tile_size: u32,
    extent: &'a Extent,
    feature_id: u64,
}

// --- conversion of geometries into screen coordinates

trait ScreenGeom<T> {
    fn from_geom(extent: &Extent, tile_size: u32, geom: T) -> Self;
}

impl ScreenGeom<geom::Point> for screen::Point {
    fn from_geom(extent: &Extent, tile_size: u32, point: geom::Point) -> Self {
        let x_span = extent.maxx - extent.minx;
        let y_span = extent.maxy - extent.miny;
        screen::Point {
            x: ((point.x-extent.minx) * tile_size as f64 / x_span) as i32,
            y: ((point.y-extent.miny) * tile_size as f64 / y_span) as i32
        }
    }
}

#[test]
fn test_point_to_screen_coords() {
    //let zh_mercator = geom::Point::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::new(960000.0, 6002729.0);
    //let zh_wgs84 = postgis::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = screen::Point::from_geom(&tile_extent, 4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}

// --- Tile creation functions

impl<'a> Tile<'a> {
    pub fn new(extent: &Extent, tile_size: u32) -> Tile {
        let mvt_tile = vector_tile::Tile::new();
        Tile {mvt_tile: mvt_tile, tile_size: tile_size, extent: extent, feature_id: 0 }
    }

    pub fn new_layer(&mut self, layer: Layer) -> vector_tile::Tile_Layer {
        vector_tile::Tile_Layer::new()
    }

    pub fn new_feature(&self, feature: Feature) -> vector_tile::Tile_Feature {
        vector_tile::Tile_Feature::new()
    }

    pub fn encode_geom(&self, geom: geom::GeometryType) -> CommandSequence {
        let screen_geom = match geom {
            GeometryType::Point(p) => screen::Point::from_geom(&self.extent, self.tile_size, p),
            _ => panic!("Geometry type not implemented yet")
        };
        screen_geom.encode()
    }

    fn add_feature_attribute(mvt_layer: &mut vector_tile::Tile_Layer,
                     mvt_feature: &mut vector_tile::Tile_Feature,
                     key: String, value: String) {
        let keyentry = mvt_layer.get_keys().iter().position(|k| *k == key);
        // Optimization: maintain a hash table with key/index pairs
        let keyidx = match keyentry {
            None => {
                mvt_layer.mut_keys().push(key.clone());
                mvt_layer.get_keys().len()-1
            },
            Some(idx) => idx
        };
        mvt_feature.mut_tags().push(keyidx as u32);

        let valentry = mvt_layer.get_values().iter().position(|v| v.get_string_value() == value);
        // Optimization: maintain a hash table with value/index pairs
        let validx = match valentry {
            None => {
                let mut mvt_value = vector_tile::Tile_Value::new();
                mvt_value.set_string_value(value.clone());
                mvt_layer.mut_values().push(mvt_value);
                mvt_layer.get_values().len()-1
            },
            Some(idx) => idx
        };
        mvt_feature.mut_tags().push(validx as u32);
    }

    pub fn add_layer(&mut self, mvt_layer: vector_tile::Tile_Layer) {

    }
}

#[test]
fn test_tile_values() {
    let mut value = vector_tile::Tile_Value::new();
    assert_eq!(value, Default::default());
    assert!(!value.has_string_value());
    value.set_string_value(String::from("Hello, world!"));
    println!("{:?}", value);
    assert!(value.has_string_value());
    assert_eq!(value.get_string_value(), String::from("Hello, world!"));
}

#[test]
fn test_read_pbf_file() {
    use std::fs::File;
    use std::io::BufReader;
    use protobuf::parse_from_reader;

    let f = File::open("src/test/tile.pbf").unwrap();
    // Command line decoding:
    // protoc --decode=vector_tile.Tile src/mvt/vector_tile.proto <src/test/tile.pbf
    let mut reader = BufReader::new(f);
    let tile = parse_from_reader::<vector_tile::Tile>(&mut reader).unwrap();
    println!("{:#?}", tile);
    let ref layer = tile.get_layers()[0];
    assert_eq!(layer.get_name(), "roads");
    let ref feature = layer.get_features()[1];
    assert_eq!(feature.get_field_type(), vector_tile::Tile_GeomType::POLYGON);
    let ref geometry = feature.get_geometry();
    assert_eq!(geometry, &[9,8236,4926,34,9,24,37,21,10,7,4,19,15]);
}

#[test]
fn test_create_pbf() {
    // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#45-example
    let mut mvt_tile = vector_tile::Tile::new();

    let mut mvt_layer = vector_tile::Tile_Layer::new();
    mvt_layer.set_version(2);
    mvt_layer.set_name(String::from("points"));
    mvt_layer.set_extent(4096);

    let mut mvt_feature = vector_tile::Tile_Feature::new();
    mvt_feature.set_id(1);
    mvt_feature.set_field_type(vector_tile::Tile_GeomType::POINT);
    mvt_feature.set_geometry([9, 2410, 3080].to_vec());

    Tile::add_feature_attribute(&mut mvt_layer, &mut mvt_feature,
        String::from("hello"), String::from("world"));
    Tile::add_feature_attribute(&mut mvt_layer, &mut mvt_feature,
        String::from("h"), String::from("world"));
    Tile::add_feature_attribute(&mut mvt_layer, &mut mvt_feature,
        String::from("count"), String::from("1.23")); // FIXME: double_value

    mvt_layer.mut_features().push(mvt_feature);

    mvt_feature = vector_tile::Tile_Feature::new();
    mvt_feature.set_id(2);
    mvt_feature.set_field_type(vector_tile::Tile_GeomType::POINT);
    mvt_feature.set_geometry([9, 2410, 3080].to_vec());

    Tile::add_feature_attribute(&mut mvt_layer, &mut mvt_feature,
        String::from("hello"), String::from("again"));
    Tile::add_feature_attribute(&mut mvt_layer, &mut mvt_feature,
        String::from("count"), String::from("2")); // FIXME: int_value

    mvt_layer.mut_features().push(mvt_feature);

    mvt_tile.mut_layers().push(mvt_layer);
    println!("{:#?}", mvt_tile);
    let expected = "Tile {
    layers: [
        Tile_Layer {
            version: Some(
                2
            ),
            name: Some(\"points\"),
            features: [
                Tile_Feature {
                    id: Some(
                        1
                    ),
                    tags: [
                        0,
                        0,
                        1,
                        0,
                        2,
                        1
                    ],
                    field_type: Some(
                        POINT
                    ),
                    geometry: [
                        9,
                        2410,
                        3080
                    ],
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Feature {
                    id: Some(
                        2
                    ),
                    tags: [
                        0,
                        2,
                        2,
                        3
                    ],
                    field_type: Some(
                        POINT
                    ),
                    geometry: [
                        9,
                        2410,
                        3080
                    ],
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                }
            ],
            keys: [
                \"hello\",
                \"h\",
                \"count\"
            ],
            values: [
                Tile_Value {
                    string_value: Some(\"world\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"1.23\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"again\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                },
                Tile_Value {
                    string_value: Some(\"2\"),
                    float_value: None,
                    double_value: None,
                    int_value: None,
                    uint_value: None,
                    sint_value: None,
                    bool_value: None,
                    unknown_fields: UnknownFields {
                        fields: None
                    },
                    cached_size: Cell { value: 0 }
                }
            ],
            extent: Some(
                4096
            ),
            unknown_fields: UnknownFields {
                fields: None
            },
            cached_size: Cell { value: 0 }
        }
    ],
    unknown_fields: UnknownFields {
        fields: None
    },
    cached_size: Cell { value: 0 }
}";
    assert_eq!(expected, &*format!("{:#?}", mvt_tile));
}
<|endoftext|>


<commit_before>use chan::Sender;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io;
use std::path::PathBuf;

use datatype::{Config, DeviceReport, Error, Event, PendingUpdateRequest,
               UpdateRequestId, UpdateReport, UpdateResultCode, UpdateState, Url};
use http::Client;

/// Encapsulate the client configuration and HTTP client used for over-the-air
/// communication.
pub struct OTA<'c, 'h> {
    config: &'c Config,
    client: &'h Client,
}

impl<'c, 'h> OTA<'c, 'h> {
    /// Creates a new instance for OTA communication.
    pub fn new(config: &'c Config, client: &'h Client) -> OTA<'c, 'h> {
        OTA { config: config, client: client }
    }

    /// Takes a path and returns a new endpoint of the format
    /// `<Core server>/api/v1/vehicle_updates/<uuid>/<path>`.
    pub fn endpoint(&self, path: &str) -> Url {
        let endpoint = if path.is_empty() {
            format!("/api/v1/vehicle_updates/{}", self.config.device.uuid)
        } else {
            format!("/api/v1/vehicle_updates/{}/{}", self.config.device.uuid, path)
        };
        self.config.core.server.join(&endpoint).expect("couldn't build endpoint url")
    }

    /// Query the Core server to identify any new package updates available.
    pub fn get_package_updates(&mut self) -> Result<Vec<PendingUpdateRequest>, Error> {
        debug!("getting package updates");
        let resp_rx = self.client.get(self.endpoint(""), None);
        let resp    = resp_rx.recv().expect("no get_package_updates response received");
        let data    = try!(resp);
        let text    = try!(String::from_utf8(data));
        Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&text)))
    }

    /// Download a specific update from the Core server.
    pub fn download_package_update(&mut self, id: UpdateRequestId) -> Result<PathBuf, Error> {
        debug!("downloading package update: {}", id);
        let resp_rx = self.client.get(self.endpoint(&format!("{}/download", id)), None);
        let resp    = resp_rx.recv().expect("no download_package_update response received");
        let data    = try!(resp);

        let mut path = PathBuf::new();
        path.push(&self.config.device.packages_dir);
        path.push(id); // TODO: Use Content-Disposition filename from request?
        let mut file = try!(File::create(path.as_path()));
        let _        = io::copy(&mut &*data, &mut file);
        Ok(path)
    }

    /// Download and install an update, sending `Event::UpdateStateChanged`
    /// notifications at each step.
    pub fn install_package_update(&mut self, id: UpdateRequestId, etx: &Sender<Event>) -> Result<UpdateReport, Error> {
        debug!("installing package update: {}", id);
        self.download_package_update(id.clone()).and_then(|path| {
            let err_str  = format!("Path is not valid UTF-8: {:?}", path);
            let pkg_path = try!(path.to_str().ok_or(Error::Parse(err_str)));
            info!("Downloaded to {:?}. Installing...", pkg_path);

            // TODO: Fire DownloadComplete event, handle async UpdateReport command
            // TODO: Do not invoke package_manager
            etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));
            self.config.device.package_manager.install_package(pkg_path).and_then(|(code, output)| {
                etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                Ok(UpdateReport::single(id.clone(), code, output))
            }).or_else(|(code, output)| {
                etx.send(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output)));
                Ok(UpdateReport::single(id.clone(), code, output))
            })
        }).or_else(|err| {
            etx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err)));
            let failed = format!("Download failed: {:?}", err);
            Ok(UpdateReport::single(id.clone(), UpdateResultCode::GENERAL_ERROR, failed))
        })
    }

    /// Send a list of the currently installed packages to the Core server.
    pub fn update_installed_packages(&mut self) -> Result<(), Error> {
        debug!("updating installed packages");
        // TODO: Fire GetInstalledSoftware event, handle async InstalledSoftware command
        // TODO: Do not invoke package_manager
        let pkgs    = try!(self.config.device.package_manager.installed_packages());
        let body    = try!(json::encode(&pkgs));
        let resp_rx = self.client.put(self.endpoint("installed"), Some(body.into_bytes()));
        let _       = resp_rx.recv().expect("no update_installed_packages response received")
                             .map_err(|err| error!("update_installed_packages failed: {}", err));
        Ok(())
    }

    /// Send the outcome of a package installation to the Core server.
    pub fn send_install_report(&mut self, update_report: &UpdateReport) -> Result<(), Error> {
        debug!("sending installation report");
        let report  = DeviceReport::new(&self.config.device.uuid, update_report);
        let body    = try!(json::encode(&report));
        let url     = self.endpoint(report.device);
        let resp_rx = self.client.post(url, Some(body.into_bytes()));
        let resp    = resp_rx.recv().expect("no send_install_report response received");
        let _       = try!(resp);
        Ok(())
    }

    /// Send system information from the device to the Core server.
    pub fn send_system_info(&mut self, info: &Json) -> Result<(), Error> {
        debug!("sending system info");
        let body    = try!(json::encode(info));
        let resp_rx = self.client.put(self.endpoint("system_info"), Some(body.into_bytes()));
        let resp    = resp_rx.recv().expect("no send_system_info response received");
        let _       = try!(resp);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Event, Package, PendingUpdateRequest, UpdateResultCode, UpdateState};
    use http::TestClient;
    use package_manager::PackageManager;
    use package_manager::tpm::{assert_rx, TestDir};

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json    = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::from(vec![json.to_string()]),
        };

        let updates: Vec<PendingUpdateRequest> = ota.get_package_updates().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }

    #[test]
    fn bad_client_download_package_update() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::default(),
        };
        let expect  = format!("Http client error: {}", ota.endpoint("0/download").to_string());
        assert_eq!(expect, format!("{}", ota.download_package_update("0".to_string()).unwrap_err()));
    }

    #[test]
    fn test_install_package_update_0() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::default(),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::GENERAL_ERROR,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        let expect = format!(r#"Client("{}")"#, ota.endpoint("0/download").to_string());
        assert_rx(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(expect))
        ]);
    }

    #[test]
    fn test_install_package_update_1() {
        let mut config = Config::default();
        let test_dir   = TestDir::new("sota-test-install-1");
        config.device.packages_dir    = test_dir.0.clone();
        config.device.package_manager = PackageManager::new_tpm(false);

        let mut ota = OTA {
            config: &config,
            client: &mut TestClient::from(vec!["".to_string()]),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::INSTALL_FAILED,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), r#"INSTALL_FAILED: "failed""#.to_string())
        ]);
    }

    #[test]
    fn test_install_package_update_2() {
        let mut config = Config::default();
        let test_dir   = TestDir::new("sota-test-install-2");
        config.device.packages_dir    = test_dir.0.clone();
        config.device.package_manager = PackageManager::new_tpm(true);

        let replies = vec![
            "[]".to_string(),
            "package data".to_string(),
        ];
        let mut ota = OTA {
            config: &config,
            client: &mut TestClient::from(replies),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::OK,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)
        ]);
    }
}
<commit_msg>[PRO-1064] Change from vehicle_updates to device_updates as endpoint<commit_after>use chan::Sender;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io;
use std::path::PathBuf;

use datatype::{Config, DeviceReport, Error, Event, PendingUpdateRequest,
               UpdateRequestId, UpdateReport, UpdateResultCode, UpdateState, Url};
use http::Client;

/// Encapsulate the client configuration and HTTP client used for over-the-air
/// communication.
pub struct OTA<'c, 'h> {
    config: &'c Config,
    client: &'h Client,
}

impl<'c, 'h> OTA<'c, 'h> {
    /// Creates a new instance for OTA communication.
    pub fn new(config: &'c Config, client: &'h Client) -> OTA<'c, 'h> {
        OTA { config: config, client: client }
    }

    /// Takes a path and returns a new endpoint of the format
    /// `<Core server>/api/v1/device_updates/<uuid>/<path>`.
    pub fn endpoint(&self, path: &str) -> Url {
        let endpoint = if path.is_empty() {
            format!("/api/v1/device_updates/{}", self.config.device.uuid)
        } else {
            format!("/api/v1/device_updates/{}/{}", self.config.device.uuid, path)
        };
        self.config.core.server.join(&endpoint).expect("couldn't build endpoint url")
    }

    /// Query the Core server to identify any new package updates available.
    pub fn get_package_updates(&mut self) -> Result<Vec<PendingUpdateRequest>, Error> {
        debug!("getting package updates");
        let resp_rx = self.client.get(self.endpoint(""), None);
        let resp    = resp_rx.recv().expect("no get_package_updates response received");
        let data    = try!(resp);
        let text    = try!(String::from_utf8(data));
        Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&text)))
    }

    /// Download a specific update from the Core server.
    pub fn download_package_update(&mut self, id: UpdateRequestId) -> Result<PathBuf, Error> {
        debug!("downloading package update: {}", id);
        let resp_rx = self.client.get(self.endpoint(&format!("{}/download", id)), None);
        let resp    = resp_rx.recv().expect("no download_package_update response received");
        let data    = try!(resp);

        let mut path = PathBuf::new();
        path.push(&self.config.device.packages_dir);
        path.push(id); // TODO: Use Content-Disposition filename from request?
        let mut file = try!(File::create(path.as_path()));
        let _        = io::copy(&mut &*data, &mut file);
        Ok(path)
    }

    /// Download and install an update, sending `Event::UpdateStateChanged`
    /// notifications at each step.
    pub fn install_package_update(&mut self, id: UpdateRequestId, etx: &Sender<Event>) -> Result<UpdateReport, Error> {
        debug!("installing package update: {}", id);
        self.download_package_update(id.clone()).and_then(|path| {
            let err_str  = format!("Path is not valid UTF-8: {:?}", path);
            let pkg_path = try!(path.to_str().ok_or(Error::Parse(err_str)));
            info!("Downloaded to {:?}. Installing...", pkg_path);

            // TODO: Fire DownloadComplete event, handle async UpdateReport command
            // TODO: Do not invoke package_manager
            etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));
            self.config.device.package_manager.install_package(pkg_path).and_then(|(code, output)| {
                etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                Ok(UpdateReport::single(id.clone(), code, output))
            }).or_else(|(code, output)| {
                etx.send(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output)));
                Ok(UpdateReport::single(id.clone(), code, output))
            })
        }).or_else(|err| {
            etx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err)));
            let failed = format!("Download failed: {:?}", err);
            Ok(UpdateReport::single(id.clone(), UpdateResultCode::GENERAL_ERROR, failed))
        })
    }

    /// Send a list of the currently installed packages to the Core server.
    pub fn update_installed_packages(&mut self) -> Result<(), Error> {
        debug!("updating installed packages");
        // TODO: Fire GetInstalledSoftware event, handle async InstalledSoftware command
        // TODO: Do not invoke package_manager
        let pkgs    = try!(self.config.device.package_manager.installed_packages());
        let body    = try!(json::encode(&pkgs));
        let resp_rx = self.client.put(self.endpoint("installed"), Some(body.into_bytes()));
        let _       = resp_rx.recv().expect("no update_installed_packages response received")
                             .map_err(|err| error!("update_installed_packages failed: {}", err));
        Ok(())
    }

    /// Send the outcome of a package installation to the Core server.
    pub fn send_install_report(&mut self, update_report: &UpdateReport) -> Result<(), Error> {
        debug!("sending installation report");
        let report  = DeviceReport::new(&self.config.device.uuid, update_report);
        let body    = try!(json::encode(&report));
        let url     = self.endpoint(report.device);
        let resp_rx = self.client.post(url, Some(body.into_bytes()));
        let resp    = resp_rx.recv().expect("no send_install_report response received");
        let _       = try!(resp);
        Ok(())
    }

    /// Send system information from the device to the Core server.
    pub fn send_system_info(&mut self, info: &Json) -> Result<(), Error> {
        debug!("sending system info");
        let body    = try!(json::encode(info));
        let resp_rx = self.client.put(self.endpoint("system_info"), Some(body.into_bytes()));
        let resp    = resp_rx.recv().expect("no send_system_info response received");
        let _       = try!(resp);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Event, Package, PendingUpdateRequest, UpdateResultCode, UpdateState};
    use http::TestClient;
    use package_manager::PackageManager;
    use package_manager::tpm::{assert_rx, TestDir};

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json    = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::from(vec![json.to_string()]),
        };

        let updates: Vec<PendingUpdateRequest> = ota.get_package_updates().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }

    #[test]
    fn bad_client_download_package_update() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::default(),
        };
        let expect  = format!("Http client error: {}", ota.endpoint("0/download").to_string());
        assert_eq!(expect, format!("{}", ota.download_package_update("0".to_string()).unwrap_err()));
    }

    #[test]
    fn test_install_package_update_0() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestClient::default(),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::GENERAL_ERROR,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        let expect = format!(r#"Client("{}")"#, ota.endpoint("0/download").to_string());
        assert_rx(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(expect))
        ]);
    }

    #[test]
    fn test_install_package_update_1() {
        let mut config = Config::default();
        let test_dir   = TestDir::new("sota-test-install-1");
        config.device.packages_dir    = test_dir.0.clone();
        config.device.package_manager = PackageManager::new_tpm(false);

        let mut ota = OTA {
            config: &config,
            client: &mut TestClient::from(vec!["".to_string()]),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::INSTALL_FAILED,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), r#"INSTALL_FAILED: "failed""#.to_string())
        ]);
    }

    #[test]
    fn test_install_package_update_2() {
        let mut config = Config::default();
        let test_dir   = TestDir::new("sota-test-install-2");
        config.device.packages_dir    = test_dir.0.clone();
        config.device.package_manager = PackageManager::new_tpm(true);

        let replies = vec![
            "[]".to_string(),
            "package data".to_string(),
        ];
        let mut ota = OTA {
            config: &config,
            client: &mut TestClient::from(replies),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update("0".to_string(), &tx);
        assert_eq!(UpdateResultCode::OK,
                   report.unwrap().operation_results.pop().unwrap().result_code);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)
        ]);
    }
}
<|endoftext|>


<commit_before>//! This module defines the `Bits` and `Dibits` iterators as well as the wrapper types
//! `Bit` and `Dibit`, for working with sub-byte values.
//!
//! The wrapped values of `Bit` and `Dibit` are guaranteed to have only one or two bits,
//! respectively.

use std;

/// Iterate over individual bits of a byte source, MSB to LSB.
pub type Bits<T> = SubByteIter<BitParams, T>;
/// Iterate over the dibits of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;

/// Defines parameters needed for (power of two) sub-byte iterators.
pub trait IterParams {
    /// Type to yield at each iteration.
    type IterType;

    /// Number of bits to consume at each iteration.
    fn bits() -> u8;
    /// Wrap the given bits in container type.
    fn wrap(bits: u8) -> Self::IterType;

    /// Number of iterations needed for each byte.
    fn iterations() -> u8 { 8 / Self::bits() }

    /// Verify the parameters are supported.
    fn validate() {
        // Only powers of two are valid because there can be no "leftovers."
        assert!(Self::bits().is_power_of_two());
    }
}

/// A single bit.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Bit(u8);

impl Bit {
    /// Construct a new `Bit` with the given bit in the LSB position.
    pub fn new(bits: u8) -> Bit {
        assert!(bits & 0b11111110 == 0);
        Bit(bits)
    }

    /// Get the wrapped bit value.
    pub fn bit(&self) -> u8 { self.0 }
}

/// Parameters for `Bits` iterator.
pub struct BitParams;

impl IterParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(bits: u8) -> Bit { Bit::new(bits) }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits & 0b11111100 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// An iterator for sub-byte (bit-level) values.
pub struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current bit-level index into the current byte.
    idx: u8,
    /// Current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter` over the given byte source. All bits are iterated
    /// over, so the number of bits must be a byte multiple.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.byte >> (8 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        Some(P::wrap(bits))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitParams::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = Dibits::new(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = Bits::new(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }
}
<commit_msg>Add Tribit and Tribits<commit_after>//! This module defines the `Bits`, `Dibits`, and `Tribits` iterators as well as the
//! wrapper types `Bit`, `Dibit`, and `Tribit`, for working with sub-byte values.
//!
//! The wrapped values of `Bit`, `Dibit`, and `Tribit, are guaranteed to have only one,
//! two, or three bits, respectively.

use std;

/// Iterate over individual bits of a byte source, MSB to LSB.
pub type Bits<T> = SubByteIter<BitParams, T>;
/// Iterate over the dibits of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;

/// Defines parameters needed for (power of two) sub-byte iterators.
pub trait IterParams {
    /// Type to yield at each iteration.
    type IterType;

    /// Number of bits to consume at each iteration.
    fn bits() -> u8;
    /// Wrap the given bits in container type.
    fn wrap(bits: u8) -> Self::IterType;

    /// Number of iterations needed for each byte.
    fn iterations() -> u8 { 8 / Self::bits() }

    /// Verify the parameters are supported.
    fn validate() {
        // Only powers of two are valid because there can be no "leftovers."
        assert!(Self::bits().is_power_of_two());
    }
}

/// A single bit.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Bit(u8);

impl Bit {
    /// Construct a new `Bit` with the given bit in the LSB position.
    pub fn new(bits: u8) -> Bit {
        assert!(bits & 0b11111110 == 0);
        Bit(bits)
    }

    /// Get the wrapped bit value.
    pub fn bit(&self) -> u8 { self.0 }
}

/// Parameters for `Bits` iterator.
pub struct BitParams;

impl IterParams for BitParams {
    type IterType = Bit;
    fn bits() -> u8 { 1 }
    fn wrap(bits: u8) -> Bit { Bit::new(bits) }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits & 0b11111100 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type IterType = Dibit;
    fn bits() -> u8 { 2 }
    fn wrap(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// Three bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Tribit(u8);

impl Tribit {
    /// Construct a new `Tribit` with the three given bits in the LSB position.
    pub fn new(bits: u8) -> Tribit {
        assert!(bits & 0b11111000 == 0);
        Tribit(bits)
    }

    /// Get the wrapped tribit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// An iterator for sub-byte (bit-level) values.
pub struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current bit-level index into the current byte.
    idx: u8,
    /// Current byte in the source.
    byte: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter` over the given byte source. All bits are iterated
    /// over, so the number of bits must be a byte multiple.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            byte: 0,
            idx: 0,
        }
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.byte = match self.src.next() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.byte >> (8 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.byte <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations();

        Some(P::wrap(bits))
    }
}

/// Iterates over the tribits in a byte source.
pub struct Tribits<T: Iterator<Item = u8>> {
    /// The source of bytes.
    src: T,
    /// Current bit buffer, containing either 6 or 3 bits (in MSB position) or 0.
    bits: u8,
    /// Tribit index into `bits` (0 or 1).
    idx: usize,
    /// Buffered bits from current source byte, to be added to `bits`.
    buf: u8,
    /// Number of bits in `buf`, either 2, 4, 6, or 0.
    buf_bits: usize,
}

impl<T: Iterator<Item = u8>> Tribits<T> {
    /// Construct a new `Tribits` from the given source of bytes. The number of bytes must
    /// be a multiple of 3 (a multiple of 24 bits).
    pub fn new(src: T) -> Tribits<T> {
        Tribits {
            src: src,
            bits: 0,
            idx: 0,
            buf: 0,
            buf_bits: 0,
        }
    }
}

impl<T: Iterator<Item = u8>> Iterator for Tribits<T> {
    type Item = Tribit;

    fn next(&mut self) -> Option<Self::Item> {
        // If on the first tribit, it's time to flush the buffer and (maybe) load another
        // byte.
        if self.idx == 0 {
            // Flush and reset the buffer.
            self.bits = self.buf;
            self.buf = 0;

            // Calculate the number of bits to buffer for the next iteration.
            self.buf_bits += 2;
            self.buf_bits %= 8;

            // Only load a new byte if bits need to be buffered.
            if self.buf_bits != 0 {
                let next = match self.src.next() {
                    Some(b) => b,
                    None => if self.buf_bits == 2 {
                        // In this case we've covered 8 tribits = 24 bits = 3 bytes
                        // exactly, so it's fine if there are no more bytes.
                        return None;
                    } else {
                        panic!("incomplete tribit");
                    }
                };

                // Add in some source bits after the MSBs.
                self.bits |= next >> self.buf_bits << 2;
                // Buffer the rest of the bits.
                self.buf = next << (8 - self.buf_bits);
            }
        }

        // Extract the 3 MSBs and strip them off for next time.
        let bits = self.bits >> 5;
        self.bits <<= 3;

        self.idx += 1;
        self.idx %= 2;

        Some(Tribit::new(bits))
    }
}

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

    #[test]
    fn validate_params() {
        BitParams::validate();
        DibitParams::validate();
    }

    #[test]
    fn test_bits() {
        const BITS: &'static [u8] = &[
            0b00011011,
            0b11001100,
        ];

        {
            let mut d = Dibits::new(BITS.iter().cloned());

            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b01);
            assert!(d.next().unwrap().0 == 0b10);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().unwrap().0 == 0b11);
            assert!(d.next().unwrap().0 == 0b00);
            assert!(d.next().is_none());
        }

        {
            let mut b = Bits::new(BITS.iter().cloned());

            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 1);
            assert!(b.next().unwrap().0 == 0);
            assert!(b.next().unwrap().0 == 0);
        }
    }

    #[test]
    fn test_tribits() {
        let bytes = [
            0b00101001,
            0b11001011,
            0b10111000,
            0b00101001,
            0b11001011,
            0b10111000,
        ];
        let mut t = Tribits::new(bytes.iter().cloned());

        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribits_panic() {
        let bytes = [1, 2, 3, 4];
        let t = Tribits::new(bytes.iter().cloned());

        for _ in t {}
    }
}
<|endoftext|>


<commit_before>use std::libc::*;
use std::ptr;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;
use rust_util::Flag;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Flag::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	fn new(w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, &BitmapOptions::new())
	}

	fn new_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		let b;
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
			b = al_create_bitmap(w as c_int, h as c_int);
		}
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}

	fn load(filename: &str) -> Option<Bitmap>
	{
		Bitmap::load_with_options(filename, &BitmapOptions::new())
	}

	fn load_with_options(filename: &str, opt: &BitmapOptions) -> Option<Bitmap>
	{
		let mut b = ptr::mut_null();
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
			filename.with_c_str(|s|
			{
				b = al_load_bitmap(s);
			});
		}
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}

	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if b.is_null()
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if b.is_null()
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		let b = al_clone_bitmap(bmp);
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}

impl ::internal::core::Core
{
	pub fn create_bitmap(&self, w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new(w, h)
	}

	pub fn create_bitmap_with_options(&self, w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, opt)
	}

	pub fn load_bitmap(&self, filename: &str) -> Option<Bitmap>
	{
		Bitmap::load(filename)
	}

	pub fn create_bitmap_with_options(&self, filename: &str, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::load_with_options(filename, opt)
	}
}
<commit_msg>Whoops<commit_after>use std::libc::*;
use std::ptr;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;
use rust_util::Flag;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Flag::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	fn new(w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, &BitmapOptions::new())
	}

	fn new_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		let b;
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
			b = al_create_bitmap(w as c_int, h as c_int);
		}
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}

	fn load(filename: &str) -> Option<Bitmap>
	{
		Bitmap::load_with_options(filename, &BitmapOptions::new())
	}

	fn load_with_options(filename: &str, opt: &BitmapOptions) -> Option<Bitmap>
	{
		let mut b = ptr::mut_null();
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
			filename.with_c_str(|s|
			{
				b = al_load_bitmap(s);
			});
		}
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}

	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if b.is_null()
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if b.is_null()
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		let b = al_clone_bitmap(bmp);
		if b.is_null()
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}

impl ::internal::core::Core
{
	pub fn create_bitmap(&self, w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new(w, h)
	}

	pub fn create_bitmap_with_options(&self, w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, opt)
	}

	pub fn load_bitmap(&self, filename: &str) -> Option<Bitmap>
	{
		Bitmap::load(filename)
	}

	pub fn load_bitmap_with_options(&self, filename: &str, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::load_with_options(filename, opt)
	}
}
<|endoftext|>


<commit_before>use crate::acpi::hpet::Hpet;

static LEG_RT_CNF: u64 = 2;
static ENABLE_CNF: u64 = 1;

static TN_VAL_SET_CNF: u64 = 0x40;
static TN_TYPE_CNF: u64 = 0x08;
static TN_INT_ENB_CNF: u64 = 0x04;

static CAPABILITY_OFFSET: usize = 0x00;
static GENERAL_CONFIG_OFFSET: usize = 0x10;
// static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
// static MAIN_COUNTER_OFFSET: usize = 0xF0;
// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
static LEG_RT_CAP: u64 = 0x8000;
static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
static T0_COMPARATOR_OFFSET: usize = 0x108;

static PER_INT_CAP: u64 = 0x10;

pub unsafe fn init(hpet: &mut Hpet) -> bool {
    // Disable HPET
    {
        let mut config_word = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
        log::info!("HPET config old: {:#x}", config_word);
        config_word &= !ENABLE_CNF;
        log::info!("HPET config new: {:#x}", config_word);
        hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
    }

    let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
    {
        log::info!("HPET caps: {:#x}", capability);
        log::info!("HPET caps clock period: {}", (capability >> 32) as u32);
        log::info!("HPET caps ID: {:#x}", (capability >> 16) as u16);
        log::info!("HPET caps LEG_RT_CAP: {}", capability & (1 << 15) == (1 << 15));
        log::info!("HPET caps COUNT_SIZE_CAP: {}", capability & (1 << 13) == (1 << 13));
        log::info!("HPET caps timers: {}", (capability >> 8) as u8 & 0x1F);
        log::info!("HPET caps revision: {}", capability as u8);
    }
    if capability & LEG_RT_CAP == 0 {
        log::warn!("HPET missing capability LEG_RT_CAP");
        return false;
    }

    let counter_clk_period_fs = capability >> 32;
    let desired_fs_period: u64 = 2_250_286 * 1_000_000;

    let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;

    let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
    {
        log::info!("HPET T0 caps: {:#x}", t0_capabilities);
        log::info!("HPET T0 caps interrupt routing: {:#x}", (t0_capabilities >> 32) as u32);
        log::info!("HPET T0 caps flags: {:#x}", t0_capabilities as u16);
    }
    if t0_capabilities & PER_INT_CAP == 0 {
        log::warn!("HPET T0 missing capability PER_INT_CAP");
        return false;
    }

    let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
    hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
    // set accumulator value
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
    // set interval
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);

    // Enable interrupts from the HPET
    {
        let mut config_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
        log::info!("HPET config old: {:#x}", config_word);
        config_word |= LEG_RT_CNF | ENABLE_CNF;
        log::info!("HPET config new: {:#x}", config_word);
        hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
    }

    true
}
<commit_msg>Fix HPET on real hardware with better debugging<commit_after>use crate::acpi::hpet::Hpet;

static LEG_RT_CNF: u64 = 2;
static ENABLE_CNF: u64 = 1;

static TN_VAL_SET_CNF: u64 = 0x40;
static TN_TYPE_CNF: u64 = 0x08;
static TN_INT_ENB_CNF: u64 = 0x04;

static CAPABILITY_OFFSET: usize = 0x00;
static GENERAL_CONFIG_OFFSET: usize = 0x10;
static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
static MAIN_COUNTER_OFFSET: usize = 0xF0;
// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
static LEG_RT_CAP: u64 = 0x8000;
static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
static T0_COMPARATOR_OFFSET: usize = 0x108;

static PER_INT_CAP: u64 = 0x10;

pub unsafe fn init(hpet: &mut Hpet) -> bool {
    println!("HPET Before Init");
    debug(hpet);

    // Disable HPET
    {
        let mut config_word = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
        config_word &= !(LEG_RT_CNF | ENABLE_CNF);
        hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
    }

    let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
    if capability & LEG_RT_CAP == 0 {
        log::warn!("HPET missing capability LEG_RT_CAP");
        return false;
    }

    let counter_clk_period_fs = capability >> 32;
    let desired_fs_period: u64 = 2_250_286 * 1_000_000;

    let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;

    let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
    if t0_capabilities & PER_INT_CAP == 0 {
        log::warn!("HPET T0 missing capability PER_INT_CAP");
        return false;
    }

    let counter = hpet.base_address.read_u64(MAIN_COUNTER_OFFSET);

    let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
    hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
    // set accumulator value
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + clk_periods_per_kernel_tick);
    // set interval
    hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);

    // Enable interrupts from the HPET
    {
        let mut config_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
        config_word |= LEG_RT_CNF | ENABLE_CNF;
        hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
    }

    println!("HPET After Init");
    debug(hpet);

    true
}

pub unsafe fn debug(hpet: &mut Hpet) {
    println!("HPET @ {:#x}", hpet.base_address.address);

    let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
    {
        println!("  caps: {:#x}", capability);
        println!("    clock period: {}", (capability >> 32) as u32);
        println!("    ID: {:#x}", (capability >> 16) as u16);
        println!("    LEG_RT_CAP: {}", capability & (1 << 15) == (1 << 15));
        println!("    COUNT_SIZE_CAP: {}", capability & (1 << 13) == (1 << 13));
        println!("    timers: {}", (capability >> 8) as u8 & 0x1F);
        println!("    revision: {}", capability as u8);
    }

    let config_word = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
    println!("  config: {:#x}", config_word);

    let interrupt_status = hpet.base_address.read_u64(GENERAL_INTERRUPT_OFFSET);
    println!("  interrupt status: {:#x}", interrupt_status);

    let counter = hpet.base_address.read_u64(MAIN_COUNTER_OFFSET);
    println!("  counter: {:#x}", counter);

    let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
    println!("  T0 caps: {:#x}", t0_capabilities);
    println!("    interrupt routing: {:#x}", (t0_capabilities >> 32) as u32);
    println!("    flags: {:#x}", t0_capabilities as u16);

    let t0_comparator = hpet.base_address.read_u64(T0_COMPARATOR_OFFSET);
    println!("  T0 comparator: {:#x}", t0_comparator);
}
<|endoftext|>


<commit_before>//! TODO: Docs

use std::collections::VecDeque;

use indexmap::IndexMap;

use crate::{
    backend::renderer::Frame,
    output::Output,
    utils::{Physical, Rectangle, Scale, Size, Transform},
};

use super::{
    element::{Id, RenderElement},
    utils::CommitCounter,
};

use super::{Renderer, Texture};

#[derive(Debug, Clone, Copy)]
struct ElementState {
    last_commit: CommitCounter,
    last_geometry: Rectangle<i32, Physical>,
    last_z_index: usize,
}

#[derive(Debug, Default)]
struct RendererState {
    size: Option<Size<i32, Physical>>,
    elements: IndexMap<Id, ElementState>,
    old_damage: VecDeque<Vec<Rectangle<i32, Physical>>>,
}

/// Mode for the [`DamageTrackedRenderer`]
#[derive(Debug, Clone)]
pub enum DamageTrackedRendererMode {
    /// Automatic mode based on a output
    Auto(Output),
    /// Static mode
    Static {
        /// Size of the static output
        size: Size<i32, Physical>,
        /// Scale of the static output
        scale: Scale<f64>,
        /// Transform of the static output
        transform: Transform,
    },
}

/// Output has no active mode
#[derive(Debug, thiserror::Error)]
#[error("Output has no active mode")]
pub struct OutputNoMode;

impl TryInto<(Size<i32, Physical>, Scale<f64>, Transform)> for DamageTrackedRendererMode {
    type Error = OutputNoMode;

    fn try_into(self) -> Result<(Size<i32, Physical>, Scale<f64>, Transform), Self::Error> {
        match self {
            DamageTrackedRendererMode::Auto(output) => Ok((
                output.current_mode().ok_or(OutputNoMode)?.size,
                output.current_scale().fractional_scale().into(),
                output.current_transform(),
            )),
            DamageTrackedRendererMode::Static {
                size,
                scale,
                transform,
            } => Ok((size, scale, transform)),
        }
    }
}

/// Rendering for a single output
#[derive(Debug)]
pub struct DamageTrackedRenderer {
    mode: DamageTrackedRendererMode,
    last_state: RendererState,
}

/// Errors thrown by [`Space::render_output`]
#[derive(thiserror::Error)]
pub enum DamageTrackedRendererError<R: Renderer> {
    /// The provided [`Renderer`] did return an error during an operation
    #[error(transparent)]
    Rendering(R::Error),
    /// The given [`Output`] has no set mode
    #[error(transparent)]
    OutputNoMode(#[from] OutputNoMode),
}

impl<R: Renderer> std::fmt::Debug for DamageTrackedRendererError<R> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DamageTrackedRendererError::Rendering(err) => std::fmt::Debug::fmt(err, f),
            DamageTrackedRendererError::OutputNoMode(err) => std::fmt::Debug::fmt(err, f),
        }
    }
}

impl DamageTrackedRenderer {
    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn new(
        size: impl Into<Size<i32, Physical>>,
        scale: impl Into<Scale<f64>>,
        transform: Transform,
    ) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Static {
                size: size.into(),
                scale: scale.into(),
                transform,
            },
            last_state: Default::default(),
        }
    }

    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn from_output(output: &Output) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Auto(output.clone()),
            last_state: Default::default(),
        }
    }

    /// Get the [`Mode`] of the [`DamageTrackedRenderer`]
    pub fn mode(&self) -> &DamageTrackedRendererMode {
        &self.mode
    }

    /// Render this output
    pub fn render_output<E, R>(
        &mut self,
        renderer: &mut R,
        age: usize,
        elements: &[E],
        clear_color: [f32; 4],
        log: &slog::Logger,
    ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, DamageTrackedRendererError<R>>
    where
        E: RenderElement<R>,
        R: Renderer,
        <R as Renderer>::TextureId: Texture,
    {
        let (output_size, output_scale, output_transform) = self.mode.clone().try_into()?;
        let output_geo = Rectangle::from_loc_and_size((0, 0), output_size);

        // This will hold all the damage we need for this rendering step
        let mut damage: Vec<Rectangle<i32, Physical>> = Vec::new();
        let mut render_elements: Vec<&E> = Vec::with_capacity(elements.len());
        let mut opaque_regions: Vec<Rectangle<i32, Physical>> = Vec::new();

        if self.last_state.size.map(|geo| geo != output_size).unwrap_or(true) {
            // The output geometry changed, so just damage everything
            slog::trace!(log, "Output geometry changed, damaging whole output geometry. previous geometry: {:?}, current geometry: {:?}", self.last_state.size, output_geo);
            damage = vec![output_geo];
        }

        // We now add old damage states, if we have an age value
        if age > 0 && self.last_state.old_damage.len() >= age {
            // We do not need even older states anymore
            self.last_state.old_damage.truncate(age);
            damage.extend(self.last_state.old_damage.iter().flatten().copied());
        } else {
            // just damage everything, if we have no damage
            damage = vec![output_geo];
        }

        for element in elements {
            let element_geometry = element.geometry(output_scale);

            // First test if the element overlaps with the output
            // if not we can skip ip
            if !element_geometry.overlaps(output_geo) {
                continue;
            }

            // Then test if the element is completely hidden behind opaque regions
            let is_hidden = opaque_regions
                .iter()
                .fold([element_geometry].to_vec(), |geometry, opaque_region| {
                    geometry
                        .into_iter()
                        .flat_map(|g| g.subtract_rect(*opaque_region))
                        .collect::<Vec<_>>()
                })
                .is_empty();

            if is_hidden {
                // No need to draw a completely hidden element
                continue;
            }

            let element_damage = element
                .damage_since(
                    output_scale,
                    self.last_state.elements.get(element.id()).map(|s| s.last_commit),
                )
                .into_iter()
                .map(|mut d| {
                    d.loc += element_geometry.loc;
                    d
                })
                .collect::<Vec<_>>();

            let element_output_damage =
                opaque_regions
                    .iter()
                    .fold(element_damage, |damage, opaque_region| {
                        damage
                            .into_iter()
                            .flat_map(|damage| damage.subtract_rect(*opaque_region))
                            .collect::<Vec<_>>()
                    });

            damage.extend(element_output_damage);
            opaque_regions.extend(
                element
                    .opaque_regions(output_scale)
                    .into_iter()
                    .map(|mut region| {
                        region.loc += element_geometry.loc;
                        region
                    }),
            );
            render_elements.insert(0, element);
        }

        // add the damage for elements gone that are not covered by
        // by an opaque region
        // TODO: actually filter the damage with the opaque regions
        let elements_gone = self
            .last_state
            .elements
            .iter()
            .filter_map(|(id, state)| {
                if !render_elements.iter().any(|e| e.id() == id) {
                    Some(state.last_geometry)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();
        damage.extend(elements_gone);

        // if the element has been moved or it's z index changed damage it
        for (z_index, element) in render_elements.iter().enumerate() {
            let element_geometry = element.geometry(output_scale);
            let element_last_state = self.last_state.elements.get(element.id());

            if element_last_state
                .map(|s| s.last_geometry != element_geometry || s.last_z_index != z_index)
                .unwrap_or(false)
            {
                if let Some(old_geo) = element_last_state.map(|s| s.last_geometry) {
                    damage.push(old_geo);
                }
                damage.push(element_geometry);
            }
        }

        // Optimize the damage for rendering
        damage.dedup();
        damage.retain(|rect| rect.overlaps(output_geo));
        damage.retain(|rect| !rect.is_empty());
        // filter damage outside of the output gep and merge overlapping rectangles
        damage = damage
            .into_iter()
            .filter_map(|rect| rect.intersection(output_geo))
            .fold(Vec::new(), |new_damage, mut rect| {
                // replace with drain_filter, when that becomes stable to reuse the original Vec's memory
                let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
                    new_damage.into_iter().partition(|other| other.overlaps(rect));

                for overlap in overlapping {
                    rect = rect.merge(overlap);
                }
                new_damage.push(rect);
                new_damage
            });

        if damage.is_empty() {
            return Ok(None);
        }

        let mut elements_drawn = 0;

        let res = renderer.render(output_size, output_transform, |renderer, frame| {
            frame.clear(clear_color, &*damage)?;

            for element in render_elements.iter() {
                let element_geometry = element.geometry(output_scale);

                let element_damage = damage
                    .iter()
                    .filter_map(|d| d.intersection(element_geometry))
                    .map(|mut d| {
                        d.loc -= element_geometry.loc;
                        d
                    })
                    .collect::<Vec<_>>();

                if element_damage.is_empty() {
                    continue;
                }

                element.draw(renderer, frame, output_scale, &*element_damage, log)?;
                elements_drawn += 1;
            }

            Result::<(), R::Error>::Ok(())
        });

        if let Err(err) = res {
            // if the rendering errors on us, we need to be prepared, that this whole buffer was partially updated and thus now unusable.
            // thus clean our old states before returning
            self.last_state = Default::default();
            return Err(DamageTrackedRendererError::Rendering(err));
        }

        let new_elements_state = render_elements
            .iter()
            .enumerate()
            .map(|(zindex, elem)| {
                let id = elem.id().clone();
                let current_commit = elem.current_commit();
                let elem_geometry = elem.geometry(output_scale);
                let state = ElementState {
                    last_commit: current_commit,
                    last_geometry: elem_geometry,
                    last_z_index: zindex,
                };
                (id, state)
            })
            .collect();
        self.last_state.size = Some(output_size);
        self.last_state.elements = new_elements_state;
        self.last_state.old_damage.push_front(damage.clone());

        Ok(Some(damage))
    }
}
<commit_msg>renderer: only accumulate new damage<commit_after>//! TODO: Docs

use std::collections::VecDeque;

use indexmap::IndexMap;

use crate::{
    backend::renderer::Frame,
    output::Output,
    utils::{Physical, Rectangle, Scale, Size, Transform},
};

use super::{
    element::{Id, RenderElement},
    utils::CommitCounter,
};

use super::{Renderer, Texture};

#[derive(Debug, Clone, Copy)]
struct ElementState {
    last_commit: CommitCounter,
    last_geometry: Rectangle<i32, Physical>,
    last_z_index: usize,
}

#[derive(Debug, Default)]
struct RendererState {
    size: Option<Size<i32, Physical>>,
    elements: IndexMap<Id, ElementState>,
    old_damage: VecDeque<Vec<Rectangle<i32, Physical>>>,
}

/// Mode for the [`DamageTrackedRenderer`]
#[derive(Debug, Clone)]
pub enum DamageTrackedRendererMode {
    /// Automatic mode based on a output
    Auto(Output),
    /// Static mode
    Static {
        /// Size of the static output
        size: Size<i32, Physical>,
        /// Scale of the static output
        scale: Scale<f64>,
        /// Transform of the static output
        transform: Transform,
    },
}

/// Output has no active mode
#[derive(Debug, thiserror::Error)]
#[error("Output has no active mode")]
pub struct OutputNoMode;

impl TryInto<(Size<i32, Physical>, Scale<f64>, Transform)> for DamageTrackedRendererMode {
    type Error = OutputNoMode;

    fn try_into(self) -> Result<(Size<i32, Physical>, Scale<f64>, Transform), Self::Error> {
        match self {
            DamageTrackedRendererMode::Auto(output) => Ok((
                output.current_mode().ok_or(OutputNoMode)?.size,
                output.current_scale().fractional_scale().into(),
                output.current_transform(),
            )),
            DamageTrackedRendererMode::Static {
                size,
                scale,
                transform,
            } => Ok((size, scale, transform)),
        }
    }
}

/// Rendering for a single output
#[derive(Debug)]
pub struct DamageTrackedRenderer {
    mode: DamageTrackedRendererMode,
    last_state: RendererState,
}

/// Errors thrown by [`Space::render_output`]
#[derive(thiserror::Error)]
pub enum DamageTrackedRendererError<R: Renderer> {
    /// The provided [`Renderer`] did return an error during an operation
    #[error(transparent)]
    Rendering(R::Error),
    /// The given [`Output`] has no set mode
    #[error(transparent)]
    OutputNoMode(#[from] OutputNoMode),
}

impl<R: Renderer> std::fmt::Debug for DamageTrackedRendererError<R> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DamageTrackedRendererError::Rendering(err) => std::fmt::Debug::fmt(err, f),
            DamageTrackedRendererError::OutputNoMode(err) => std::fmt::Debug::fmt(err, f),
        }
    }
}

impl DamageTrackedRenderer {
    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn new(
        size: impl Into<Size<i32, Physical>>,
        scale: impl Into<Scale<f64>>,
        transform: Transform,
    ) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Static {
                size: size.into(),
                scale: scale.into(),
                transform,
            },
            last_state: Default::default(),
        }
    }

    /// Initialize a new [`DamageTrackedRenderer`]
    pub fn from_output(output: &Output) -> Self {
        Self {
            mode: DamageTrackedRendererMode::Auto(output.clone()),
            last_state: Default::default(),
        }
    }

    /// Get the [`Mode`] of the [`DamageTrackedRenderer`]
    pub fn mode(&self) -> &DamageTrackedRendererMode {
        &self.mode
    }

    /// Render this output
    pub fn render_output<E, R>(
        &mut self,
        renderer: &mut R,
        age: usize,
        elements: &[E],
        clear_color: [f32; 4],
        log: &slog::Logger,
    ) -> Result<Option<Vec<Rectangle<i32, Physical>>>, DamageTrackedRendererError<R>>
    where
        E: RenderElement<R>,
        R: Renderer,
        <R as Renderer>::TextureId: Texture,
    {
        let (output_size, output_scale, output_transform) = self.mode.clone().try_into()?;
        let output_geo = Rectangle::from_loc_and_size((0, 0), output_size);

        // This will hold all the damage we need for this rendering step
        let mut damage: Vec<Rectangle<i32, Physical>> = Vec::new();
        let mut render_elements: Vec<&E> = Vec::with_capacity(elements.len());
        let mut opaque_regions: Vec<Rectangle<i32, Physical>> = Vec::new();

        for element in elements {
            let element_geometry = element.geometry(output_scale);

            // First test if the element overlaps with the output
            // if not we can skip ip
            if !element_geometry.overlaps(output_geo) {
                continue;
            }

            // Then test if the element is completely hidden behind opaque regions
            let is_hidden = opaque_regions
                .iter()
                .fold([element_geometry].to_vec(), |geometry, opaque_region| {
                    geometry
                        .into_iter()
                        .flat_map(|g| g.subtract_rect(*opaque_region))
                        .collect::<Vec<_>>()
                })
                .is_empty();

            if is_hidden {
                // No need to draw a completely hidden element
                continue;
            }

            let element_damage = element
                .damage_since(
                    output_scale,
                    self.last_state.elements.get(element.id()).map(|s| s.last_commit),
                )
                .into_iter()
                .map(|mut d| {
                    d.loc += element_geometry.loc;
                    d
                })
                .collect::<Vec<_>>();

            let element_output_damage =
                opaque_regions
                    .iter()
                    .fold(element_damage, |damage, opaque_region| {
                        damage
                            .into_iter()
                            .flat_map(|damage| damage.subtract_rect(*opaque_region))
                            .collect::<Vec<_>>()
                    });

            damage.extend(element_output_damage);
            opaque_regions.extend(
                element
                    .opaque_regions(output_scale)
                    .into_iter()
                    .map(|mut region| {
                        region.loc += element_geometry.loc;
                        region
                    }),
            );
            render_elements.insert(0, element);
        }

        // add the damage for elements gone that are not covered by
        // by an opaque region
        // TODO: actually filter the damage with the opaque regions
        let elements_gone = self
            .last_state
            .elements
            .iter()
            .filter_map(|(id, state)| {
                if !render_elements.iter().any(|e| e.id() == id) {
                    Some(state.last_geometry)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();
        damage.extend(elements_gone);

        // if the element has been moved or it's z index changed damage it
        for (z_index, element) in render_elements.iter().enumerate() {
            let element_geometry = element.geometry(output_scale);
            let element_last_state = self.last_state.elements.get(element.id());

            if element_last_state
                .map(|s| s.last_geometry != element_geometry || s.last_z_index != z_index)
                .unwrap_or(false)
            {
                if let Some(old_geo) = element_last_state.map(|s| s.last_geometry) {
                    damage.push(old_geo);
                }
                damage.push(element_geometry);
            }
        }

        if self.last_state.size.map(|geo| geo != output_size).unwrap_or(true) {
            // The output geometry changed, so just damage everything
            slog::trace!(log, "Output geometry changed, damaging whole output geometry. previous geometry: {:?}, current geometry: {:?}", self.last_state.size, output_geo);
            damage = vec![output_geo];
        }

        // That is all completely new damage, which we need to store for subsequent renders
        let new_damage = damage.clone();

        // We now add old damage states, if we have an age value
        if age > 0 && self.last_state.old_damage.len() >= age {
            slog::trace!(log, "age of {} recent enough, using old damage", age);
            // We do not need even older states anymore
            self.last_state.old_damage.truncate(age);
            damage.extend(self.last_state.old_damage.iter().flatten().copied());
        } else {
            slog::trace!(
                log,
                "no old damage available, re-render everything. age: {} old_damage len: {}",
                age,
                self.last_state.old_damage.len(),
            );
            // just damage everything, if we have no damage
            damage = vec![output_geo];
        };

        // Optimize the damage for rendering
        damage.dedup();
        damage.retain(|rect| rect.overlaps(output_geo));
        damage.retain(|rect| !rect.is_empty());
        // filter damage outside of the output gep and merge overlapping rectangles
        damage = damage
            .into_iter()
            .filter_map(|rect| rect.intersection(output_geo))
            .fold(Vec::new(), |new_damage, mut rect| {
                // replace with drain_filter, when that becomes stable to reuse the original Vec's memory
                let (overlapping, mut new_damage): (Vec<_>, Vec<_>) =
                    new_damage.into_iter().partition(|other| other.overlaps(rect));

                for overlap in overlapping {
                    rect = rect.merge(overlap);
                }
                new_damage.push(rect);
                new_damage
            });

        if damage.is_empty() {
            slog::trace!(log, "nothing damaged, exiting early");
            return Ok(None);
        }

        slog::trace!(log, "damage to be rendered: {:#?}", &damage);

        let mut elements_drawn = 0;

        let res = renderer.render(output_size, output_transform, |renderer, frame| {
            frame.clear(clear_color, &*damage)?;

            for element in render_elements.iter() {
                let element_geometry = element.geometry(output_scale);

                let element_damage = damage
                    .iter()
                    .filter_map(|d| d.intersection(element_geometry))
                    .map(|mut d| {
                        d.loc -= element_geometry.loc;
                        d
                    })
                    .collect::<Vec<_>>();

                if element_damage.is_empty() {
                    continue;
                }

                element.draw(renderer, frame, output_scale, &*element_damage, log)?;
                elements_drawn += 1;
            }

            Result::<(), R::Error>::Ok(())
        });

        if let Err(err) = res {
            // if the rendering errors on us, we need to be prepared, that this whole buffer was partially updated and thus now unusable.
            // thus clean our old states before returning
            self.last_state = Default::default();
            return Err(DamageTrackedRendererError::Rendering(err));
        }

        let new_elements_state = render_elements
            .iter()
            .enumerate()
            .map(|(zindex, elem)| {
                let id = elem.id().clone();
                let current_commit = elem.current_commit();
                let elem_geometry = elem.geometry(output_scale);
                let state = ElementState {
                    last_commit: current_commit,
                    last_geometry: elem_geometry,
                    last_z_index: zindex,
                };
                (id, state)
            })
            .collect();
        self.last_state.size = Some(output_size);
        self.last_state.elements = new_elements_state;
        self.last_state.old_damage.push_front(new_damage.clone());

        Ok(Some(new_damage))
    }
}
<|endoftext|>


<commit_before>use super::super::context::BuildContext;
use super::super::download::download_file;
use super::super::tarcmd::unpack_file;
use super::generic::run_command;

pub fn fetch_ubuntu_core(ctx: &mut BuildContext, release: &String)
    -> Result<(), String>
{
    let kind = "core";
    let arch = "amd64";
    let url = format!(concat!(
        "http://cdimage.ubuntu.com/ubuntu-{kind}/{release}/",
        "daily/current/{release}-{kind}-{arch}.tar.gz",
        ), kind=kind, arch=arch, release=release);
    let filename = try!(download_file(ctx, &url));
    try!(unpack_file(ctx, &filename, &Path::new("/vagga/root"), &[],
        &[Path::new("dev")]));
    try!(init_debian_build(ctx));
    return Ok(());
}

fn init_debian_build(ctx: &mut BuildContext) -> Result<(), String> {
    try!(ctx.add_cache_dir(Path::new("/var/cache/apt"),
                           "apt-cache".to_string()));
    // TODO(tailhook) remove apt and dpkg
    ctx.add_remove_dir(Path::new("/var/lib/apt"));
    ctx.add_remove_dir(Path::new("/var/lib/dpkg"));
    return Ok(());
}

pub fn apt_install(ctx: &mut BuildContext, pkgs: &Vec<String>)
    -> Result<(), String>
{
    let mut args = vec!(
        "/usr/bin/apt-get".to_string(),
        "install".to_string(),
        "-y".to_string(),
        );
    args.extend(pkgs.clone().into_iter());
    run_command(ctx, args.as_slice())
}
<commit_msg>Implement ubuntu/debian specific hacks<commit_after>use std::io::fs::File;

use super::super::context::BuildContext;
use super::super::download::download_file;
use super::super::tarcmd::unpack_file;
use super::generic::run_command;

pub fn fetch_ubuntu_core(ctx: &mut BuildContext, release: &String)
    -> Result<(), String>
{
    let kind = "core";
    let arch = "amd64";
    let url = format!(concat!(
        "http://cdimage.ubuntu.com/ubuntu-{kind}/{release}/",
        "daily/current/{release}-{kind}-{arch}.tar.gz",
        ), kind=kind, arch=arch, release=release);
    let filename = try!(download_file(ctx, &url));
    try!(unpack_file(ctx, &filename, &Path::new("/vagga/root"), &[],
        &[Path::new("dev")]));
    try!(init_debian_build(ctx));
    return Ok(());
}

fn init_debian_build(ctx: &mut BuildContext) -> Result<(), String> {

    // Do not attempt to start init scripts
    try!(File::create(
            &Path::new("/vagga/root/usr/sbin/policy-rc.d"))
        .and_then(|mut f| f.write(b"#!/bin/sh\nexit 101\n"))
        .map_err(|e| format!("Error writing policy-rc.d file: {}", e)));

    // Do not need to fsync() after package installation
    try!(File::create(
            &Path::new("/vagga/root/etc/dpkg/dpkg.cfg.d/02apt-speedup"))
        .and_then(|mut f| f.write(b"force-unsafe-io"))
        .map_err(|e| format!("Error writing dpkg config: {}", e)));

    try!(ctx.add_cache_dir(Path::new("/var/cache/apt"),
                           "apt-cache".to_string()));
    // TODO(tailhook) remove apt and dpkg
    ctx.add_remove_dir(Path::new("/var/lib/apt"));
    ctx.add_remove_dir(Path::new("/var/lib/dpkg"));
    return Ok(());
}

pub fn apt_install(ctx: &mut BuildContext, pkgs: &Vec<String>)
    -> Result<(), String>
{
    let mut args = vec!(
        "/usr/bin/apt-get".to_string(),
        "install".to_string(),
        "-y".to_string(),
        );
    args.extend(pkgs.clone().into_iter());
    run_command(ctx, args.as_slice())
}
<|endoftext|>