<commit_before>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

const LED_COLUMNS: usize = 17;
const LED_ROWS: usize = 7;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError>;
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display().unwrap();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), LinuxI2CError> {
        self.write_data(BANK_ADDRESS, &[bank])
    }

    fn register(&mut self, bank: u8, register: u8, value: u8) -> Result<(), LinuxI2CError> {
        self.bank(bank)?;
        self.write_data(register, &[value])
    }

    fn frame(&mut self, frame: u8) -> Result<(), LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn write_data(&mut self, base_address: u8, data: &[u8]) -> Result<(), LinuxI2CError> {
        for i in 0..data.len() {
            self.device
                .smbus_write_byte_data(base_address + (i as u8), data[i])?;
        }
        Ok(())
    }

    fn reset_display(&mut self) -> Result<(), LinuxI2CError> {
        self.sleep(true)?;
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false)?;
        Ok(())
    }

    fn init_display(&mut self) -> Result<(), LinuxI2CError> {
        self.reset_display()?;

        // Switch to Picture Mode.
        self.register(CONFIG_BANK, MODE_REGISTER, PICTURE_MODE)?;

        // Disable audio sync.
        self.register(CONFIG_BANK, AUDIOSYNC_REGISTER, 0)?;

        // Initialize frames 0 and 1.
        for frame in 0..2 {
            self.write_data(BANK_ADDRESS, &[frame])?;

            // Turn off blinking for all LEDs.
            self.write_data(BLINK_OFFSET, &[0; LED_COLUMNS * LED_ROWS])?;

            // Set the PWM duty cycle for all LEDs to 0%.
            self.write_data(COLOR_OFFSET, &[0; LED_COLUMNS * LED_ROWS])?;

            // Turn all LEDs "on".
            self.write_data(ENABLE_OFFSET, &[127; LED_COLUMNS * LED_ROWS])?;
        }

        Ok(())
    }

    fn sleep(&mut self, value: bool) -> Result<(), LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        // Double buffering with frames 0 and 1.
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame)?;
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.write_data(COLOR_OFFSET + offset as u8, &[value])?;
            }
        }
        self.frame(new_frame)?;
        self.frame = new_frame;
        Ok(())
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

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

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
        Ok(())
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

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

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );

        Ok(())
    }
}
<commit_msg>Write I2C data in up to 32-byte chunks<commit_after>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

const LED_COLUMNS: usize = 17;
const LED_ROWS: usize = 7;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError>;
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display().unwrap();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), LinuxI2CError> {
        self.write_data(BANK_ADDRESS, &[bank])
    }

    fn register(&mut self, bank: u8, register: u8, value: u8) -> Result<(), LinuxI2CError> {
        self.bank(bank)?;
        self.write_data(register, &[value])
    }

    fn frame(&mut self, frame: u8) -> Result<(), LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn write_data(&mut self, base_address: u8, data: &[u8]) -> Result<(), LinuxI2CError> {
        let mut offset = 0;
        for chunk in data.chunks(32) {
            self.device.smbus_process_block(base_address + offset, chunk)?;
            offset += 32;
        }

        Ok(())
    }

    fn reset_display(&mut self) -> Result<(), LinuxI2CError> {
        self.sleep(true)?;
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false)?;
        Ok(())
    }

    fn init_display(&mut self) -> Result<(), LinuxI2CError> {
        self.reset_display()?;

        // Switch to Picture Mode.
        self.register(CONFIG_BANK, MODE_REGISTER, PICTURE_MODE)?;

        // Disable audio sync.
        self.register(CONFIG_BANK, AUDIOSYNC_REGISTER, 0)?;

        // Initialize frames 0 and 1.
        for frame in 0..2 {
            self.write_data(BANK_ADDRESS, &[frame])?;

            // Turn off blinking for all LEDs.
            self.write_data(BLINK_OFFSET, &[0; LED_COLUMNS * LED_ROWS])?;

            // Set the PWM duty cycle for all LEDs to 0%.
            self.write_data(COLOR_OFFSET, &[0; LED_COLUMNS * LED_ROWS])?;

            // Turn all LEDs "on".
            self.write_data(ENABLE_OFFSET, &[127; LED_COLUMNS * LED_ROWS])?;
        }

        Ok(())
    }

    fn sleep(&mut self, value: bool) -> Result<(), LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        // Double buffering with frames 0 and 1.
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame)?;
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.write_data(COLOR_OFFSET + offset as u8, &[value])?;
            }
        }
        self.frame(new_frame)?;
        self.frame = new_frame;
        Ok(())
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

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

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
        Ok(())
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

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

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) -> Result<(), LinuxI2CError> {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );

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


<commit_before>//! Interval-based annotation features.

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{self, Display};

use bio::utils::{Interval, IntervalError};

use self::error::FeatureError;

// TODO: PR for rust-bio so that it implements Copy
//       for now, we use our own
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Strand {
    Forward,
    Reverse,
    Unknown
}

pub mod error {

    use super::*;

    #[derive(Debug, PartialEq)]
    pub enum FeatureError {
        IntervalError,
        StrandCharError,
        ConflictingStrandError,
        UnspecifiedStrandError,
        IncompleteTranscriptError,
    }

    impl Error for FeatureError {

