<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Handles routing to devices in an address space.

use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::collections::btree_map::BTreeMap;
use std::result;
use std::sync::{Arc, Mutex};

/// Trait for devices that respond to reads or writes in an arbitrary address space.
///
/// The device does not care where it exists in address space as each method is only given an offset
/// into its allocated portion of address space.
#[allow(unused_variables)]
pub trait BusDevice: Send {
    /// Reads at `offset` from this device
    fn read(&mut self, offset: u64, data: &mut [u8]) {}
    /// Writes at `offset` into this device
    fn write(&mut self, offset: u64, data: &[u8]) {}
    /// Triggers the `irq_mask` interrupt on this device
    fn interrupt(&self, irq_mask: u32) {}
}

#[derive(Debug)]
pub enum Error {
    /// The insertion failed because the new device overlapped with an old device.
    Overlap,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Copy, Clone)]
struct BusRange(u64, u64);

impl Eq for BusRange {}

impl PartialEq for BusRange {
    fn eq(&self, other: &BusRange) -> bool {
        self.0 == other.0
    }
}

impl Ord for BusRange {
    fn cmp(&self, other: &BusRange) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for BusRange {
    fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

/// A device container for routing reads and writes over some address space.
///
/// This doesn't have any restrictions on what kind of device or address space this applies to. The
/// only restriction is that no two devices can overlap in this address space.
#[derive(Clone)]
pub struct Bus {
    devices: BTreeMap<BusRange, Arc<Mutex<BusDevice>>>,
}

impl Bus {
    /// Constructs an a bus with an empty address space.
    pub fn new() -> Bus {
        Bus {
            devices: BTreeMap::new(),
        }
    }

    fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<BusDevice>)> {
        // for when we switch to rustc 1.17: self.devices.range(..addr).iter().rev().next()
        for (range, dev) in self.devices.iter().rev() {
            if range.0 <= addr {
                return Some((*range, dev));
            }
        }
        None
    }

    pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<BusDevice>)> {
        if let Some((BusRange(start, len), dev)) = self.first_before(addr) {
            let offset = addr - start;
            if offset < len {
                return Some((offset, dev));
            }
        }
        None
    }

    /// Puts the given device at the given address space.
    pub fn insert(&mut self, device: Arc<Mutex<BusDevice>>, base: u64, len: u64) -> Result<()> {
        if len == 0 {
            return Err(Error::Overlap);
        }

        // Reject all cases where the new device's base is within an old device's range.
        if self.get_device(base).is_some() {
            return Err(Error::Overlap);
        }

        // The above check will miss an overlap in which the new device's base address is before the
        // range of another device. To catch that case, we search for a device with a range before
        // the new device's range's end. If there is no existing device in that range that starts
        // after the new device, then there will be no overlap.
        if let Some((BusRange(start, _), _)) = self.first_before(base + len - 1) {
            // Such a device only conflicts with the new device if it also starts after the new
            // device because of our initial `get_device` check above.
            if start >= base {
                return Err(Error::Overlap);
            }
        }

        if self.devices.insert(BusRange(base, len), device).is_some() {
            return Err(Error::Overlap);
        }

        Ok(())
    }

    /// Reads data from the device that owns the range containing `addr` and puts it into `data`.
    ///
    /// Returns true on success, otherwise `data` is untouched.
    pub fn read(&self, addr: u64, data: &mut [u8]) -> bool {
        if let Some((offset, dev)) = self.get_device(addr) {
            // OK to unwrap as lock() failing is a serious error condition and should panic.
            dev.lock().unwrap().read(offset, data);
            true
        } else {
            false
        }
    }

    /// Writes `data` to the device that owns the range containing `addr`.
    ///
    /// Returns true on success, otherwise `data` is untouched.
    pub fn write(&self, addr: u64, data: &[u8]) -> bool {
        if let Some((offset, dev)) = self.get_device(addr) {
            // OK to unwrap as lock() failing is a serious error condition and should panic.
            dev.lock().unwrap().write(offset, data);
            true
        } else {
            false
        }
    }
}

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

    struct DummyDevice;
    impl BusDevice for DummyDevice {}

    struct ConstantDevice;
    impl BusDevice for ConstantDevice {
        fn read(&mut self, offset: u64, data: &mut [u8]) {
            for (i, v) in data.iter_mut().enumerate() {
                *v = (offset as u8) + (i as u8);
            }
        }

        fn write(&mut self, offset: u64, data: &[u8]) {
            for (i, v) in data.iter().enumerate() {
                assert_eq!(*v, (offset as u8) + (i as u8))
            }
        }
    }

    #[test]
    fn bus_insert() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(DummyDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());

        let result = bus.insert(dummy.clone(), 0x0f, 0x10);
        assert!(result.is_err());
        assert_eq!(format!("{:?}", result), "Err(Overlap)");

        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_err());
        assert!(bus.insert(dummy.clone(), 0x10, 0x15).is_err());
        assert!(bus.insert(dummy.clone(), 0x12, 0x15).is_err());
        assert!(bus.insert(dummy.clone(), 0x12, 0x01).is_err());
        assert!(bus.insert(dummy.clone(), 0x0, 0x20).is_err());
        assert!(bus.insert(dummy.clone(), 0x20, 0x05).is_ok());
        assert!(bus.insert(dummy.clone(), 0x25, 0x05).is_ok());
        assert!(bus.insert(dummy.clone(), 0x0, 0x10).is_ok());
    }

    #[test]
    fn bus_read_write() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(DummyDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
        assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x10, &[0, 0, 0, 0]));
        assert!(bus.read(0x11, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x11, &[0, 0, 0, 0]));
        assert!(bus.read(0x16, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x16, &[0, 0, 0, 0]));
        assert!(!bus.read(0x20, &mut [0, 0, 0, 0]));
        assert!(!bus.write(0x20, &mut [0, 0, 0, 0]));
        assert!(!bus.read(0x06, &mut [0, 0, 0, 0]));
        assert!(!bus.write(0x06, &mut [0, 0, 0, 0]));
    }

    #[test]
    fn bus_read_write_values() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(ConstantDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());

        let mut values = [0, 1, 2, 3];
        assert!(bus.read(0x10, &mut values));
        assert_eq!(values, [0, 1, 2, 3]);
        assert!(bus.write(0x10, &values));
        assert!(bus.read(0x15, &mut values));
        assert_eq!(values, [5, 6, 7, 8]);
        assert!(bus.write(0x15, &values));
    }

    #[test]
    fn busrange_cmp_and_clone() {
        assert_eq!(BusRange(0x10, 2), BusRange(0x10, 3));
        assert_eq!(BusRange(0x10, 2), BusRange(0x10, 2));

        assert!(BusRange(0x10, 2) < BusRange(0x12, 1));
        assert!(BusRange(0x10, 2) < BusRange(0x12, 3));

        let bus_range = BusRange(0x10, 2);
        assert_eq!(bus_range, bus_range.clone());

        let mut bus = Bus::new();
        let mut data = [1, 2, 3, 4];
        assert!(
            bus.insert(Arc::new(Mutex::new(DummyDevice)), 0x10, 0x10)
                .is_ok()
        );
        assert!(bus.write(0x10, &mut data));
        let bus_clone = bus.clone();
        assert!(bus.read(0x10, &mut data));
        assert_eq!(data, [1, 2, 3, 4]);
        assert!(bus_clone.read(0x10, &mut data));
        assert_eq!(data, [1, 2, 3, 4]);
    }
}
<commit_msg>devices: replace unwrap with expect<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Handles routing to devices in an address space.

use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::collections::btree_map::BTreeMap;
use std::result;
use std::sync::{Arc, Mutex};

/// Trait for devices that respond to reads or writes in an arbitrary address space.
///
/// The device does not care where it exists in address space as each method is only given an offset
/// into its allocated portion of address space.
#[allow(unused_variables)]
pub trait BusDevice: Send {
    /// Reads at `offset` from this device
    fn read(&mut self, offset: u64, data: &mut [u8]) {}
    /// Writes at `offset` into this device
    fn write(&mut self, offset: u64, data: &[u8]) {}
    /// Triggers the `irq_mask` interrupt on this device
    fn interrupt(&self, irq_mask: u32) {}
}

#[derive(Debug)]
pub enum Error {
    /// The insertion failed because the new device overlapped with an old device.
    Overlap,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Copy, Clone)]
struct BusRange(u64, u64);

impl Eq for BusRange {}

impl PartialEq for BusRange {
    fn eq(&self, other: &BusRange) -> bool {
        self.0 == other.0
    }
}