        fn description(&self) -> &str {
            match *self {
                FeatureError::IntervalError =>
                    "interval start coordinate larger than its end coordinate",
                FeatureError::StrandCharError =>
                    "strand character is invalid",
                FeatureError::ConflictingStrandError =>
                    "conflicting strand inputs specified",
                FeatureError::UnspecifiedStrandError =>
                    "strand not specified",
                FeatureError::IncompleteTranscriptError =>
                    "transcript annotation is incomplete",
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl Display for FeatureError {

        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }

    impl From<IntervalError> for FeatureError {
        fn from(err: IntervalError) -> FeatureError {
            FeatureError::IntervalError
        }
    }
}

trait Annotation {
    fn seq_name(&self) -> &str;
    fn interval(&self) -> &Interval<u64>;
    fn attributes(&self) -> &HashMap<String, String>;
    fn attribute(&self, key: &str) -> Option<&str>;
    fn strand(&self) -> &Strand;
}

macro_rules! impl_annotation {
    ($struct_ty:ty) => (

        impl Annotation for $struct_ty {

            fn seq_name(&self) -> &str {
                self.seq_name.as_str()
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn attributes(&self) -> &HashMap<String, String> {
                &self.attributes
            }

            fn attribute(&self, key: &str) -> Option<&str> {
                self.attributes.get(key).map(|n| n.as_str())
            }

            fn strand(&self) -> &Strand {
                &self.strand
            }
        }

    );
}

fn char_to_strand(strand_char: char) -> Result<Strand, FeatureError> {
    match strand_char {
        '+' | 'f' | 'F' => Ok(Strand::Forward),
        '-' | 'r' | 'R' => Ok(Strand::Reverse),
        '.' | '?' => Ok(Strand::Unknown),
        _ => Err(FeatureError::StrandCharError),
    }
}

fn resolve_strand_input(strand: Option<Strand>, strand_char: Option<char>) -> Result<Strand, FeatureError> {
    match (strand, strand_char) {
        (None, None) => Err(FeatureError::UnspecifiedStrandError),
        (Some(sv), None) => Ok(sv),
        (None, Some(scv)) => char_to_strand(scv),
        (Some(sv), Some(scv)) => {
            let sv_from_char = char_to_strand(scv)?;
            if sv == sv_from_char {
                Ok(sv)
            } else {
                Err(FeatureError::ConflictingStrandError)
            }
        }
    }
}

fn coords_to_interval(start: u64, end: u64) -> Result<Interval<u64>, FeatureError> {
    Interval::new(start..end).map_err(FeatureError::from)
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TxFeature {
    Exon,
    UTR,
    UTR5,
    UTR3,
    CDS,
    StartCodon,
    StopCodon,
    Any,
}

#[derive(Debug)]
pub struct TranscriptFeature {
    kind: TxFeature,
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>
}

impl_annotation!(TranscriptFeature);

impl TranscriptFeature {

    fn kind(&self) -> &TxFeature {
        &self.kind
    }
}

pub struct TxFeatureBuilder {
    seq_name: String,
    start: u64,
    end: u64,
    attributes: HashMap<String, String>,
    kind: TxFeature,
    strand: Option<Strand>,
    strand_char: Option<char>,
}

impl TxFeatureBuilder {

    fn new<T>(seq_name: T, start: u64, end: u64) -> TxFeatureBuilder
        where T: Into<String>
    {
        TxFeatureBuilder {
            seq_name: seq_name.into(),
            start: start, end: end,
            kind: TxFeature::Any,
            attributes: HashMap::new(),
            strand: None,
            strand_char: None,
        }
    }

    fn kind(mut self, kind: TxFeature) -> TxFeatureBuilder {
        self.kind = kind;
        self
    }

    fn strand(mut self, strand: Strand) -> TxFeatureBuilder {
        self.strand = Some(strand);
        self
    }

    fn strand_char(mut self, strand_char: char) -> TxFeatureBuilder {
        self.strand_char = Some(strand_char);
        self
    }

    fn attribute<K, V>(mut self, key: K, value: V) -> TxFeatureBuilder
        where K: Into<String>, V: Into<String>
    {
        self.attributes.insert(key.into(), value.into());
        self
    }

    fn build(self) -> Result<TranscriptFeature, FeatureError> {
        let interval = coords_to_interval(self.start, self.end)?;
        let strand = resolve_strand_input(self.strand, self.strand_char)?;
        let feature = TranscriptFeature {
            seq_name: self.seq_name, kind: self.kind, interval: interval,
            strand: strand, attributes: self.attributes,
        };
        Ok(feature)
    }
}

#[derive(Debug)]
pub struct Transcript {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    features: Vec<TranscriptFeature>,
}

impl_annotation!(Transcript);

#[derive(Debug)]
pub struct Gene {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    transcripts: HashMap<String, Transcript>,
}

impl_annotation!(Gene);

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

    #[test]
    fn builder() {
        let tfm1 = TxFeatureBuilder::new("chrT", 10, 20)
            .kind(TxFeature::Exon)
            .strand(Strand::Forward)
            .attribute("name", "ex1")
            .build();
        assert!(tfm1.is_ok());
        let tf = tfm1.unwrap();
        assert_eq!(tf.seq_name(), "chrT");
        assert_eq!(tf.kind(), &TxFeature::Exon);
        assert_eq!(tf.strand(), &Strand::Forward);
        assert_eq!(tf.attribute("name"), Some("ex1"));
        assert_eq!(tf.attributes.len(), 1);

        let tfm2 = TxFeatureBuilder::new("chrO", 10, 10)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm2.is_ok());
    }

    #[test]
    fn builder_interval_invalid() {
        let tfm = TxFeatureBuilder::new("chrE", 20, 10).build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::IntervalError);
    }

    #[test]
    fn builder_strand_unspecified() {
        let tfm = TxFeatureBuilder::new("chrT", 20, 30)
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::UnspecifiedStrandError);
    }

    #[test]
    fn builder_strand_char_unexpected() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('w')
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::StrandCharError);
    }

    #[test]
    fn builder_strand_char_conflicting() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm.is_ok());
        let tf = tfm.unwrap();
        assert_eq!(tf.strand(), &Strand::Reverse);
    }
}
<commit_msg>Switch back to rust-bio Strand<commit_after>//! Interval-based annotation features.

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{self, Display};

use bio::utils::{Interval, IntervalError, Strand};

use self::error::FeatureError;

pub mod error {

    use super::*;

    #[derive(Debug, PartialEq)]
    pub enum FeatureError {
        IntervalError,
        StrandCharError,
        ConflictingStrandError,
        UnspecifiedStrandError,
        IncompleteTranscriptError,
    }

    impl Error for FeatureError {

        fn description(&self) -> &str {
            match *self {
                FeatureError::IntervalError =>
                    "interval start coordinate larger than its end coordinate",
                FeatureError::StrandCharError =>
                    "strand character is invalid",
                FeatureError::ConflictingStrandError =>
                    "conflicting strand inputs specified",
                FeatureError::UnspecifiedStrandError =>
                    "strand not specified",
                FeatureError::IncompleteTranscriptError =>
                    "transcript annotation is incomplete",
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl Display for FeatureError {

        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }

    impl From<IntervalError> for FeatureError {
        fn from(err: IntervalError) -> FeatureError {
            FeatureError::IntervalError
        }
    }
}

trait Annotation {
    fn seq_name(&self) -> &str;
    fn interval(&self) -> &Interval<u64>;
    fn attributes(&self) -> &HashMap<String, String>;
    fn attribute(&self, key: &str) -> Option<&str>;
    fn strand(&self) -> &Strand;
}

macro_rules! impl_annotation {
    ($struct_ty:ty) => (

        impl Annotation for $struct_ty {

            fn seq_name(&self) -> &str {
                self.seq_name.as_str()
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn attributes(&self) -> &HashMap<String, String> {
                &self.attributes
            }

            fn attribute(&self, key: &str) -> Option<&str> {
                self.attributes.get(key).map(|n| n.as_str())
            }

            fn strand(&self) -> &Strand {
                &self.strand
            }
        }

    );
}

fn char_to_strand(strand_char: char) -> Result<Strand, FeatureError> {
    match strand_char {
        '+' | 'f' | 'F' => Ok(Strand::Forward),
        '-' | 'r' | 'R' => Ok(Strand::Reverse),
        '.' | '?' => Ok(Strand::Unknown),
        _ => Err(FeatureError::StrandCharError),
    }
}

fn resolve_strand_input(strand: Option<Strand>, strand_char: Option<char>) -> Result<Strand, FeatureError> {
    match (strand, strand_char) {
        (None, None) => Err(FeatureError::UnspecifiedStrandError),
        (Some(sv), None) => Ok(sv),
        (None, Some(scv)) => char_to_strand(scv),
        (Some(sv), Some(scv)) => {
            let sv_from_char = char_to_strand(scv)?;
            if sv == sv_from_char {
                Ok(sv)
            } else {
                Err(FeatureError::ConflictingStrandError)
            }
        }
    }
}

fn coords_to_interval(start: u64, end: u64) -> Result<Interval<u64>, FeatureError> {
    Interval::new(start..end).map_err(FeatureError::from)
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TxFeature {
    Exon,
    UTR,
    UTR5,
    UTR3,
    CDS,
    StartCodon,
    StopCodon,
    Any,
}

#[derive(Debug)]
pub struct TranscriptFeature {
    kind: TxFeature,
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>
}

impl_annotation!(TranscriptFeature);

impl TranscriptFeature {

    fn kind(&self) -> &TxFeature {
        &self.kind
    }
}

pub struct TxFeatureBuilder {
    seq_name: String,
    start: u64,
    end: u64,
    attributes: HashMap<String, String>,
    kind: TxFeature,
    strand: Option<Strand>,
    strand_char: Option<char>,
}

impl TxFeatureBuilder {

    fn new<T>(seq_name: T, start: u64, end: u64) -> TxFeatureBuilder
        where T: Into<String>
    {
        TxFeatureBuilder {
            seq_name: seq_name.into(),
            start: start, end: end,
            kind: TxFeature::Any,
            attributes: HashMap::new(),
            strand: None,
            strand_char: None,
        }
    }

    fn kind(mut self, kind: TxFeature) -> TxFeatureBuilder {
        self.kind = kind;
        self
    }

    fn strand(mut self, strand: Strand) -> TxFeatureBuilder {
        self.strand = Some(strand);
        self
    }

    fn strand_char(mut self, strand_char: char) -> TxFeatureBuilder {
        self.strand_char = Some(strand_char);
        self
    }

    fn attribute<K, V>(mut self, key: K, value: V) -> TxFeatureBuilder
        where K: Into<String>, V: Into<String>
    {
        self.attributes.insert(key.into(), value.into());
        self
    }

    fn build(self) -> Result<TranscriptFeature, FeatureError> {
        let interval = coords_to_interval(self.start, self.end)?;
        let strand = resolve_strand_input(self.strand, self.strand_char)?;
        let feature = TranscriptFeature {
            seq_name: self.seq_name, kind: self.kind, interval: interval,
            strand: strand, attributes: self.attributes,
        };
        Ok(feature)
    }
}

#[derive(Debug)]
pub struct Transcript {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    features: Vec<TranscriptFeature>,
}

impl_annotation!(Transcript);

#[derive(Debug)]
pub struct Gene {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    transcripts: HashMap<String, Transcript>,
}

impl_annotation!(Gene);

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

    #[test]
    fn builder() {
        let tfm1 = TxFeatureBuilder::new("chrT", 10, 20)
            .kind(TxFeature::Exon)
            .strand(Strand::Forward)
            .attribute("name", "ex1")
            .build();
        assert!(tfm1.is_ok());
        let tf = tfm1.unwrap();
        assert_eq!(tf.seq_name(), "chrT");
        assert_eq!(tf.kind(), &TxFeature::Exon);
        assert_eq!(tf.strand(), &Strand::Forward);
        assert_eq!(tf.attribute("name"), Some("ex1"));
        assert_eq!(tf.attributes.len(), 1);

        let tfm2 = TxFeatureBuilder::new("chrO", 10, 10)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm2.is_ok());
    }

    #[test]
    fn builder_interval_invalid() {
        let tfm = TxFeatureBuilder::new("chrE", 20, 10).build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::IntervalError);
    }

    #[test]
    fn builder_strand_unspecified() {
        let tfm = TxFeatureBuilder::new("chrT", 20, 30)
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::UnspecifiedStrandError);
    }

    #[test]
    fn builder_strand_char_unexpected() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('w')
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::StrandCharError);
    }

    #[test]
    fn builder_strand_char_conflicting() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm.is_ok());
        let tf = tfm.unwrap();
        assert_eq!(tf.strand(), &Strand::Reverse);
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};

use ctxt::SemContext;
use driver::cmd::Args;
use gc::root::{get_rootset, IndirectObj};
use gc::{Address, Collector, formatted_size, Region};
use gc::tlab;
use mem;
use object::Obj;
use os::{self, ProtType};
use timer::Timer;

pub struct CopyCollector {
    total: Region,
    separator: Address,

    top: AtomicUsize,
    end: AtomicUsize,
}

impl CopyCollector {
    pub fn new(args: &Args) -> CopyCollector {
        let alignment = 2 * (os::page_size() as usize);
        let heap_size = mem::align_usize(args.max_heap_size(), alignment);
        let ptr = os::mmap(heap_size, os::Writable);

        if ptr.is_null() {
            panic!("could not allocate semi space of size {} bytes", heap_size);
        }

        let heap_start = Address::from_ptr(ptr);
        let heap = heap_start.region_start(heap_size);

        let semi_size = heap_size / 2;
        let separator = heap_start.offset(semi_size);

        if args.flag_gc_verbose {
            println!(
                "GC: {}; semi size: {}",
                heap,
                formatted_size(semi_size),
            );
        }

        CopyCollector {
            total: heap,
            separator: separator,
            top: AtomicUsize::new(heap_start.to_usize()),
            end: AtomicUsize::new(separator.to_usize()),
        }
    }
}

impl Collector for CopyCollector {
    fn alloc_tlab_area(&self, ctxt: &SemContext, size: usize) -> Option<Region> {
        let ptr = self.bump_alloc(size);

        if ptr.is_non_null() {
            return Some(ptr.region_start(size));
        }

        self.collect(ctxt);

        let ptr = self.bump_alloc(size);

        return if ptr.is_null() {
            None
        } else {
            Some(ptr.region_start(size))
        };
    }

    fn alloc_normal(&self, ctxt: &SemContext, size: usize, _array_ref: bool) -> Address {
        let ptr = self.bump_alloc(size);

        if ptr.is_non_null() {
            return ptr;
        }

        self.collect(ctxt);
        self.bump_alloc(size)
    }

    fn alloc_large(&self, ctxt: &SemContext, size: usize, array_ref: bool) -> Address {
        self.alloc_normal(ctxt, size, array_ref)
    }

    fn collect(&self, ctxt: &SemContext) {
        // make heap iterable
        tlab::make_iterable(ctxt);

        let rootset = get_rootset(ctxt);
        self.collect_from(ctxt, &rootset);
    }

    fn minor_collect(&self, ctxt: &SemContext) {
        self.collect(ctxt);
    }
}

impl Drop for CopyCollector {
    fn drop(&mut self) {
        os::munmap(self.total.start.to_ptr(), self.total.size());
    }
}