impl Ord for BusRange {
    fn cmp(&self, other: &BusRange) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for BusRange {
    fn partial_cmp(&self, other: &BusRange) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

/// A device container for routing reads and writes over some address space.
///
/// This doesn't have any restrictions on what kind of device or address space this applies to. The
/// only restriction is that no two devices can overlap in this address space.
#[derive(Clone)]
pub struct Bus {
    devices: BTreeMap<BusRange, Arc<Mutex<BusDevice>>>,
}

impl Bus {
    /// Constructs an a bus with an empty address space.
    pub fn new() -> Bus {
        Bus {
            devices: BTreeMap::new(),
        }
    }

    fn first_before(&self, addr: u64) -> Option<(BusRange, &Mutex<BusDevice>)> {
        // for when we switch to rustc 1.17: self.devices.range(..addr).iter().rev().next()
        for (range, dev) in self.devices.iter().rev() {
            if range.0 <= addr {
                return Some((*range, dev));
            }
        }
        None
    }

    pub fn get_device(&self, addr: u64) -> Option<(u64, &Mutex<BusDevice>)> {
        if let Some((BusRange(start, len), dev)) = self.first_before(addr) {
            let offset = addr - start;
            if offset < len {
                return Some((offset, dev));
            }
        }
        None
    }

    /// Puts the given device at the given address space.
    pub fn insert(&mut self, device: Arc<Mutex<BusDevice>>, base: u64, len: u64) -> Result<()> {
        if len == 0 {
            return Err(Error::Overlap);
        }

        // Reject all cases where the new device's base is within an old device's range.
        if self.get_device(base).is_some() {
            return Err(Error::Overlap);
        }

        // The above check will miss an overlap in which the new device's base address is before the
        // range of another device. To catch that case, we search for a device with a range before
        // the new device's range's end. If there is no existing device in that range that starts
        // after the new device, then there will be no overlap.
        if let Some((BusRange(start, _), _)) = self.first_before(base + len - 1) {
            // Such a device only conflicts with the new device if it also starts after the new
            // device because of our initial `get_device` check above.
            if start >= base {
                return Err(Error::Overlap);
            }
        }

        if self.devices.insert(BusRange(base, len), device).is_some() {
            return Err(Error::Overlap);
        }

        Ok(())
    }

    /// Reads data from the device that owns the range containing `addr` and puts it into `data`.
    ///
    /// Returns true on success, otherwise `data` is untouched.
    pub fn read(&self, addr: u64, data: &mut [u8]) -> bool {
        if let Some((offset, dev)) = self.get_device(addr) {
            // OK to unwrap as lock() failing is a serious error condition and should panic.
            dev.lock()
                .expect("Failed to acquire device lock")
                .read(offset, data);
            true
        } else {
            false
        }
    }

    /// Writes `data` to the device that owns the range containing `addr`.
    ///
    /// Returns true on success, otherwise `data` is untouched.
    pub fn write(&self, addr: u64, data: &[u8]) -> bool {
        if let Some((offset, dev)) = self.get_device(addr) {
            // OK to unwrap as lock() failing is a serious error condition and should panic.
            dev.lock()
                .expect("Failed to acquire device lock")
                .write(offset, data);
            true
        } else {
            false
        }
    }
}

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

    struct DummyDevice;
    impl BusDevice for DummyDevice {}

    struct ConstantDevice;
    impl BusDevice for ConstantDevice {
        fn read(&mut self, offset: u64, data: &mut [u8]) {
            for (i, v) in data.iter_mut().enumerate() {
                *v = (offset as u8) + (i as u8);
            }
        }

        fn write(&mut self, offset: u64, data: &[u8]) {
            for (i, v) in data.iter().enumerate() {
                assert_eq!(*v, (offset as u8) + (i as u8))
            }
        }
    }

    #[test]
    fn bus_insert() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(DummyDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());

        let result = bus.insert(dummy.clone(), 0x0f, 0x10);
        assert!(result.is_err());
        assert_eq!(format!("{:?}", result), "Err(Overlap)");

        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_err());
        assert!(bus.insert(dummy.clone(), 0x10, 0x15).is_err());
        assert!(bus.insert(dummy.clone(), 0x12, 0x15).is_err());
        assert!(bus.insert(dummy.clone(), 0x12, 0x01).is_err());
        assert!(bus.insert(dummy.clone(), 0x0, 0x20).is_err());
        assert!(bus.insert(dummy.clone(), 0x20, 0x05).is_ok());
        assert!(bus.insert(dummy.clone(), 0x25, 0x05).is_ok());
        assert!(bus.insert(dummy.clone(), 0x0, 0x10).is_ok());
    }

    #[test]
    fn bus_read_write() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(DummyDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
        assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x10, &[0, 0, 0, 0]));
        assert!(bus.read(0x11, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x11, &[0, 0, 0, 0]));
        assert!(bus.read(0x16, &mut [0, 0, 0, 0]));
        assert!(bus.write(0x16, &[0, 0, 0, 0]));
        assert!(!bus.read(0x20, &mut [0, 0, 0, 0]));
        assert!(!bus.write(0x20, &mut [0, 0, 0, 0]));
        assert!(!bus.read(0x06, &mut [0, 0, 0, 0]));
        assert!(!bus.write(0x06, &mut [0, 0, 0, 0]));
    }

    #[test]
    fn bus_read_write_values() {
        let mut bus = Bus::new();
        let dummy = Arc::new(Mutex::new(ConstantDevice));
        assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());

        let mut values = [0, 1, 2, 3];
        assert!(bus.read(0x10, &mut values));
        assert_eq!(values, [0, 1, 2, 3]);
        assert!(bus.write(0x10, &values));
        assert!(bus.read(0x15, &mut values));
        assert_eq!(values, [5, 6, 7, 8]);
        assert!(bus.write(0x15, &values));
    }

    #[test]
    fn busrange_cmp_and_clone() {
        assert_eq!(BusRange(0x10, 2), BusRange(0x10, 3));
        assert_eq!(BusRange(0x10, 2), BusRange(0x10, 2));

        assert!(BusRange(0x10, 2) < BusRange(0x12, 1));
        assert!(BusRange(0x10, 2) < BusRange(0x12, 3));

        let bus_range = BusRange(0x10, 2);
        assert_eq!(bus_range, bus_range.clone());

        let mut bus = Bus::new();
        let mut data = [1, 2, 3, 4];
        assert!(
            bus.insert(Arc::new(Mutex::new(DummyDevice)), 0x10, 0x10)
                .is_ok()
        );
        assert!(bus.write(0x10, &mut data));
        let bus_clone = bus.clone();
        assert!(bus.read(0x10, &mut data));
        assert_eq!(data, [1, 2, 3, 4]);
        assert!(bus_clone.read(0x10, &mut data));
        assert_eq!(data, [1, 2, 3, 4]);
    }
}
<|endoftext|>


<commit_before>use std::convert::TryInto;
use std::io::prelude::*;

use crate::deserialize::{self, FromSql};
use crate::pg::{Pg, PgValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types::MacAddr;

#[allow(dead_code)]
mod foreign_derives {
    use super::*;
    use crate::deserialize::FromSqlRow;
    use crate::expression::AsExpression;

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = MacAddr)]
    struct ByteArrayProxy([u8; 6]);
}

#[cfg(all(feature = "postgres_backend", feature = "network-address"))]
impl FromSql<MacAddr, Pg> for [u8; 6] {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        value
            .as_bytes()
            .try_into()
            .map_err(|_| "invalid network address format: input isn't 6 bytes.".into())
    }
}

#[cfg(all(feature = "postgres_backend", feature = "network-address"))]
impl ToSql<MacAddr, Pg> for [u8; 6] {
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
        out.write_all(&self[..])
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

#[test]
fn macaddr_roundtrip() {
    use crate::query_builder::bind_collector::ByteWrapper;

    let mut buffer = Vec::new();
    let mut bytes = Output::test(ByteWrapper(&mut buffer));
    let input_address = [0x52, 0x54, 0x00, 0xfb, 0xc6, 0x16];
    ToSql::<MacAddr, Pg>::to_sql(&input_address, &mut bytes).unwrap();
    let output_address: [u8; 6] = FromSql::from_sql(PgValue::for_test(&buffer)).unwrap();
    assert_eq!(input_address, output_address);
}
<commit_msg>Fix cfgs in the mac_addr module<commit_after>use std::convert::TryInto;
use std::io::prelude::*;

use crate::deserialize::{self, FromSql};
use crate::pg::{Pg, PgValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types::MacAddr;

#[allow(dead_code)]
mod foreign_derives {
    use super::*;
    use crate::deserialize::FromSqlRow;
    use crate::expression::AsExpression;

    #[derive(AsExpression, FromSqlRow)]
    #[diesel(foreign_derive)]
    #[diesel(sql_type = MacAddr)]
    struct ByteArrayProxy([u8; 6]);
}

#[cfg(feature = "postgres_backend")]
impl FromSql<MacAddr, Pg> for [u8; 6] {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        value
            .as_bytes()
            .try_into()
            .map_err(|_| "invalid network address format: input isn't 6 bytes.".into())
    }
}

#[cfg(feature = "postgres_backend")]
impl ToSql<MacAddr, Pg> for [u8; 6] {
    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
        out.write_all(&self[..])
            .map(|_| IsNull::No)
            .map_err(Into::into)
    }
}

#[test]
fn macaddr_roundtrip() {
    use crate::query_builder::bind_collector::ByteWrapper;

    let mut buffer = Vec::new();
    let mut bytes = Output::test(ByteWrapper(&mut buffer));
    let input_address = [0x52, 0x54, 0x00, 0xfb, 0xc6, 0x16];
    ToSql::<MacAddr, Pg>::to_sql(&input_address, &mut bytes).unwrap();
    let output_address: [u8; 6] = FromSql::from_sql(PgValue::for_test(&buffer)).unwrap();
    assert_eq!(input_address, output_address);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gleam::gl;
use glutin;
use std::env;
use std::path::PathBuf;
use webrender;
use winit;
use webrender::{DebugFlags, ShaderPrecacheFlags};
use webrender::api::*;
use webrender::api::units::*;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<dyn RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

pub trait HandyDandyRectBuilder {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect;
    fn by(&self, w: i32, h: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32
// values to build a f32 LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32),
        )
    }

    fn by(&self, w: i32, h: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new(w as f32, h as f32),
        )
    }
}

pub trait Example {
    const TITLE: &'static str = "WebRender Sample App";
    const PRECACHE_SHADER_FLAGS: ShaderPrecacheFlags = ShaderPrecacheFlags::EMPTY;
    const WIDTH: u32 = 1920;
    const HEIGHT: u32 = 1080;

    fn render(
        &mut self,
        api: &mut RenderApi,
        builder: &mut DisplayListBuilder,
        txn: &mut Transaction,
        device_size: DeviceIntSize,
        pipeline_id: PipelineId,
        document_id: DocumentId,
    );
    fn on_event(
        &mut self,
        _: winit::WindowEvent,
        _: &mut RenderApi,
        _: DocumentId,
    ) -> bool {
        false
    }
    fn get_image_handlers(
        &mut self,
        _gl: &dyn gl::Gl,
    ) -> (Option<Box<dyn ExternalImageHandler>>,
          Option<Box<dyn OutputImageHandler>>) {
        (None, None)
    }
    fn draw_custom(&mut self, _gl: &dyn gl::Gl) {
    }
}