impl CopyCollector {
    fn bump_alloc(&self, size: usize) -> Address {
        let mut old = self.top.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new > self.end.load(Ordering::Relaxed) {
                return Address::null();
            }

            let res = self
                .top
                .compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed);

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old.into()
    }

    fn collect_from(&self, ctxt: &SemContext, rootset: &[IndirectObj]) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        // enable writing into to-space again (for debug builds)
        if cfg!(debug_assertions) {
            let to_space = self.to_space();
            os::mprotect(to_space.start.to_ptr(), to_space.size(), ProtType::Writable);
        }

        // empty to-space
        let to_space = self.to_space();
        let from_space = self.from_space();

        let mut top = to_space.start;
        let mut scan = top;

        for root in rootset {
            let root_ptr = root.get();

            if from_space.contains(Address::from_ptr(root_ptr)) {
                root.set(self.copy(root_ptr, &mut top));
            }
        }

        while scan < top {
            let object: &mut Obj = unsafe { &mut *scan.to_mut_ptr() };

            object.visit_reference_fields(|field| {
                let field_ptr = field.get();

                if from_space.contains(Address::from_ptr(field_ptr)) {
                    field.set(self.copy(field_ptr, &mut top));
                }
            });

            scan = scan.offset(object.size());
        }

        // disable access in current from-space
        // makes sure that no pointer into from-space is left (in debug-builds)
        if cfg!(debug_assertions) {
            os::mprotect(from_space.start.to_ptr(), from_space.size(), ProtType::None);
        }

        self.top.store(top.to_usize(), Ordering::Relaxed);
        self.end.store(to_space.end.to_usize(), Ordering::Relaxed);

        timer.stop_with(|time_pause| {
            if ctxt.args.flag_gc_events {
                println!("Copy GC: collect garbage ({:.1} ms)", time_pause);
            }
        });
    }

    fn copy(&self, obj: *mut Obj, top: &mut Address) -> *mut Obj {
        let obj = unsafe { &mut *obj };

        if let Some(fwd) = obj.header().vtbl_forwarded() {
            return fwd.to_mut_ptr();
        }

        let addr = *top;
        let obj_size = obj.size();

        obj.copy_to(addr, obj_size);
        *top = top.offset(obj_size);

        obj.header_mut().vtbl_forward_to(addr);

        addr.to_mut_ptr()
    }

    pub fn from_space(&self) -> Region {
        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            Region::new(self.total.start, self.separator)
        } else {
            Region::new(self.separator, self.total.end)
        }
    }

    pub fn to_space(&self) -> Region {
        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            Region::new(self.separator, self.total.end)
        } else {
            Region::new(self.total.start, self.separator)
        }
    }
}
<commit_msg>rename collect_from to copy_collect<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};

use ctxt::SemContext;
use driver::cmd::Args;
use gc::root::{get_rootset, IndirectObj};
use gc::{Address, Collector, formatted_size, Region};
use gc::tlab;
use mem;
use object::Obj;
use os::{self, ProtType};
use timer::Timer;

pub struct CopyCollector {
    total: Region,
    separator: Address,

    top: AtomicUsize,
    end: AtomicUsize,
}

impl CopyCollector {
    pub fn new(args: &Args) -> CopyCollector {
        let alignment = 2 * (os::page_size() as usize);
        let heap_size = mem::align_usize(args.max_heap_size(), alignment);
        let ptr = os::mmap(heap_size, os::Writable);

        if ptr.is_null() {
            panic!("could not allocate semi space of size {} bytes", heap_size);
        }

        let heap_start = Address::from_ptr(ptr);
        let heap = heap_start.region_start(heap_size);

        let semi_size = heap_size / 2;
        let separator = heap_start.offset(semi_size);

        if args.flag_gc_verbose {
            println!(
                "GC: {}; semi size: {}",
                heap,
                formatted_size(semi_size),
            );
        }

        CopyCollector {
            total: heap,
            separator: separator,
            top: AtomicUsize::new(heap_start.to_usize()),
            end: AtomicUsize::new(separator.to_usize()),
        }
    }
}

impl Collector for CopyCollector {
    fn alloc_tlab_area(&self, ctxt: &SemContext, size: usize) -> Option<Region> {
        let ptr = self.bump_alloc(size);

        if ptr.is_non_null() {
            return Some(ptr.region_start(size));
        }

        self.collect(ctxt);

        let ptr = self.bump_alloc(size);

        return if ptr.is_null() {
            None
        } else {
            Some(ptr.region_start(size))
        };
    }

    fn alloc_normal(&self, ctxt: &SemContext, size: usize, _array_ref: bool) -> Address {
        let ptr = self.bump_alloc(size);

        if ptr.is_non_null() {
            return ptr;
        }

        self.collect(ctxt);
        self.bump_alloc(size)
    }

    fn alloc_large(&self, ctxt: &SemContext, size: usize, array_ref: bool) -> Address {
        self.alloc_normal(ctxt, size, array_ref)
    }

    fn collect(&self, ctxt: &SemContext) {
        // make heap iterable
        tlab::make_iterable(ctxt);

        let rootset = get_rootset(ctxt);
        self.copy_collect(ctxt, &rootset);
    }

    fn minor_collect(&self, ctxt: &SemContext) {
        self.collect(ctxt);
    }
}

impl Drop for CopyCollector {
    fn drop(&mut self) {
        os::munmap(self.total.start.to_ptr(), self.total.size());
    }
}

impl CopyCollector {
    fn bump_alloc(&self, size: usize) -> Address {
        let mut old = self.top.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new > self.end.load(Ordering::Relaxed) {
                return Address::null();
            }

            let res = self
                .top
                .compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed);

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old.into()
    }

    fn copy_collect(&self, ctxt: &SemContext, rootset: &[IndirectObj]) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        // enable writing into to-space again (for debug builds)
        if cfg!(debug_assertions) {
            let to_space = self.to_space();
            os::mprotect(to_space.start.to_ptr(), to_space.size(), ProtType::Writable);
        }

        // empty to-space
        let to_space = self.to_space();
        let from_space = self.from_space();

        let mut top = to_space.start;
        let mut scan = top;

        for root in rootset {
            let root_ptr = root.get();

            if from_space.contains(Address::from_ptr(root_ptr)) {
                root.set(self.copy(root_ptr, &mut top));
            }
        }

        while scan < top {
            let object: &mut Obj = unsafe { &mut *scan.to_mut_ptr() };

            object.visit_reference_fields(|field| {
                let field_ptr = field.get();

                if from_space.contains(Address::from_ptr(field_ptr)) {
                    field.set(self.copy(field_ptr, &mut top));
                }
            });

            scan = scan.offset(object.size());
        }

        // disable access in current from-space
        // makes sure that no pointer into from-space is left (in debug-builds)
        if cfg!(debug_assertions) {
            os::mprotect(from_space.start.to_ptr(), from_space.size(), ProtType::None);
        }

        self.top.store(top.to_usize(), Ordering::Relaxed);
        self.end.store(to_space.end.to_usize(), Ordering::Relaxed);

        timer.stop_with(|time_pause| {
            if ctxt.args.flag_gc_events {
                println!("Copy GC: collect garbage ({:.1} ms)", time_pause);
            }
        });
    }

    fn copy(&self, obj: *mut Obj, top: &mut Address) -> *mut Obj {
        let obj = unsafe { &mut *obj };

        if let Some(fwd) = obj.header().vtbl_forwarded() {
            return fwd.to_mut_ptr();
        }

        let addr = *top;
        let obj_size = obj.size();

        obj.copy_to(addr, obj_size);
        *top = top.offset(obj_size);

        obj.header_mut().vtbl_forward_to(addr);

        addr.to_mut_ptr()
    }

    pub fn from_space(&self) -> Region {
        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            Region::new(self.total.start, self.separator)
        } else {
            Region::new(self.separator, self.total.end)
        }
    }

    pub fn to_space(&self) -> Region {
        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            Region::new(self.separator, self.total.end)
        } else {
            Region::new(self.total.start, self.separator)
        }
    }
}
<|endoftext|>


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

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#[phase(plugin, link)] extern crate log;
extern crate libc;