pub fn main_wrapper<E: Example>(
    example: &mut E,
    options: Option<webrender::RendererOptions>,
) {
    env_logger::init();

    #[cfg(target_os = "macos")]
    {
        use core_foundation::{self as cf, base::TCFType};
        let i = cf::bundle::CFBundle::main_bundle().info_dictionary();
        let mut i = unsafe { i.to_mutable() };
        i.set(
            cf::string::CFString::new("NSSupportsAutomaticGraphicsSwitching"),
            cf::boolean::CFBoolean::true_value().into_CFType(),
        );
    }

    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let mut events_loop = winit::EventsLoop::new();
    let window_builder = winit::WindowBuilder::new()
        .with_title(E::TITLE)
        .with_multitouch()
        .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
    let windowed_context = glutin::ContextBuilder::new()
        .with_gl(glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2),
            opengles_version: (3, 0),
        })
        .build_windowed(window_builder, &events_loop)
        .unwrap();

    let windowed_context = unsafe { windowed_context.make_current().unwrap() };

    let gl = match windowed_context.get_api() {
        glutin::Api::OpenGl => unsafe {
            gl::GlFns::load_with(
                |symbol| windowed_context.get_proc_address(symbol) as *const _
            )
        },
        glutin::Api::OpenGlEs => unsafe {
            gl::GlesFns::load_with(
                |symbol| windowed_context.get_proc_address(symbol) as *const _
            )
        },
        glutin::Api::WebGl => unimplemented!(),
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);
    let device_pixel_ratio = windowed_context.window().get_hidpi_factor() as f32;
    println!("Device pixel ratio: {}", device_pixel_ratio);

    println!("Loading shaders...");
    let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES | DebugFlags::TEXTURE_CACHE_DBG;
    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        precache_flags: E::PRECACHE_SHADER_FLAGS,
        device_pixel_ratio,
        clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        debug_flags,
        //allow_texture_swizzling: false,
        ..options.unwrap_or(webrender::RendererOptions::default())
    };

    let device_size = {
        let size = windowed_context
            .window()
            .get_inner_size()
            .unwrap()
            .to_physical(device_pixel_ratio as f64);
        DeviceIntSize::new(size.width as i32, size.height as i32)
    };
    let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
    let (mut renderer, sender) = webrender::Renderer::new(
        gl.clone(),
        notifier,
        opts,
        None,
        device_size,
    ).unwrap();
    let mut api = sender.create_api();
    let document_id = api.add_document(device_size, 0);

    let (external, output) = example.get_image_handlers(&*gl);

    if let Some(output_image_handler) = output {
        renderer.set_output_image_handler(output_image_handler);
    }

    if let Some(external_image_handler) = external {
        renderer.set_external_image_handler(external_image_handler);
    }

    let epoch = Epoch(0);
    let pipeline_id = PipelineId(0, 0);
    let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
    let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
    let mut txn = Transaction::new();

    example.render(
        &mut api,
        &mut builder,
        &mut txn,
        device_size,
        pipeline_id,
        document_id,
    );
    txn.set_display_list(
        epoch,
        Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        layout_size,
        builder.finalize(),
        true,
    );
    txn.set_root_pipeline(pipeline_id);
    txn.generate_frame();
    api.send_transaction(document_id, txn);

    println!("Entering event loop");
    events_loop.run_forever(|global_event| {
        let mut txn = Transaction::new();
        let mut custom_event = true;

        let old_flags = debug_flags;
        let win_event = match global_event {
            winit::Event::WindowEvent { event, .. } => event,
            _ => return winit::ControlFlow::Continue,
        };
        match win_event {
            winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break,
            // skip high-frequency events
            winit::WindowEvent::AxisMotion { .. } |
            winit::WindowEvent::CursorMoved { .. } => return winit::ControlFlow::Continue,
            winit::WindowEvent::KeyboardInput {
                input: winit::KeyboardInput {
                    state: winit::ElementState::Pressed,
                    virtual_keycode: Some(key),
                    ..
                },
                ..
            } => match key {
                winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
                winit::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
                winit::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
                winit::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
                winit::VirtualKeyCode::S => debug_flags.toggle(DebugFlags::COMPACT_PROFILER),
                winit::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
                winit::VirtualKeyCode::Q => debug_flags.toggle(
                    DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
                ),
                winit::VirtualKeyCode::F => debug_flags.toggle(
                    DebugFlags::NEW_FRAME_INDICATOR | DebugFlags::NEW_SCENE_INDICATOR
                ),
                winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
                winit::VirtualKeyCode::Key1 => txn.set_document_view(
                    device_size.into(),
                    1.0
                ),
                winit::VirtualKeyCode::Key2 => txn.set_document_view(
                    device_size.into(),
                    2.0
                ),
                winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                winit::VirtualKeyCode::C => {
                    let path: PathBuf = "../captures/example".into();
                    //TODO: switch between SCENE/FRAME capture types
                    // based on "shift" modifier, when `glutin` is updated.
                    let bits = CaptureBits::all();
                    api.save_capture(path, bits);
                },
                _ => {
                    custom_event = example.on_event(
                        win_event,
                        &mut api,
                        document_id,
                    )
                },
            },
            other => custom_event = example.on_event(
                other,
                &mut api,
                document_id,
            ),
        };

        if debug_flags != old_flags {
            api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
        }

        if custom_event {
            let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);

            example.render(
                &mut api,
                &mut builder,
                &mut txn,
                device_size,
                pipeline_id,
                document_id,
            );
            txn.set_display_list(
                epoch,
                Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
                layout_size,
                builder.finalize(),
                true,
            );
            txn.generate_frame();
        }
        api.send_transaction(document_id, txn);

        renderer.update();
        renderer.render(device_size).unwrap();
        let _ = renderer.flush_pipeline_info();
        example.draw_custom(&*gl);
        windowed_context.swap_buffers().ok();

        winit::ControlFlow::Continue
    });

    renderer.deinit();
}
<commit_msg>Auto merge of #3963 - moz-gfx:github-sync, r=auto<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gleam::gl;
use glutin;
use std::env;
use std::path::PathBuf;
use webrender;
use winit;
use webrender::{DebugFlags, ShaderPrecacheFlags};
use webrender::api::*;
use webrender::api::units::*;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<dyn RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

pub trait HandyDandyRectBuilder {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect;
    fn by(&self, w: i32, h: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32
// values to build a f32 LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32),
        )
    }

    fn by(&self, w: i32, h: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new(w as f32, h as f32),
        )
    }
}

pub trait Example {
    const TITLE: &'static str = "WebRender Sample App";
    const PRECACHE_SHADER_FLAGS: ShaderPrecacheFlags = ShaderPrecacheFlags::EMPTY;
    const WIDTH: u32 = 1920;
    const HEIGHT: u32 = 1080;

    fn render(
        &mut self,
        api: &mut RenderApi,
        builder: &mut DisplayListBuilder,
        txn: &mut Transaction,
        device_size: DeviceIntSize,
        pipeline_id: PipelineId,
        document_id: DocumentId,
    );
    fn on_event(
        &mut self,
        _: winit::WindowEvent,
        _: &mut RenderApi,
        _: DocumentId,
    ) -> bool {
        false
    }
    fn get_image_handlers(
        &mut self,
        _gl: &dyn gl::Gl,
    ) -> (Option<Box<dyn ExternalImageHandler>>,
          Option<Box<dyn OutputImageHandler>>) {
        (None, None)
    }
    fn draw_custom(&mut self, _gl: &dyn gl::Gl) {
    }
}

pub fn main_wrapper<E: Example>(
    example: &mut E,
    options: Option<webrender::RendererOptions>,
) {
    env_logger::init();

    #[cfg(target_os = "macos")]
    {
        use core_foundation::{self as cf, base::TCFType};
        let i = cf::bundle::CFBundle::main_bundle().info_dictionary();
        let mut i = unsafe { i.to_mutable() };
        i.set(
            cf::string::CFString::new("NSSupportsAutomaticGraphicsSwitching"),
            cf::boolean::CFBoolean::true_value().into_CFType(),
        );
    }

    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let mut events_loop = winit::EventsLoop::new();
    let window_builder = winit::WindowBuilder::new()
        .with_title(E::TITLE)
        .with_multitouch()
        .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
    let windowed_context = glutin::ContextBuilder::new()
        .with_gl(glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2),
            opengles_version: (3, 0),
        })
        .build_windowed(window_builder, &events_loop)
        .unwrap();

    let windowed_context = unsafe { windowed_context.make_current().unwrap() };

    let gl = match windowed_context.get_api() {
        glutin::Api::OpenGl => unsafe {
            gl::GlFns::load_with(
                |symbol| windowed_context.get_proc_address(symbol) as *const _
            )
        },
        glutin::Api::OpenGlEs => unsafe {
            gl::GlesFns::load_with(
                |symbol| windowed_context.get_proc_address(symbol) as *const _
            )
        },
        glutin::Api::WebGl => unimplemented!(),
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);
    let device_pixel_ratio = windowed_context.window().get_hidpi_factor() as f32;
    println!("Device pixel ratio: {}", device_pixel_ratio);

    println!("Loading shaders...");
    let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES | DebugFlags::TEXTURE_CACHE_DBG;
    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        precache_flags: E::PRECACHE_SHADER_FLAGS,
        device_pixel_ratio,
        clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        debug_flags,
        //allow_texture_swizzling: false,
        ..options.unwrap_or(webrender::RendererOptions::default())
    };

    let device_size = {
        let size = windowed_context
            .window()
            .get_inner_size()
            .unwrap()
            .to_physical(device_pixel_ratio as f64);
        DeviceIntSize::new(size.width as i32, size.height as i32)
    };
    let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
    let (mut renderer, sender) = webrender::Renderer::new(
        gl.clone(),
        notifier,
        opts,
        None,
        device_size,
    ).unwrap();
    let mut api = sender.create_api();
    let document_id = api.add_document(device_size, 0);

    let (external, output) = example.get_image_handlers(&*gl);

    if let Some(output_image_handler) = output {
        renderer.set_output_image_handler(output_image_handler);
    }

    if let Some(external_image_handler) = external {
        renderer.set_external_image_handler(external_image_handler);
    }

    let epoch = Epoch(0);
    let pipeline_id = PipelineId(0, 0);
    let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
    let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
    let mut txn = Transaction::new();

    example.render(
        &mut api,
        &mut builder,
        &mut txn,
        device_size,
        pipeline_id,
        document_id,
    );
    txn.set_display_list(
        epoch,
        Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        layout_size,
        builder.finalize(),
        true,
    );
    txn.set_root_pipeline(pipeline_id);
    txn.generate_frame();
    api.send_transaction(document_id, txn);

    println!("Entering event loop");
    events_loop.run_forever(|global_event| {
        let mut txn = Transaction::new();
        let mut custom_event = true;

        let old_flags = debug_flags;
        let win_event = match global_event {
            winit::Event::WindowEvent { event, .. } => event,
            _ => return winit::ControlFlow::Continue,
        };
        match win_event {
            winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break,
            winit::WindowEvent::AxisMotion { .. } |
            winit::WindowEvent::CursorMoved { .. } => {
                custom_event = example.on_event(
                        win_event,
                        &mut api,
                        document_id,
                    );
                // skip high-frequency events from triggering a frame draw.
                if !custom_event {
                    return winit::ControlFlow::Continue;
                }
            },
            winit::WindowEvent::KeyboardInput {
                input: winit::KeyboardInput {
                    state: winit::ElementState::Pressed,
                    virtual_keycode: Some(key),
                    ..
                },
                ..
            } => match key {
                winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
                winit::VirtualKeyCode::P => debug_flags.toggle(DebugFlags::PROFILER_DBG),
                winit::VirtualKeyCode::O => debug_flags.toggle(DebugFlags::RENDER_TARGET_DBG),
                winit::VirtualKeyCode::I => debug_flags.toggle(DebugFlags::TEXTURE_CACHE_DBG),
                winit::VirtualKeyCode::S => debug_flags.toggle(DebugFlags::COMPACT_PROFILER),
                winit::VirtualKeyCode::T => debug_flags.toggle(DebugFlags::PICTURE_CACHING_DBG),
                winit::VirtualKeyCode::Q => debug_flags.toggle(
                    DebugFlags::GPU_TIME_QUERIES | DebugFlags::GPU_SAMPLE_QUERIES
                ),
                winit::VirtualKeyCode::F => debug_flags.toggle(
                    DebugFlags::NEW_FRAME_INDICATOR | DebugFlags::NEW_SCENE_INDICATOR
                ),
                winit::VirtualKeyCode::G => debug_flags.toggle(DebugFlags::GPU_CACHE_DBG),
                winit::VirtualKeyCode::Key1 => txn.set_document_view(
                    device_size.into(),
                    1.0
                ),
                winit::VirtualKeyCode::Key2 => txn.set_document_view(
                    device_size.into(),
                    2.0
                ),
                winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                winit::VirtualKeyCode::C => {
                    let path: PathBuf = "../captures/example".into();
                    //TODO: switch between SCENE/FRAME capture types
                    // based on "shift" modifier, when `glutin` is updated.
                    let bits = CaptureBits::all();
                    api.save_capture(path, bits);
                },
                _ => {
                    custom_event = example.on_event(
                        win_event,
                        &mut api,
                        document_id,
                    )
                },
            },
            other => custom_event = example.on_event(
                other,
                &mut api,
                document_id,
            ),
        };

        if debug_flags != old_flags {
            api.send_debug_cmd(DebugCommand::SetFlags(debug_flags));
        }

        if custom_event {
            let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);

            example.render(
                &mut api,
                &mut builder,
                &mut txn,
                device_size,
                pipeline_id,
                document_id,
            );
            txn.set_display_list(
                epoch,
                Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
                layout_size,
                builder.finalize(),
                true,
            );
            txn.generate_frame();
        }
        api.send_transaction(document_id, txn);

        renderer.update();
        renderer.render(device_size).unwrap();
        let _ = renderer.flush_pipeline_info();
        example.draw_custom(&*gl);
        windowed_context.swap_buffers().ok();

        winit::ControlFlow::Continue
    });

    renderer.deinit();
}
<|endoftext|>


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

trait Graph {
	fn graph_fn(&self) -> u32 ;
}
trait GraphMut: Graph {
	fn graph_mut(&mut self) -> &mut u32;
}

trait BaseConstraint: Sized {
	type Graph: Graph;
	fn get_graph(&self) -> &Self::Graph;
}
trait BaseConstraintMut: BaseConstraint
{
	type GraphMut: GraphMut;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut;
}
trait Constraint: Sized
{
	type Base:  BaseConstraint;
	type Constrained: Constraint<Base=Self::Base>;

	fn base_single(&self) -> &Self::Constrained;
	fn unconstrain_single(self) -> Self::Constrained;
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()>;

	fn unconstrain(self) -> Self::Base{
		self.unconstrain_single().unconstrain()
	}
	fn constrain(g: Self::Base) -> Result<Self, ()>{
		Self::constrain_single(Self::Constrained::constrain(g)?)
	}
	fn base(&self) -> &<Self::Base as BaseConstraint>::Graph {
		self.base_single().base()
	}

}
trait ConstraintMut: Constraint
{
	type BaseMut:  BaseConstraintMut;
	type ConstrainedMut: ConstraintMut<BaseMut=Self::BaseMut>;
	fn base_single_mut(&mut self) -> &mut Self::ConstrainedMut;
	fn base_mut(&mut self) -> &mut <Self::BaseMut as BaseConstraintMut>::GraphMut {
		self.base_single_mut().base_mut()
	}
}

impl<B: BaseConstraint> Constraint for B{
	type Base = Self;
	type Constrained = Self;

	fn base_single(&self) -> &Self::Constrained { &self }
	fn unconstrain_single(self) -> Self::Constrained { self }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> { Ok(g)}

	fn unconstrain(self) -> Self::Base { self }
	fn constrain(g: Self::Base) -> Result<Self, ()>{ Ok(g) }
	fn base(&self) -> &<Self::Base as BaseConstraint>::Graph { self.get_graph() }
}
impl<B: BaseConstraintMut> ConstraintMut for B{
	type BaseMut = Self;
	type ConstrainedMut = Self;
	fn base_single_mut(&mut self) -> &mut Self::Constrained { self }
	fn base_mut(&mut self) -> &mut <Self::BaseMut as BaseConstraintMut>::GraphMut {
		self.get_graph_mut()
	}
}

impl<G: Graph, D: Deref<Target=G>> BaseConstraint for D
{
	type Graph = G;
	fn get_graph(&self) -> &Self::Graph {&**self}
}
impl<G: GraphMut, D: DerefMut<Target=G>> BaseConstraintMut for D
{
	type GraphMut = G;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut {&mut **self}
}

struct BaseGraph(u32);
impl Graph for BaseGraph{
	fn graph_fn(&self) -> u32 {
		self.0
	}
}
impl GraphMut for BaseGraph {
	fn graph_mut(&mut self) -> &mut u32 { &mut self.0 }
}
impl BaseConstraint for BaseGraph {
	type Graph = Self;
	fn get_graph(&self) -> &Self::Graph {self}
}
impl BaseConstraintMut for BaseGraph{
	type GraphMut = Self;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut {self}
}

struct Connected<C: Constraint>(C);
impl<C: Constraint> Graph for Connected<C>{
	fn graph_fn(&self) -> u32 {
		self.base().graph_fn()
	}
}
impl<C: ConstraintMut> GraphMut for Connected<C>
{
	fn graph_mut(&mut self) -> &mut u32 { self.0.base_mut().graph_mut() }
}
impl<C: Constraint> Constraint for Connected<C>
{
	type Base = C::Base;
	type Constrained = C;

	fn base_single(&self) -> &Self::Constrained { &self.0 }
	fn unconstrain_single(self) -> Self::Constrained { self.0 }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> {
		if g.base().graph_fn() < 32 {
			Ok(Self(g))
		} else {
			Err(())
		}

	}
}
impl<C: ConstraintMut> ConstraintMut for Connected<C>
{
	type BaseMut = C::BaseMut;
	type ConstrainedMut = C;

	fn base_single_mut(&mut self) -> &mut Self::Constrained { &mut self.0 }
}

#[test]
fn test(){
	let mut g = BaseGraph(16);
	assert_eq!(g.graph_fn(), 16);

	let c_ref = Connected::constrain_single(&g).unwrap();
	assert_eq!(c_ref.graph_fn(), 16);

	let mut c_ref_mut = Connected::constrain_single(&mut g).unwrap();
	*c_ref_mut.graph_mut() = 30;
	assert_eq!(c_ref_mut.graph_fn(), 30);

	let c_owned = Connected::constrain_single(g).unwrap();
	assert_eq!(c_owned.graph_fn(), 30);

}<commit_msg>Tested new design<commit_after>use std::ops::{Deref, DerefMut};

trait Graph {
	fn graph_fn(&self) -> u32 ;
}
trait GraphMut: Graph {
	fn graph_mut(&mut self) -> &mut u32;
}

trait BaseConstraint: Sized {
	type Graph: Graph;
	fn get_graph(&self) -> &Self::Graph;
	fn constrain<G>(self) -> Result<G, ()>
		where G: Constraint<Base=Self>
	{
		G::constrain(self)
	}
}
trait BaseConstraintMut: BaseConstraint
{
	type GraphMut: GraphMut;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut;
}
trait Constraint: Sized
{
	type Base:  BaseConstraint;
	type Constrained: Constraint<Base=Self::Base>;

	fn base_single(&self) -> &Self::Constrained;
	fn unconstrain_single(self) -> Self::Constrained;
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()>;