extern crate device;
// when cargo is ready, re-enable the cfg's
/* #[cfg(glfw)] */ extern crate glfw;
/* #[cfg(glfw)] */ extern crate glfw_platform;
extern crate render;

// public re-exports
pub use render::{BufferHandle, SurfaceHandle, TextureHandle, SamplerHandle, ProgramHandle, EnvirHandle};
pub use render::Renderer;
pub use render::mesh::{Attribute, Mesh, VertexFormat, Slice, VertexSlice, IndexSlice};
pub use render::state::{DrawState, BlendAdditive, BlendAlpha};
pub use render::shade::{ParameterSink, ToUniform, ShaderParam, TextureParam,
    ParameterLinkError, ParameterError, ErrorInternal, ErrorUniform, ErrorBlock, ErrorTexture,
    FnUniform, FnBlock, FnTexture, VarUniform, VarBlock, VarTexture};
pub use render::target::{Frame, Plane, PlaneEmpty, PlaneSurface, PlaneTexture};
pub use device::{attrib, state, tex};
pub use device::target::{Color, ClearData, Layer, Level};
pub use device::{Blob, Device, GlBackEnd, GlProvider, GraphicsContext, InitError, QueueSize};
pub use device::shade::{UniformValue, ValueI32, ValueF32, ValueI32Vec, ValueF32Vec, ValueF32Matrix};
pub use device::shade::{ShaderSource, StaticBytes};
/* #[cfg(glfw)] */ pub use GlfwWindowBuilder = glfw_platform::WindowBuilder;
/* #[cfg(glfw)] */ pub use GlfwContext = glfw_platform::Platform;
/* #[cfg(glfw)] */ pub use GlfwProvider = glfw_platform::Wrap;

/// The empty variant of a type-level option.
///
/// See also: `SomeT`.
pub struct NoneT;

/// The the 'some' variant of a type-level option.
///
/// See also: `NoneT`.
pub struct SomeT<T>(pub T);

/// A builder object used to initialise gfx-rs.
pub struct Builder<C, P> {
    pub context: C,
    pub provider: P,
    pub queue_size: QueueSize,
}

/// A builder for initializing gfx-rs using the GLFW library.
/* #[cfg(glfw)] */
pub type GlfwBuilder<'a, C> = Builder<
    SomeT<GlfwContext<C>>,
    SomeT<GlfwProvider<'a>>
>;

/// Create an empty builder object for initialising gfx-rs. The context and
/// provider *must* be supplied before initialisation can occur.
pub fn build() -> Builder<NoneT, NoneT> {
    Builder {
        context: NoneT,
        provider: NoneT,
        queue_size: 0,
    }
}

impl<C, P> Builder<C, P> {
    /// Supply a context to the builder.
    pub fn with_context<NewC: GraphicsContext<GlBackEnd>>(self, context: NewC)
            -> Builder<SomeT<NewC>, P> {
        let Builder { context: _, provider, queue_size } = self;
        Builder {
            context: SomeT(context),
            provider: provider,
            queue_size: queue_size,
        }
    }

    /// Supply a provider to the builder.
    pub fn with_provider<NewP: GlProvider>(self, provider: NewP)
            -> Builder<C, SomeT<NewP>> {
        let Builder { context, provider: _, queue_size } = self;
        Builder {
            context: context,
            provider: SomeT(provider),
            queue_size: queue_size,
        }
    }

    /// Supply a queue size to the builder.
    pub fn with_queue_size(mut self, queue_size: QueueSize) -> Builder<C, P> {
        self.queue_size = queue_size;
        self
    }

    /// Use GLFW for the context and provider.
    /* #[cfg(glfw)] */
    pub fn with_glfw<'a, C: glfw::Context>(self, glfw: &'a glfw::Glfw, context: C) -> GlfwBuilder<'a, C> {
        let (platform, provider) = glfw_platform::Platform::new(context, glfw);
        self.with_context(platform)
            .with_provider(provider)
    }

    /// Use GLFW for the context and provider, taking them from the supplied.
    /// `glfw::Window`.
    /* #[cfg(glfw)] */
    pub fn with_glfw_window<'a>(self, window: &'a mut glfw::Window) -> GlfwBuilder<'a, glfw::RenderContext> {
        let context = window.render_context();
        self.with_glfw(&window.glfw, context)
    }
}

/// Terminal builder methods. These can only be called once both the context
/// and provider have been supplied.
impl<C: GraphicsContext<GlBackEnd>, P: GlProvider> Builder<SomeT<C>, SomeT<P>> {
    /// Create a `Renderer` and `Device`.
    pub fn create(self) -> Result<(Renderer, Device<render::Token, GlBackEnd, C>), InitError> {
        let Builder { context: SomeT(context), provider: SomeT(provider), queue_size } = self;
        device::init(context, provider, queue_size).map(|(tx, rx, server, ack, should_finish)| {
            (Renderer::new(tx, rx, ack, should_finish), server)
        })
    }

    /// Spawn the renderer in a new native task, and return the `Device`.
    pub fn spawn(self, f: proc(Renderer): 'static + Send) -> Result<Device<render::Token, GlBackEnd, C>, InitError> {
        match self.create() {
            Ok((renderer, device)) => {
                spawn(proc() f(renderer));
                Ok(device)
            },
            Err(e) => Err(e),
        }
    }
}
<commit_msg>Fix apostrophe<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#[phase(plugin, link)] extern crate log;
extern crate libc;

extern crate device;
// when cargo is ready, re-enable the `cfg`s
/* #[cfg(glfw)] */ extern crate glfw;
/* #[cfg(glfw)] */ extern crate glfw_platform;
extern crate render;

// public re-exports
pub use render::{BufferHandle, SurfaceHandle, TextureHandle, SamplerHandle, ProgramHandle, EnvirHandle};
pub use render::Renderer;
pub use render::mesh::{Attribute, Mesh, VertexFormat, Slice, VertexSlice, IndexSlice};
pub use render::state::{DrawState, BlendAdditive, BlendAlpha};
pub use render::shade::{ParameterSink, ToUniform, ShaderParam, TextureParam,
    ParameterLinkError, ParameterError, ErrorInternal, ErrorUniform, ErrorBlock, ErrorTexture,
    FnUniform, FnBlock, FnTexture, VarUniform, VarBlock, VarTexture};
pub use render::target::{Frame, Plane, PlaneEmpty, PlaneSurface, PlaneTexture};
pub use device::{attrib, state, tex};
pub use device::target::{Color, ClearData, Layer, Level};
pub use device::{Blob, Device, GlBackEnd, GlProvider, GraphicsContext, InitError, QueueSize};
pub use device::shade::{UniformValue, ValueI32, ValueF32, ValueI32Vec, ValueF32Vec, ValueF32Matrix};
pub use device::shade::{ShaderSource, StaticBytes};
/* #[cfg(glfw)] */ pub use GlfwWindowBuilder = glfw_platform::WindowBuilder;
/* #[cfg(glfw)] */ pub use GlfwContext = glfw_platform::Platform;
/* #[cfg(glfw)] */ pub use GlfwProvider = glfw_platform::Wrap;