	fn unconstrain(self) -> Self::Base{
		self.unconstrain_single().unconstrain()
	}
	fn constrain(g: Self::Base) -> Result<Self, ()>{
		Self::constrain_single(Self::Constrained::constrain(g)?)
	}
	fn base(&self) -> &<Self::Base as BaseConstraint>::Graph {
		self.base_single().base()
	}

}
trait ConstraintMut: Constraint
{
	type BaseMut:  BaseConstraintMut;
	type ConstrainedMut: ConstraintMut<BaseMut=Self::BaseMut>;
	fn base_single_mut(&mut self) -> &mut Self::ConstrainedMut;
	fn base_mut(&mut self) -> &mut <Self::BaseMut as BaseConstraintMut>::GraphMut {
		self.base_single_mut().base_mut()
	}
}

impl<G: Graph, D: Deref<Target=G>> BaseConstraint for D
{
	type Graph = G;
	fn get_graph(&self) -> &Self::Graph {&**self}
}
impl<G: GraphMut, D: DerefMut<Target=G>> BaseConstraintMut for D
{
	type GraphMut = G;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut {&mut **self}
}
impl<B: BaseConstraint> Constraint for B {
	type Base = Self;
	type Constrained = Self;

	fn base_single(&self) -> &Self::Constrained { &self }
	fn unconstrain_single(self) -> Self::Constrained { self }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> { Ok(g)}

	fn unconstrain(self) -> Self::Base { self }
	fn constrain(g: Self::Base) -> Result<Self, ()>{ Ok(g) }
	fn base(&self) -> &<Self::Base as BaseConstraint>::Graph { self.get_graph() }
}
impl<B: BaseConstraintMut> ConstraintMut for B {
	type BaseMut = Self;
	type ConstrainedMut = Self;
	fn base_single_mut(&mut self) -> &mut Self::Constrained { self }
	fn base_mut(&mut self) -> &mut <Self::BaseMut as BaseConstraintMut>::GraphMut {
		self.get_graph_mut()
	}
}

struct BaseGraph(u32);
impl BaseGraph {
	fn base_graph_fn(&self) -> u32
	{
		self.0
	}
}
impl Graph for BaseGraph{
	fn graph_fn(&self) -> u32 {
		self.0
	}
}
impl GraphMut for BaseGraph {
	fn graph_mut(&mut self) -> &mut u32 { &mut self.0 }
}
impl BaseConstraint for BaseGraph {
	type Graph = Self;
	fn get_graph(&self) -> &Self::Graph {self}
}
impl BaseConstraintMut for BaseGraph{
	type GraphMut = Self;
	fn get_graph_mut(&mut self) -> &mut Self::GraphMut {self}
}

struct Connected<C: Constraint>(C);
impl<C: Constraint> Connected<C>
{
	fn connected_fn(&self) -> u32
	{
		self.base().graph_fn()
	}
}
impl<C: Constraint> Graph for Connected<C>{
	fn graph_fn(&self) -> u32 {
		self.base().graph_fn()
	}
}
impl<C: ConstraintMut> GraphMut for Connected<C>
{
	fn graph_mut(&mut self) -> &mut u32 { self.0.base_mut().graph_mut() }
}
impl<C: Constraint> Constraint for Connected<C>
{
	type Base = C::Base;
	type Constrained = C;

	fn base_single(&self) -> &Self::Constrained { &self.0 }
	fn unconstrain_single(self) -> Self::Constrained { self.0 }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> {
		if g.base().graph_fn() < 32 {
			Ok(Self(g))
		} else {
			Err(())
		}

	}
}
impl<C: ConstraintMut> ConstraintMut for Connected<C>
{
	type BaseMut = C::BaseMut;
	type ConstrainedMut = C;

	fn base_single_mut(&mut self) -> &mut Self::ConstrainedMut { &mut self.0 }
}

#[test]
fn constrainer_constraining_base(){
	type ConstrainedGraphRef<'a> =
	Connected<
		Connected<
			&'a BaseGraph
		>>;

	let mut g = BaseGraph(16);
	assert_eq!(g.graph_fn(), 16);

	let c_ref = ConstrainedGraphRef::constrain(&g).unwrap();
	assert_eq!(c_ref.connected_fn(), 16);

	type ConstrainedGraphMut<'a> =
	Connected<
		Connected<
			&'a mut BaseGraph
		>>;

	let mut c_ref_mut = ConstrainedGraphMut::constrain(&mut g).unwrap();
	*c_ref_mut.graph_mut() = 30;
	assert_eq!(c_ref_mut.connected_fn(), 30);

	type ConstrainedGraph<'a> =
	Connected<
		Connected<
			BaseGraph
		>>;

	let c_owned = ConstrainedGraph::constrain(g).unwrap();
	assert_eq!(c_owned.connected_fn(), 30);

}

#[test]
fn inline_constrainer_constraining_base(){

	let mut g = BaseGraph(16);
	assert_eq!(g.graph_fn(), 16);

	let c_ref = <Connected<Connected<&BaseGraph>>>::constrain(&g).unwrap();
	assert_eq!(c_ref.connected_fn(), 16);

	let mut c_ref_mut = <Connected<Connected<&mut BaseGraph>>>::constrain(&mut g).unwrap();
	*c_ref_mut.graph_mut() = 30;
	assert_eq!(c_ref_mut.connected_fn(), 30);

	let c_owned = <Connected<Connected<BaseGraph>>>::constrain(g).unwrap();
	assert_eq!(c_owned.connected_fn(), 30);

}

#[test]
fn base_constrains_self_by_constraint_inference(){
	type ConstrainedGraph<G> = Connected< Connected< Connected<G> > >;

	let mut g = BaseGraph(16);
	assert_eq!(g.graph_fn(), 16);

	let c_ref: ConstrainedGraph<&BaseGraph> = (&g).constrain().unwrap();
	assert_eq!(c_ref.connected_fn(), 16);
	let c_ref_unc = c_ref.unconstrain_single();
	assert_eq!(c_ref_unc.connected_fn(), 16);

	let mut c_ref_mut: ConstrainedGraph<&mut BaseGraph> = (&mut g).constrain().unwrap();
	*c_ref_mut.graph_mut() = 30;
	assert_eq!(c_ref_mut.connected_fn(), 30);
	let mut c_ref_mut_unc = c_ref_mut.unconstrain_single();
	assert_eq!(c_ref_mut_unc.connected_fn(), 30);
	*c_ref_mut_unc.graph_mut() = 31;
	assert_eq!(c_ref_mut_unc.connected_fn(), 31);

	let c_owned: ConstrainedGraph<BaseGraph> = g.constrain().unwrap();
	assert_eq!(c_owned.connected_fn(), 31);
	let c_owned_unc = c_owned.unconstrain_single();
	assert_eq!(c_owned_unc.connected_fn(), 31);
	let g2 = c_owned_unc.unconstrain();
	assert_eq!(g2.base_graph_fn(), 31);
}

#[test]
fn base_constrains_self_by_inline_constraint_inference(){

	let mut g = BaseGraph(16);
	assert_eq!(g.graph_fn(), 16);

	let c_ref: Connected<Connected<Connected<&BaseGraph>>> = (&g).constrain().unwrap();
	assert_eq!(c_ref.connected_fn(), 16);
	let c_ref_unc = c_ref.unconstrain_single();
	assert_eq!(c_ref_unc.connected_fn(), 16);

	let mut c_ref_mut: Connected<Connected<Connected<&mut BaseGraph>>> = (&mut g).constrain().unwrap();
	*c_ref_mut.graph_mut() = 30;
	assert_eq!(c_ref_mut.connected_fn(), 30);
	let mut c_ref_mut_unc = c_ref_mut.unconstrain_single();
	assert_eq!(c_ref_mut_unc.connected_fn(), 30);
	*c_ref_mut_unc.graph_mut() = 31;
	assert_eq!(c_ref_mut_unc.connected_fn(), 31);

	let c_owned: Connected<Connected<Connected<BaseGraph>>> = g.constrain().unwrap();
	assert_eq!(c_owned.connected_fn(), 31);
	let c_owned_unc = c_owned.unconstrain_single();
	assert_eq!(c_owned_unc.connected_fn(), 31);
	let g2 = c_owned_unc.unconstrain();
	assert_eq!(g2.base_graph_fn(), 31);
}<|endoftext|>


<commit_before>use il;
use clang as cx;

static PREFIX: &'static str = "POSGEN_VAR_";

struct Context<'a> {
    file: &'a [u8],
    defs: &'a ::Defs,
    globals: Vec<il::Global>,
}

impl<'a> Context<'a> {
    fn conv_ptr_ty(&mut self, ty: &cx::Type) -> String {
        let mutable = if ty.is_const() {
            "const"
        } else {
            "mut"
        };
        match ty.kind() {
            cx::ll::CXType_Unexposed | cx::ll::CXType_FunctionProto
                    | cx::ll::CXType_FunctionNoProto => {
                let ret_ty = ty.ret_type();
                let decl = ty.declaration();
                if ret_ty.kind() != cx::ll::CXType_Invalid {
                    let mut ret = String::new();
                    ret.push_str("fn(");
                    for arg in ty.arg_types().iter() {
                        ret.push_str(self.type_to_str(arg).as_slice());
                        ret.push_str(", ");
                    }
                    ret.push_str(")");
                    match ret_ty.kind() {
                        cx::ll::CXType_Void => { },
                        _ => ret.push_str(format!(" -> {}", self.type_to_str(&ret_ty)).as_slice()),
                    }
                    ret
                } else if decl.kind() != cx::ll::CXCursor_NoDeclFound {
                    format!("*{} {}", mutable, self.type_to_str(&decl.cur_type()))
                } else {
                    format!("*{} ::void_t", mutable)
                }
            }
            _ => {
                format!("*{} {}", mutable, self.type_to_str(ty))
            }
        }
    }

    fn type_to_str(&mut self, ty: &cx::Type) -> String {
        self.type_to_str_int(ty, true)
    }

    fn find_type(&self, spelling: &str, skip: bool) -> Option<String> {
        let trimmed = spelling.as_slice().trim_left_chars('_');
        match self.defs.types.iter().find(|t| t.as_slice() == trimmed) {
            Some(s) => if skip { return Some(s.to_string()) },
            _ => match ::types::find(trimmed) {
                Some(t) => return Some(t.to_string()),
                _ => { },
            },
        }
        None
    }

    fn type_to_str_int(&mut self, ty: &cx::Type, skip: bool) -> String {
        match ty.kind() {
            cx::ll::CXType_SChar | cx::ll::CXType_Char_S => "::schar_t".to_string(),
            cx::ll::CXType_UChar | cx::ll::CXType_Char_U => "::uchar_t".to_string(),
            cx::ll::CXType_Void       => "::void_t".to_string(),
            cx::ll::CXType_Bool       => "::bool_t".to_string(),
            cx::ll::CXType_UShort     => "::ushort_t".to_string(),
            cx::ll::CXType_UInt       => "::uint_t".to_string(),
            cx::ll::CXType_ULong      => "::ulong_t".to_string(),
            cx::ll::CXType_ULongLong  => "::ulonglong_t".to_string(),
            cx::ll::CXType_Short      => "::short_t".to_string(),
            cx::ll::CXType_Int        => "::int_t".to_string(),
            cx::ll::CXType_Long       => "::long_t".to_string(),
            cx::ll::CXType_LongLong   => "::longlong_t".to_string(),
            cx::ll::CXType_Float      => "::float_t".to_string(),
            cx::ll::CXType_Double     => "::double_t".to_string(),
            cx::ll::CXType_LongDouble => "::longdouble_t".to_string(),
            cx::ll::CXType_Pointer => self.conv_ptr_ty(&ty.pointee_type()),
            cx::ll::CXType_Record | cx::ll::CXType_Unexposed | cx::ll::CXType_Typedef => {
                let spelling = ty.spelling();
                match self.find_type(spelling.as_slice(), skip) {
                    Some(s) => return s,
                    _ => { }
                }
                let cursor = ty.declaration();
                match cursor.kind() {
                    cx::ll::CXCursor_StructDecl | cx::ll::CXCursor_UnionDecl => {
                        let spelling = cursor.spelling();
                        match self.find_type(spelling.as_slice(), skip) {
                            Some(s) => s,
                            _ => unknown_array(ty),
                        }
                    },
                    cx::ll::CXCursor_EnumDecl => {
                        match ty.size() {
                            1 => "i8".to_string(),
                            2 => "i16".to_string(),
                            4 => "i32".to_string(),
                            8 => "i64".to_string(),
                            _ => fail!("Enum type too large"),
                        }
                    },
                    cx::ll::CXCursor_TypedefDecl => {
                        let ty = cursor.typedef_type();
                        self.type_to_str_int(&ty, skip)
                    },
                    _ => format!("UNKNOWN: {} {}", cursor.kind(), ty.kind()),
                }
            },
            cx::ll::CXType_Enum => {
                match ty.size() {
                    1 => "i8".to_string(),
                    2 => "i16".to_string(),
                    4 => "i32".to_string(),
                    8 => "i64".to_string(),
                    _ => fail!("Enum type too large"),
                }
            },
            cx::ll::CXType_ConstantArray => {
                let ts = self.type_to_str(&ty.elem_type());
                format!("[{}, ..{}]", ts, ty.array_size())
            }
            _ => format!("Can't handle type {}", ty.kind()),
        }
    }

    fn visit_struct(&mut self, cursor: &cx::Cursor,
                    fields: &mut Vec<il::Field>) -> cx::ll::Enum_CXVisitorResult {
        if cursor.kind() == cx::ll::CXCursor_FieldDecl {
            let ty = cursor.cur_type();
            let name = cursor.spelling();
            let public = !name.as_slice().starts_with("_");
            let ts = if public {
                self.type_to_str(&ty)
            } else {
                unknown_array(&ty)
            };
            let field = il::Field { name: name, ty: ts, public: public };
            fields.push(field);
        }
        cx::ll::CXChildVisit_Continue
    }

    fn visit_var(&mut self, cursor: &cx::Cursor,
                 dst: &mut Option<String>) -> cx::ll::Enum_CXVisitorResult {
        match cursor.kind() {
            cx::ll::CXCursor_DeclRefExpr => {
                let def = cursor.definition();
                if def.kind() == cx::ll::CXCursor_EnumConstantDecl {
                    *dst = Some(format!("{}", def.enum_val()));
                }
                cx::ll::CXChildVisit_Break
            },
            cx::ll::CXCursor_ParenExpr | cx::ll::CXCursor_IntegerLiteral
                    | cx::ll::CXCursor_FloatingLiteral => {
                let offset = cursor.get_location();
                let mut slc = self.file.slice_from(offset);
                slc = match slc.iter().position(|b| *b == ';' as u8) {
                    Some(p) => slc.slice_to(p),
                    _ => slc,
                };
                *dst = ::std::str::from_utf8(slc).map(|s| s.to_string());
                cx::ll::CXChildVisit_Break
            },
            _ => cx::ll::CXChildVisit_Recurse,
        }
    }

    fn handle_struct(&mut self, cursor: &cx::Cursor,
                     spelling: String) -> cx::ll::Enum_CXVisitorResult {
        let mut fields = vec!();
        cursor.visit(|c, _| {
            self.visit_struct(c, &mut fields)
        });
        let s = il::Struct {
            name: spelling,
            fields: fields,
        };
        self.globals.push(il::StructVar(s));
        if cursor.kind() == cx::ll::CXCursor_FieldDecl {
            cx::ll::CXChildVisit_Break
        } else {
            cx::ll::CXChildVisit_Recurse
        }
    }

    fn handle_typedef(&mut self, cursor: &cx::Cursor,
                      spelling: String) -> cx::ll::Enum_CXVisitorResult {
        let mut dst = cursor.typedef_type();
        if dst.kind() == cx::ll::CXType_Unexposed {
            dst = dst.canonical_type();
        }
        if dst.kind() == cx::ll::CXType_Record {
            let decl = dst.declaration();
            self.handle_struct(&decl, spelling);
        } else {
            let dst = self.type_to_str_int(&dst, false);
            let typedef = il::Typedef { name: spelling, dst: dst };
            self.globals.push(il::TypedefVar(typedef));
        }
        cx::ll::CXChildVisit_Continue
    }

    fn visit_top(&mut self, cursor: &cx::Cursor) -> cx::ll::Enum_CXVisitorResult {
        let kind = cursor.kind();
        let spelling = cursor.spelling();
        match kind {
            cx::ll::CXCursor_StructDecl | cx::ll::CXCursor_TypedefDecl => {
                if self.defs.types.iter().all(|t| t.as_slice() != spelling.as_slice()) {
                    return cx::ll::CXChildVisit_Continue;
                }
            },
            cx::ll::CXCursor_VarDecl => {
                if !spelling.as_slice().starts_with(PREFIX) {
                    return cx::ll::CXChildVisit_Continue;
                }
            },
            _ => { },
        }
        match kind {
            cx::ll::CXCursor_StructDecl => self.handle_struct(cursor, spelling),
            cx::ll::CXCursor_TypedefDecl => self.handle_typedef(cursor, spelling),
            cx::ll::CXCursor_VarDecl => {
                let real_name = spelling.as_slice().slice_from(PREFIX.len());
                let mut val = None;
                cursor.visit(|c, _| {
                    self.visit_var(c, &mut val)
                });
                let var = self.defs.consts.iter().find(|v| v.name.as_slice() == real_name);
                match (var, val) {
                    (Some(var), Some(mut val)) => {
                        if val.len() > 1 && val.as_bytes()[0] == '0' as u8 &&
                                val.as_bytes()[1] != 'x' as u8 {
                            val = format!("0o{}", val.as_slice().slice_from(1));
                        }
                        let info = il::Constant {
                            name: real_name.to_string(),
                            ty: var.rs_type.clone(),
                            val: val
                        };
                        self.globals.push(il::ConstantVar(info));
                    },
                    _ => { },
                }
                cx::ll::CXChildVisit_Continue
            }
            cx::ll::CXCursor_EnumDecl     => cx::ll::CXChildVisit_Continue,
            cx::ll::CXCursor_FunctionDecl => cx::ll::CXChildVisit_Continue,
            cx::ll::CXCursor_FieldDecl    => cx::ll::CXChildVisit_Continue,
            _ => cx::ll::CXChildVisit_Recurse,
        }
    }
}

fn unknown_array(ty: &cx::Type) -> String {
    let size = ty.size();
    let mut align = ty.align();
    if align == 0 {
        align = 1;
    }
    assert_eq!(size % align, 0);
    let ut = match align {
        0 | 1 => "u8",
        2 => "u16",
        4 => "u32",
        8 => "u64",
        _ => unreachable!(),
    };
    format!("[{}, ..{}]", ut, size / align)
}

fn preprocess(defs: &::Defs) -> ::std::io::IoResult<Vec<u8>> {
    let mut wr = ::std::io::MemWriter::new();
    try!(writeln!(wr, "#include <{}>", defs.header.as_slice()));
    for c in defs.consts.iter() {
        try!(writeln!(wr, "static const {} {}{} = {};", c.c_type.as_slice(), PREFIX,
                      c.name.as_slice(), c.name.as_slice()));
    }
    let header = wr.unwrap();
    let mut process = try!(::std::io::Command::new("clang").args(["-P", "-E", "-"]).spawn());
    process.stdin.as_mut().unwrap().write(header.as_slice()).ok();
    let output = try!(process.wait_with_output());
    if !output.status.success() {
        let mut err = ::std::io::standard_error(::std::io::InvalidInput);
        err.detail = Some(String::from_utf8_lossy(output.error.as_slice()).into_string());
        return Err(err);
    }
    Ok(output.output)
}