/// The empty variant of a type-level option.
///
/// See also: `SomeT`.
pub struct NoneT;

/// The the 'some' variant of a type-level option.
///
/// See also: `NoneT`.
pub struct SomeT<T>(pub T);

/// A builder object used to initialise gfx-rs.
pub struct Builder<C, P> {
    pub context: C,
    pub provider: P,
    pub queue_size: QueueSize,
}

/// A builder for initializing gfx-rs using the GLFW library.
/* #[cfg(glfw)] */
pub type GlfwBuilder<'a, C> = Builder<
    SomeT<GlfwContext<C>>,
    SomeT<GlfwProvider<'a>>
>;

/// Create an empty builder object for initialising gfx-rs. The context and
/// provider *must* be supplied before initialisation can occur.
pub fn build() -> Builder<NoneT, NoneT> {
    Builder {
        context: NoneT,
        provider: NoneT,
        queue_size: 0,
    }
}

impl<C, P> Builder<C, P> {
    /// Supply a context to the builder.
    pub fn with_context<NewC: GraphicsContext<GlBackEnd>>(self, context: NewC)
            -> Builder<SomeT<NewC>, P> {
        let Builder { context: _, provider, queue_size } = self;
        Builder {
            context: SomeT(context),
            provider: provider,
            queue_size: queue_size,
        }
    }

    /// Supply a provider to the builder.
    pub fn with_provider<NewP: GlProvider>(self, provider: NewP)
            -> Builder<C, SomeT<NewP>> {
        let Builder { context, provider: _, queue_size } = self;
        Builder {
            context: context,
            provider: SomeT(provider),
            queue_size: queue_size,
        }
    }

    /// Supply a queue size to the builder.
    pub fn with_queue_size(mut self, queue_size: QueueSize) -> Builder<C, P> {
        self.queue_size = queue_size;
        self
    }

    /// Use GLFW for the context and provider.
    /* #[cfg(glfw)] */
    pub fn with_glfw<'a, C: glfw::Context>(self, glfw: &'a glfw::Glfw, context: C) -> GlfwBuilder<'a, C> {
        let (platform, provider) = glfw_platform::Platform::new(context, glfw);
        self.with_context(platform)
            .with_provider(provider)
    }

    /// Use GLFW for the context and provider, taking them from the supplied.
    /// `glfw::Window`.
    /* #[cfg(glfw)] */
    pub fn with_glfw_window<'a>(self, window: &'a mut glfw::Window) -> GlfwBuilder<'a, glfw::RenderContext> {
        let context = window.render_context();
        self.with_glfw(&window.glfw, context)
    }
}

/// Terminal builder methods. These can only be called once both the context
/// and provider have been supplied.
impl<C: GraphicsContext<GlBackEnd>, P: GlProvider> Builder<SomeT<C>, SomeT<P>> {
    /// Create a `Renderer` and `Device`.
    pub fn create(self) -> Result<(Renderer, Device<render::Token, GlBackEnd, C>), InitError> {
        let Builder { context: SomeT(context), provider: SomeT(provider), queue_size } = self;
        device::init(context, provider, queue_size).map(|(tx, rx, server, ack, should_finish)| {
            (Renderer::new(tx, rx, ack, should_finish), server)
        })
    }

    /// Spawn the renderer in a new native task, and return the `Device`.
    pub fn spawn(self, f: proc(Renderer): 'static + Send) -> Result<Device<render::Token, GlBackEnd, C>, InitError> {
        match self.create() {
            Ok((renderer, device)) => {
                spawn(proc() f(renderer));
                Ok(device)
            },
            Err(e) => Err(e),
        }
    }
}
<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = if cfg!(unix) {
            unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
        } else {
            0
        };
        let f = File::create(path);
        if cfg!(unix) {
            unsafe {
                libc::umask(old_umask);
            }
        }
        let file = try!(f);
        if cfg!(unix) {
            use std::os::unix::io::AsRawFd;
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Try to fix windows build<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1])
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> u16 {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: u16) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(file: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use super::{Direction, History};
    use config::Config;

    fn init() -> super::History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>use cairo::Rectangle;
use markup5ever::local_name;

use crate::allowed_url::Fragment;
use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::dpi::Dpi;
use crate::drawing_ctx::{ClipMode, DrawingCtx, ViewParams};
use crate::error::{AcquireError, AttributeResultExt, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::*;
use crate::node::*;
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::property_defs::Overflow;
use crate::rect::RectangleExt;
use crate::viewbox::*;

#[derive(Default)]
pub struct NodeGroup();

impl NodeTrait for NodeGroup {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

/// A no-op node that does not render anything
///
/// Sometimes we just need a node that can contain children, but doesn't
/// render itself or its children.  This is just that kind of node.
#[derive(Default)]
pub struct NodeNonRendering;

impl NodeTrait for NodeNonRendering {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

#[derive(Default)]
pub struct NodeSwitch();

impl NodeTrait for NodeSwitch {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node
                .children()
                .filter(|c| c.borrow().get_type() != NodeType::Chars)
                .find(|c| c.borrow().get_cond())
            {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(dc.empty_bbox())
            }
        })
    }
}

/// Intrinsic dimensions of an SVG document fragment
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IntrinsicDimensions {
    pub width: Option<LengthHorizontal>,
    pub height: Option<LengthVertical>,
    pub vbox: Option<ViewBox>,
}

#[derive(Default)]
pub struct NodeSvg {
    preserve_aspect_ratio: AspectRatio,
    x: Option<LengthHorizontal>,
    y: Option<LengthVertical>,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
    vbox: Option<ViewBox>,
}

impl NodeSvg {
    pub fn get_size(&self, values: &ComputedValues, dpi: Dpi) -> Option<(i32, i32)> {
        let (_, _, w, h) = self.get_unnormalized_viewport();

        match (w, h, self.vbox) {
            (w, h, Some(vbox)) => {
                let params = ViewParams::new(dpi.x(), dpi.y(), vbox.width, vbox.height);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }

            (w, h, None) if w.unit() != LengthUnit::Percent && h.unit() != LengthUnit::Percent => {
                let params = ViewParams::new(dpi.x(), dpi.y(), 0.0, 0.0);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }
            (_, _, _) => None,
        }
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        IntrinsicDimensions {
            width: self.w,
            height: self.h,
            vbox: self.vbox,
        }
    }

    // returns (x, y, w, h)
    fn get_unnormalized_viewport(
        &self,
    ) -> (
        LengthHorizontal,
        LengthVertical,
        LengthHorizontal,
        LengthVertical,
    ) {
        // these defaults are per the spec
        let x = self
            .x
            .unwrap_or_else(|| LengthHorizontal::parse_str("0").unwrap());
        let y = self
            .y
            .unwrap_or_else(|| LengthVertical::parse_str("0").unwrap());
        let w = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap());
        let h = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap());

        (x, y, w, h)
    }

    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rectangle {
        let (x, y, w, h) = self.get_unnormalized_viewport();

        Rectangle::new(
            x.normalize(values, &params),
            y.normalize(values, &params),
            w.normalize(values, &params),
            h.normalize(values, &params),
        )
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = parent.is_some();

        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                local_name!("x") if is_inner_svg => self.x = Some(attr.parse(value)?),
                local_name!("y") if is_inner_svg => self.y = Some(attr.parse(value)?),
                local_name!("width") => {
                    self.w =
                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
                }
                local_name!("height") => {
                    self.h =
                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
                }
                local_name!("viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        let params = draw_ctx.get_view_params();

        let has_parent = node.parent().is_some();

        let clip_mode = if !values.is_overflow() && has_parent {
            Some(ClipMode::ClipToViewport)
        } else {
            None
        };

        let svg_viewport = self.get_viewport(values, &params);

        let is_measuring_toplevel_svg = !has_parent && draw_ctx.is_measuring();

        let (viewport, vbox) = if is_measuring_toplevel_svg {
            // We are obtaining the toplevel SVG's geometry.  This means, don't care about the
            // DrawingCtx's viewport, just use the SVG's intrinsic dimensions and see how far
            // it wants to extend.
            (svg_viewport, self.vbox)
        } else {
            if has_parent {
                (svg_viewport, self.vbox)
            } else {
                (
                    // The client's viewport overrides the toplevel's x/y/w/h viewport
                    draw_ctx.toplevel_viewport(),
                    // Use our viewBox if available, or try to derive one from
                    // the intrinsic dimensions.
                    self.vbox.or_else(|| {
                        Some(ViewBox {
                            x: 0.0,
                            y: 0.0,
                            width: svg_viewport.width,
                            height: svg_viewport.height,
                        })
                    }),
                )
            }
        };

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let _params =
                dc.push_new_viewport(vbox, &viewport, self.preserve_aspect_ratio, clip_mode);

            node.draw_children(cascaded, dc, clipping)
        })
    }
}