pub fn parse(defs: &::Defs) -> ::std::io::IoResult<Vec<il::Global>> {
    let pp = try!(preprocess(defs));
    let tmpdir = match ::std::io::TempDir::new("") {
        Ok(d) => d,
        _ => return Err(::std::io::IoError::last_error())
    };
    let mut path = tmpdir.path().clone();
    path.push("file.c");
    let mut file = try!(::std::io::fs::File::create(&path));
    try!(file.write(pp.as_slice()));
    drop(file);

    let mut ctx = Context {
        file: pp.as_slice(),
        defs: defs,
        globals: vec!(),
    };

    let ix = cx::Index::create(false, true);
    if ix.is_null() {
        return Err(::std::io::standard_error(::std::io::OtherIoError))
    }

    let unit = cx::TranslationUnit::parse(&ix, &path);
    if unit.is_null() {
        return Err(::std::io::standard_error(::std::io::OtherIoError))
    }

    let cursor = unit.cursor();

    cursor.visit(|cur, _| ctx.visit_top(cur));

    unit.dispose();
    ix.dispose();

    Ok(ctx.globals)
}
<commit_msg>Fix: Rename fail! to panic!<commit_after>use il;
use clang as cx;

static PREFIX: &'static str = "POSGEN_VAR_";

struct Context<'a> {
    file: &'a [u8],
    defs: &'a ::Defs,
    globals: Vec<il::Global>,
}

impl<'a> Context<'a> {
    fn conv_ptr_ty(&mut self, ty: &cx::Type) -> String {
        let mutable = if ty.is_const() {
            "const"
        } else {
            "mut"
        };
        match ty.kind() {
            cx::ll::CXType_Unexposed | cx::ll::CXType_FunctionProto
                    | cx::ll::CXType_FunctionNoProto => {
                let ret_ty = ty.ret_type();
                let decl = ty.declaration();
                if ret_ty.kind() != cx::ll::CXType_Invalid {
                    let mut ret = String::new();
                    ret.push_str("fn(");
                    for arg in ty.arg_types().iter() {
                        ret.push_str(self.type_to_str(arg).as_slice());
                        ret.push_str(", ");
                    }
                    ret.push_str(")");
                    match ret_ty.kind() {
                        cx::ll::CXType_Void => { },
                        _ => ret.push_str(format!(" -> {}", self.type_to_str(&ret_ty)).as_slice()),
                    }
                    ret
                } else if decl.kind() != cx::ll::CXCursor_NoDeclFound {
                    format!("*{} {}", mutable, self.type_to_str(&decl.cur_type()))
                } else {
                    format!("*{} ::void_t", mutable)
                }
            }
            _ => {
                format!("*{} {}", mutable, self.type_to_str(ty))
            }
        }
    }

    fn type_to_str(&mut self, ty: &cx::Type) -> String {
        self.type_to_str_int(ty, true)
    }

    fn find_type(&self, spelling: &str, skip: bool) -> Option<String> {
        let trimmed = spelling.as_slice().trim_left_chars('_');
        match self.defs.types.iter().find(|t| t.as_slice() == trimmed) {
            Some(s) => if skip { return Some(s.to_string()) },
            _ => match ::types::find(trimmed) {
                Some(t) => return Some(t.to_string()),
                _ => { },
            },
        }
        None
    }

    fn type_to_str_int(&mut self, ty: &cx::Type, skip: bool) -> String {
        match ty.kind() {
            cx::ll::CXType_SChar | cx::ll::CXType_Char_S => "::schar_t".to_string(),
            cx::ll::CXType_UChar | cx::ll::CXType_Char_U => "::uchar_t".to_string(),
            cx::ll::CXType_Void       => "::void_t".to_string(),
            cx::ll::CXType_Bool       => "::bool_t".to_string(),
            cx::ll::CXType_UShort     => "::ushort_t".to_string(),
            cx::ll::CXType_UInt       => "::uint_t".to_string(),
            cx::ll::CXType_ULong      => "::ulong_t".to_string(),
            cx::ll::CXType_ULongLong  => "::ulonglong_t".to_string(),
            cx::ll::CXType_Short      => "::short_t".to_string(),
            cx::ll::CXType_Int        => "::int_t".to_string(),
            cx::ll::CXType_Long       => "::long_t".to_string(),
            cx::ll::CXType_LongLong   => "::longlong_t".to_string(),
            cx::ll::CXType_Float      => "::float_t".to_string(),
            cx::ll::CXType_Double     => "::double_t".to_string(),
            cx::ll::CXType_LongDouble => "::longdouble_t".to_string(),
            cx::ll::CXType_Pointer => self.conv_ptr_ty(&ty.pointee_type()),
            cx::ll::CXType_Record | cx::ll::CXType_Unexposed | cx::ll::CXType_Typedef => {
                let spelling = ty.spelling();
                match self.find_type(spelling.as_slice(), skip) {
                    Some(s) => return s,
                    _ => { }
                }
                let cursor = ty.declaration();
                match cursor.kind() {
                    cx::ll::CXCursor_StructDecl | cx::ll::CXCursor_UnionDecl => {
                        let spelling = cursor.spelling();
                        match self.find_type(spelling.as_slice(), skip) {
                            Some(s) => s,
                            _ => unknown_array(ty),
                        }
                    },
                    cx::ll::CXCursor_EnumDecl => {
                        match ty.size() {
                            1 => "i8".to_string(),
                            2 => "i16".to_string(),
                            4 => "i32".to_string(),
                            8 => "i64".to_string(),
                            _ => panic!("Enum type too large"),
                        }
                    },
                    cx::ll::CXCursor_TypedefDecl => {
                        let ty = cursor.typedef_type();
                        self.type_to_str_int(&ty, skip)
                    },
                    _ => format!("UNKNOWN: {} {}", cursor.kind(), ty.kind()),
                }
            },
            cx::ll::CXType_Enum => {
                match ty.size() {
                    1 => "i8".to_string(),
                    2 => "i16".to_string(),
                    4 => "i32".to_string(),
                    8 => "i64".to_string(),
                    _ => panic!("Enum type too large"),
                }
            },
            cx::ll::CXType_ConstantArray => {
                let ts = self.type_to_str(&ty.elem_type());
                format!("[{}, ..{}]", ts, ty.array_size())
            }
            _ => format!("Can't handle type {}", ty.kind()),
        }
    }

    fn visit_struct(&mut self, cursor: &cx::Cursor,
                    fields: &mut Vec<il::Field>) -> cx::ll::Enum_CXVisitorResult {
        if cursor.kind() == cx::ll::CXCursor_FieldDecl {
            let ty = cursor.cur_type();
            let name = cursor.spelling();
            let public = !name.as_slice().starts_with("_");
            let ts = if public {
                self.type_to_str(&ty)
            } else {
                unknown_array(&ty)
            };
            let field = il::Field { name: name, ty: ts, public: public };
            fields.push(field);
        }
        cx::ll::CXChildVisit_Continue
    }

    fn visit_var(&mut self, cursor: &cx::Cursor,
                 dst: &mut Option<String>) -> cx::ll::Enum_CXVisitorResult {
        match cursor.kind() {
            cx::ll::CXCursor_DeclRefExpr => {
                let def = cursor.definition();
                if def.kind() == cx::ll::CXCursor_EnumConstantDecl {
                    *dst = Some(format!("{}", def.enum_val()));
                }
                cx::ll::CXChildVisit_Break
            },
            cx::ll::CXCursor_ParenExpr | cx::ll::CXCursor_IntegerLiteral
                    | cx::ll::CXCursor_FloatingLiteral => {
                let offset = cursor.get_location();
                let mut slc = self.file.slice_from(offset);
                slc = match slc.iter().position(|b| *b == ';' as u8) {
                    Some(p) => slc.slice_to(p),
                    _ => slc,
                };
                *dst = ::std::str::from_utf8(slc).map(|s| s.to_string());
                cx::ll::CXChildVisit_Break
            },
            _ => cx::ll::CXChildVisit_Recurse,
        }
    }

    fn handle_struct(&mut self, cursor: &cx::Cursor,
                     spelling: String) -> cx::ll::Enum_CXVisitorResult {
        let mut fields = vec!();
        cursor.visit(|c, _| {
            self.visit_struct(c, &mut fields)
        });
        let s = il::Struct {
            name: spelling,
            fields: fields,
        };
        self.globals.push(il::StructVar(s));
        if cursor.kind() == cx::ll::CXCursor_FieldDecl {
            cx::ll::CXChildVisit_Break
        } else {
            cx::ll::CXChildVisit_Recurse
        }
    }

    fn handle_typedef(&mut self, cursor: &cx::Cursor,
                      spelling: String) -> cx::ll::Enum_CXVisitorResult {
        let mut dst = cursor.typedef_type();
        if dst.kind() == cx::ll::CXType_Unexposed {
            dst = dst.canonical_type();
        }
        if dst.kind() == cx::ll::CXType_Record {
            let decl = dst.declaration();
            self.handle_struct(&decl, spelling);
        } else {
            let dst = self.type_to_str_int(&dst, false);
            let typedef = il::Typedef { name: spelling, dst: dst };
            self.globals.push(il::TypedefVar(typedef));
        }
        cx::ll::CXChildVisit_Continue
    }

    fn visit_top(&mut self, cursor: &cx::Cursor) -> cx::ll::Enum_CXVisitorResult {
        let kind = cursor.kind();
        let spelling = cursor.spelling();
        match kind {
            cx::ll::CXCursor_StructDecl | cx::ll::CXCursor_TypedefDecl => {
                if self.defs.types.iter().all(|t| t.as_slice() != spelling.as_slice()) {
                    return cx::ll::CXChildVisit_Continue;
                }
            },
            cx::ll::CXCursor_VarDecl => {
                if !spelling.as_slice().starts_with(PREFIX) {
                    return cx::ll::CXChildVisit_Continue;
                }
            },
            _ => { },
        }
        match kind {
            cx::ll::CXCursor_StructDecl => self.handle_struct(cursor, spelling),
            cx::ll::CXCursor_TypedefDecl => self.handle_typedef(cursor, spelling),
            cx::ll::CXCursor_VarDecl => {
                let real_name = spelling.as_slice().slice_from(PREFIX.len());
                let mut val = None;
                cursor.visit(|c, _| {
                    self.visit_var(c, &mut val)
                });
                let var = self.defs.consts.iter().find(|v| v.name.as_slice() == real_name);
                match (var, val) {
                    (Some(var), Some(mut val)) => {
                        if val.len() > 1 && val.as_bytes()[0] == '0' as u8 &&
                                val.as_bytes()[1] != 'x' as u8 {
                            val = format!("0o{}", val.as_slice().slice_from(1));
                        }
                        let info = il::Constant {
                            name: real_name.to_string(),
                            ty: var.rs_type.clone(),
                            val: val
                        };
                        self.globals.push(il::ConstantVar(info));
                    },
                    _ => { },
                }
                cx::ll::CXChildVisit_Continue
            }
            cx::ll::CXCursor_EnumDecl     => cx::ll::CXChildVisit_Continue,
            cx::ll::CXCursor_FunctionDecl => cx::ll::CXChildVisit_Continue,
            cx::ll::CXCursor_FieldDecl    => cx::ll::CXChildVisit_Continue,
            _ => cx::ll::CXChildVisit_Recurse,
        }
    }
}

fn unknown_array(ty: &cx::Type) -> String {
    let size = ty.size();
    let mut align = ty.align();
    if align == 0 {
        align = 1;
    }
    assert_eq!(size % align, 0);
    let ut = match align {
        0 | 1 => "u8",
        2 => "u16",
        4 => "u32",
        8 => "u64",
        _ => unreachable!(),
    };
    format!("[{}, ..{}]", ut, size / align)
}

fn preprocess(defs: &::Defs) -> ::std::io::IoResult<Vec<u8>> {
    let mut wr = ::std::io::MemWriter::new();
    try!(writeln!(wr, "#include <{}>", defs.header.as_slice()));
    for c in defs.consts.iter() {
        try!(writeln!(wr, "static const {} {}{} = {};", c.c_type.as_slice(), PREFIX,
                      c.name.as_slice(), c.name.as_slice()));
    }
    let header = wr.unwrap();
    let mut process = try!(::std::io::Command::new("clang").args(["-P", "-E", "-"]).spawn());
    process.stdin.as_mut().unwrap().write(header.as_slice()).ok();
    let output = try!(process.wait_with_output());
    if !output.status.success() {
        let mut err = ::std::io::standard_error(::std::io::InvalidInput);
        err.detail = Some(String::from_utf8_lossy(output.error.as_slice()).into_string());
        return Err(err);
    }
    Ok(output.output)
}

pub fn parse(defs: &::Defs) -> ::std::io::IoResult<Vec<il::Global>> {
    let pp = try!(preprocess(defs));
    let tmpdir = match ::std::io::TempDir::new("") {
        Ok(d) => d,
        _ => return Err(::std::io::IoError::last_error())
    };
    let mut path = tmpdir.path().clone();
    path.push("file.c");
    let mut file = try!(::std::io::fs::File::create(&path));
    try!(file.write(pp.as_slice()));
    drop(file);

    let mut ctx = Context {
        file: pp.as_slice(),
        defs: defs,
        globals: vec!(),
    };

    let ix = cx::Index::create(false, true);
    if ix.is_null() {
        return Err(::std::io::standard_error(::std::io::OtherIoError))
    }

    let unit = cx::TranslationUnit::parse(&ix, &path);
    if unit.is_null() {
        return Err(::std::io::standard_error(::std::io::OtherIoError))
    }

    let cursor = unit.cursor();

    cursor.visit(|cur, _| ctx.visit_top(cur));

    unit.dispose();
    ix.dispose();

    Ok(ctx.globals)
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Remove from a given motion (row based)
    pub fn remove_rb<'a>(&mut self, (x, y): (usize, usize)) {
        if y == self.y() {
            // Single line mode
            let (a, b) = if self.x() < x {
                (self.x(), x)
            } else {
                (x, self.x())
            };
            for i in a..b {
                self.text[y].remove(i);
            }
        } else {
            // Full line mode
            let (a, b) = if self.y() < y {
                (self.y(), y)
            } else {
                (y, self.y())
            };
            for ln in a..(b + 1) {
                self.text.remove(ln);
            }
        }
    }
}
<commit_msg>Cleanup schemes and features<commit_after>use super::*;

impl Editor {
    /// Remove from a given motion (row based)
    pub fn remove_rb<'a>(&mut self, (x, y): (usize, usize)) {
        if y == self.y() {
            // Single line mode
            let (a, b) = if self.x() < x {
                (self.x(), x)
            } else {
                (x, self.x())
            };
            for i in a..b {
                self.text[y].remove(i);
            }
        } else {
            // Full line mode
            let (a, b) = if self.y() < y {
                (self.y(), y)
            } else {
                (y, self.y())
            };
            for ln in a..(b + 1) {
                self.text.remove(ln);
            }
        }
    }
}
<|endoftext|>


<commit_before>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
#[ignore]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
#[ignore]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
#[ignore]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
#[ignore]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
#[ignore]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_mores_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(3, 11), Clock::new(99, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(22, 40), Clock::new(-2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(17, 3), Clock::new(-31, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(13, 49), Clock::new(-83, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1), Clock::new(0, 1441));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 2), Clock::new(2, 4322));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(2, 40), Clock::new(3, -20))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(4, 10), Clock::new(5, -1490))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, 15), Clock::new(6, -4305))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(7, 32), Clock::new(-12, -268))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(18, 7), Clock::new(-54, -11_513))
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0))
}
<commit_msg>Add a test to construct clock with negative 120 minutes (#996)<commit_after>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
#[ignore]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
#[ignore]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
#[ignore]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
#[ignore]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
#[ignore]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_one_twenty_minutes_is_two_prev_hours() {
    assert_eq!(Clock::new(1, -120).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_mores_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(3, 11), Clock::new(99, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(22, 40), Clock::new(-2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(17, 3), Clock::new(-31, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(13, 49), Clock::new(-83, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1), Clock::new(0, 1441));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 2), Clock::new(2, 4322));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(2, 40), Clock::new(3, -20))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(4, 10), Clock::new(5, -1490))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, 15), Clock::new(6, -4305))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(7, 32), Clock::new(-12, -268))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(18, 7), Clock::new(-54, -11_513))
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0))
}
<|endoftext|>


<commit_before>#![feature(try_trait)]

use serde::Deserialize;

#[derive(Deserialize)]
struct Versions {
    stable: Option<String>,
    bottle: bool,
}

#[derive(Deserialize)]
struct Bottle {
    stable: Option<BottleStable>,
}

#[derive(Deserialize)]
struct BottleStable {
    rebuild: u64,
    files: serde_json::Value,
}

#[derive(Deserialize)]
struct Formula {
    name: String,
    versions: Versions,
    bottle: Bottle,
}

#[derive(Deserialize)]
struct Formulae(Vec<Formula>);

#[derive(Deserialize)]
struct BottleInfo {
    url: String,
    sha256: String,
}

fn d(f: &Formula) -> Option<()> {
    if f.versions.bottle {
        let name = &f.name;
        let ver = f.versions.stable.as_ref()?;
        let bs = f.bottle.stable.as_ref()?;
        let rebuild = bs.rebuild;
        for (platform, v) in bs.files.as_object()?.iter() {
            if let Ok(bi) = serde_json::from_value::<BottleInfo>(v.clone()) {
                if rebuild == 0 {
                    println!("{} {} {}-{}.{}.bottle.tar.gz", bi.sha256, bi.url, name, ver, platform);
                } else {
                    println!("{} {} {}-{}.{}.bottle.{}.tar.gz", bi.sha256, bi.url, name, ver, platform, rebuild);
                }
            }
        }
    }
    Some(())
}

fn main() {
    let f: Formulae = serde_json::from_reader(std::io::stdin()).unwrap();
    for f in f.0 {
        d(&f);
    }
}
<commit_msg>homebrew-bottles: fix filename with revision attribute<commit_after>#![feature(try_trait)]

use serde::Deserialize;

#[derive(Deserialize)]
struct Versions {
    stable: Option<String>,
    bottle: bool,
}

#[derive(Deserialize)]
struct Bottle {
    stable: Option<BottleStable>,
}

#[derive(Deserialize)]
struct BottleStable {
    rebuild: u64,
    files: serde_json::Value,
}

#[derive(Deserialize)]
struct Formula {
    name: String,
    versions: Versions,
    bottle: Bottle,
    revision: u64,
}

#[derive(Deserialize)]
struct Formulae(Vec<Formula>);

#[derive(Deserialize)]
struct BottleInfo {
    url: String,
    sha256: String,
}

fn d(f: &Formula) -> Option<()> {
    let revision = f.revision;
    let revision = if revision == 0 { "".to_string() } else { format!("_{}", revision) };
    if f.versions.bottle {
        let name = &f.name;
        let version = f.versions.stable.as_ref()?;
        let bs = f.bottle.stable.as_ref()?;
        let rebuild = bs.rebuild;
        let rebuild = if rebuild == 0 { "".to_string() } else { format!(".{}", rebuild) };
        for (platform, v) in bs.files.as_object()?.iter() {
            if let Ok(v) = serde_json::from_value::<BottleInfo>(v.clone()) {
                println!(
                    "{} {} bottles/{}-{}{}.{}.bottle{}.tar.gz",
                    v.sha256, v.url, name, version, revision, platform, rebuild
                );
            }
        }
    }
    Some(())
}

fn main() {
    let f: Formulae = serde_json::from_reader(std::io::stdin()).unwrap();
    for f in f.0 {
        d(&f);
    }
}
<|endoftext|>