#[derive(Default)]
pub struct NodeUse {
    link: Option<Fragment>,
    x: LengthHorizontal,
    y: LengthVertical,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
}

impl NodeTrait for NodeUse {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("xlink:href") => {
                    self.link = Some(Fragment::parse(value).attribute(attr)?)
                }
                local_name!("x") => self.x = attr.parse(value)?,
                local_name!("y") => self.y = attr.parse(value)?,
                local_name!("width") => {
                    self.w = attr
                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
                        .map(Some)?
                }
                local_name!("height") => {
                    self.h = attr
                        .parse_and_validate(value, LengthVertical::check_nonnegative)
                        .map(Some)?
                }
                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        if self.link.is_none() {
            return Ok(draw_ctx.empty_bbox());
        }

        let link = self.link.as_ref().unwrap();

        let child = match draw_ctx.acquire_node(link, &[]) {
            Ok(acquired) => {
                // Here we clone the acquired child, so that we can drop the AcquiredNode as
                // early as possible.  This is so that the child's drawing method will be able
                // to re-acquire the child for other purposes.
                acquired.get().clone()
            }

            Err(AcquireError::CircularReference(_)) => {
                // FIXME: add a fragment or node id to this:
                rsvg_log!("circular reference in <use> element {}", node);
                return Err(RenderingError::CircularReference);
            }

            Err(AcquireError::MaxReferencesExceeded) => {
                return Err(RenderingError::InstancingLimit);
            }

            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),

            Err(AcquireError::LinkNotFound(fragment)) => {
                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
                return Ok(draw_ctx.empty_bbox());
            }
        };

        if node.ancestors().any(|ancestor| ancestor == child) {
            // or, if we're <use>'ing ourselves
            return Err(RenderingError::CircularReference);
        }

        let params = draw_ctx.get_view_params();

        let nx = self.x.normalize(values, &params);
        let ny = self.y.normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(0.0) || nh.approx_eq_cairo(0.0) {
            return Ok(draw_ctx.empty_bbox());
        }

        let viewport = Rectangle::new(nx, ny, nw, nh);

        if child.borrow().get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(viewport.x, viewport.y);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            let node_data = child.borrow();
            let symbol = node_data.get_impl::<NodeSymbol>();

            let clip_mode = if !values.is_overflow()
                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
            {
                Some(ClipMode::ClipToVbox)
            } else {
                None
            };

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let _params = dc.push_new_viewport(
                    symbol.vbox,
                    &viewport,
                    symbol.preserve_aspect_ratio,
                    clip_mode,
                );

                child.draw_children(
                    &CascadedValues::new_from_values(&child, values),
                    dc,
                    clipping,
                )
            })
        }
    }
}

#[derive(Default)]
pub struct NodeSymbol {
    preserve_aspect_ratio: AspectRatio,
    vbox: Option<ViewBox>,
}

impl NodeTrait for NodeSymbol {
    fn set_atts(&mut self, _parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                local_name!("viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }
}
<commit_msg>structure: marge "else if" in outer "if"<commit_after>use cairo::Rectangle;
use markup5ever::local_name;

use crate::allowed_url::Fragment;
use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::dpi::Dpi;
use crate::drawing_ctx::{ClipMode, DrawingCtx, ViewParams};
use crate::error::{AcquireError, AttributeResultExt, RenderingError};
use crate::float_eq_cairo::ApproxEqCairo;
use crate::length::*;
use crate::node::*;
use crate::parsers::{Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::property_defs::Overflow;
use crate::rect::RectangleExt;
use crate::viewbox::*;

#[derive(Default)]
pub struct NodeGroup();

impl NodeTrait for NodeGroup {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

/// A no-op node that does not render anything
///
/// Sometimes we just need a node that can contain children, but doesn't
/// render itself or its children.  This is just that kind of node.
#[derive(Default)]
pub struct NodeNonRendering;

impl NodeTrait for NodeNonRendering {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

#[derive(Default)]
pub struct NodeSwitch();

impl NodeTrait for NodeSwitch {
    fn set_atts(&mut self, _: Option<&RsvgNode>, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node
                .children()
                .filter(|c| c.borrow().get_type() != NodeType::Chars)
                .find(|c| c.borrow().get_cond())
            {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(dc.empty_bbox())
            }
        })
    }
}

/// Intrinsic dimensions of an SVG document fragment
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct IntrinsicDimensions {
    pub width: Option<LengthHorizontal>,
    pub height: Option<LengthVertical>,
    pub vbox: Option<ViewBox>,
}

#[derive(Default)]
pub struct NodeSvg {
    preserve_aspect_ratio: AspectRatio,
    x: Option<LengthHorizontal>,
    y: Option<LengthVertical>,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
    vbox: Option<ViewBox>,
}

impl NodeSvg {
    pub fn get_size(&self, values: &ComputedValues, dpi: Dpi) -> Option<(i32, i32)> {
        let (_, _, w, h) = self.get_unnormalized_viewport();

        match (w, h, self.vbox) {
            (w, h, Some(vbox)) => {
                let params = ViewParams::new(dpi.x(), dpi.y(), vbox.width, vbox.height);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }

            (w, h, None) if w.unit() != LengthUnit::Percent && h.unit() != LengthUnit::Percent => {
                let params = ViewParams::new(dpi.x(), dpi.y(), 0.0, 0.0);

                Some((
                    w.normalize(values, &params).round() as i32,
                    h.normalize(values, &params).round() as i32,
                ))
            }
            (_, _, _) => None,
        }
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        IntrinsicDimensions {
            width: self.w,
            height: self.h,
            vbox: self.vbox,
        }
    }

    // returns (x, y, w, h)
    fn get_unnormalized_viewport(
        &self,
    ) -> (
        LengthHorizontal,
        LengthVertical,
        LengthHorizontal,
        LengthVertical,
    ) {
        // these defaults are per the spec
        let x = self
            .x
            .unwrap_or_else(|| LengthHorizontal::parse_str("0").unwrap());
        let y = self
            .y
            .unwrap_or_else(|| LengthVertical::parse_str("0").unwrap());
        let w = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap());
        let h = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap());

        (x, y, w, h)
    }

    fn get_viewport(&self, values: &ComputedValues, params: &ViewParams) -> Rectangle {
        let (x, y, w, h) = self.get_unnormalized_viewport();

        Rectangle::new(
            x.normalize(values, &params),
            y.normalize(values, &params),
            w.normalize(values, &params),
            h.normalize(values, &params),
        )
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = parent.is_some();

        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                local_name!("x") if is_inner_svg => self.x = Some(attr.parse(value)?),
                local_name!("y") if is_inner_svg => self.y = Some(attr.parse(value)?),
                local_name!("width") => {
                    self.w =
                        Some(attr.parse_and_validate(value, LengthHorizontal::check_nonnegative)?)
                }
                local_name!("height") => {
                    self.h =
                        Some(attr.parse_and_validate(value, LengthVertical::check_nonnegative)?)
                }
                local_name!("viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        let params = draw_ctx.get_view_params();

        let has_parent = node.parent().is_some();

        let clip_mode = if !values.is_overflow() && has_parent {
            Some(ClipMode::ClipToViewport)
        } else {
            None
        };

        let svg_viewport = self.get_viewport(values, &params);

        let is_measuring_toplevel_svg = !has_parent && draw_ctx.is_measuring();

        let (viewport, vbox) = if is_measuring_toplevel_svg {
            // We are obtaining the toplevel SVG's geometry.  This means, don't care about the
            // DrawingCtx's viewport, just use the SVG's intrinsic dimensions and see how far
            // it wants to extend.
            (svg_viewport, self.vbox)
        } else if has_parent {
            (svg_viewport, self.vbox)
        } else {
            (
                // The client's viewport overrides the toplevel's x/y/w/h viewport
                draw_ctx.toplevel_viewport(),
                // Use our viewBox if available, or try to derive one from
                // the intrinsic dimensions.
                self.vbox.or_else(|| {
                    Some(ViewBox {
                        x: 0.0,
                        y: 0.0,
                        width: svg_viewport.width,
                        height: svg_viewport.height,
                    })
                }),
            )
        };

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            let _params =
                dc.push_new_viewport(vbox, &viewport, self.preserve_aspect_ratio, clip_mode);

            node.draw_children(cascaded, dc, clipping)
        })
    }
}

#[derive(Default)]
pub struct NodeUse {
    link: Option<Fragment>,
    x: LengthHorizontal,
    y: LengthVertical,
    w: Option<LengthHorizontal>,
    h: Option<LengthVertical>,
}

impl NodeTrait for NodeUse {
    fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("xlink:href") => {
                    self.link = Some(Fragment::parse(value).attribute(attr)?)
                }
                local_name!("x") => self.x = attr.parse(value)?,
                local_name!("y") => self.y = attr.parse(value)?,
                local_name!("width") => {
                    self.w = attr
                        .parse_and_validate(value, LengthHorizontal::check_nonnegative)
                        .map(Some)?
                }
                local_name!("height") => {
                    self.h = attr
                        .parse_and_validate(value, LengthVertical::check_nonnegative)
                        .map(Some)?
                }
                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let values = cascaded.get();

        if self.link.is_none() {
            return Ok(draw_ctx.empty_bbox());
        }

        let link = self.link.as_ref().unwrap();

        let child = match draw_ctx.acquire_node(link, &[]) {
            Ok(acquired) => {
                // Here we clone the acquired child, so that we can drop the AcquiredNode as
                // early as possible.  This is so that the child's drawing method will be able
                // to re-acquire the child for other purposes.
                acquired.get().clone()
            }

            Err(AcquireError::CircularReference(_)) => {
                // FIXME: add a fragment or node id to this:
                rsvg_log!("circular reference in <use> element {}", node);
                return Err(RenderingError::CircularReference);
            }

            Err(AcquireError::MaxReferencesExceeded) => {
                return Err(RenderingError::InstancingLimit);
            }

            Err(AcquireError::InvalidLinkType(_)) => unreachable!(),

            Err(AcquireError::LinkNotFound(fragment)) => {
                rsvg_log!("element {} references nonexistent \"{}\"", node, fragment);
                return Ok(draw_ctx.empty_bbox());
            }
        };

        if node.ancestors().any(|ancestor| ancestor == child) {
            // or, if we're <use>'ing ourselves
            return Err(RenderingError::CircularReference);
        }

        let params = draw_ctx.get_view_params();

        let nx = self.x.normalize(values, &params);
        let ny = self.y.normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .unwrap_or_else(|| LengthHorizontal::parse_str("100%").unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .unwrap_or_else(|| LengthVertical::parse_str("100%").unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(0.0) || nh.approx_eq_cairo(0.0) {
            return Ok(draw_ctx.empty_bbox());
        }

        let viewport = Rectangle::new(nx, ny, nw, nh);

        if child.borrow().get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(viewport.x, viewport.y);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            let node_data = child.borrow();
            let symbol = node_data.get_impl::<NodeSymbol>();

            let clip_mode = if !values.is_overflow()
                || (values.overflow == Overflow::Visible && child.borrow().is_overflow())
            {
                Some(ClipMode::ClipToVbox)
            } else {
                None
            };

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let _params = dc.push_new_viewport(
                    symbol.vbox,
                    &viewport,
                    symbol.preserve_aspect_ratio,
                    clip_mode,
                );

                child.draw_children(
                    &CascadedValues::new_from_values(&child, values),
                    dc,
                    clipping,
                )
            })
        }
    }
}

#[derive(Default)]
pub struct NodeSymbol {
    preserve_aspect_ratio: AspectRatio,
    vbox: Option<ViewBox>,
}

impl NodeTrait for NodeSymbol {
    fn set_atts(&mut self, _parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                local_name!("preserveAspectRatio") => {
                    self.preserve_aspect_ratio = attr.parse(value)?
                }
                local_name!("viewBox") => self.vbox = attr.parse(value).map(Some)?,
                _ => (),
            }
        }

        Ok(())
    }

    fn overflow_hidden(&self) -> bool {
        true
    }
}
<|endoftext|>