<commit_before>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::error::FromError;
use std::io;
use std::mem;
use std::result;
use std::io::ReadExt;

use iter::{RexIterExt, ResultIterExt};

/// `Error` is used to report errors that occur within the decoder.
pub enum Error {
    /// `EOF` indicates that record source ended before it could be fully decoded.
    EOF,

    /// `IoError` is used to pass through std::io errors.
    IoError(io::Error),
}

impl FromError<io::Error> for Error {
    fn from_error(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

/// `read_uvarint` reads a varint encoded `u64` from `r`.
fn read_uvarint<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes()
        .take_while_incl(|x| match x { &Ok(x) => x >= 0x80, _ => true });

    // The Ok(try!(..)) just lets us convert from io::Error to Error
    result::fold(itr, 0, |sum, x| (sum << 7) + (x & 0x7F) as u64)
        .map_err(FromError::from_error)
}

/// `read_varint` reads a zig-zag varint encoded `i64` from `r`.
fn read_varint<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    let ux = try!(read_uvarint(r));

    Ok( if ux & 1 != 0 {
        let x = (!ux >> 1) as i64;
        -x
    } else {
        let x = (ux >> 1) as i64;
        x
    })
}

/// `read_u8` reads a single byte from `r`.
fn read_u8<R>(r: &mut R) -> Result<u8, Error>
    where R: io::Read {

    r.bytes()
        .take_or_err(1, Error::EOF)
        .next()
        // take_or_err guarantees that we'll get an Error at worst.
        .unwrap()
}

/// `read_le_u16` reads 2 bytes as a little endian `u16` from 'r'
fn read_le_u16<R>(r: &mut R) -> Result<u16, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(2, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u16)
}

/// `read_le_u32` reads 4 bytes as a little endian `u32` from 'r'
fn read_le_u32<R>(r: &mut R) -> Result<u32, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(4, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u32)
}

/// `read_le_u64` reads 8 bytes as a little endian `u64` from 'r'
fn read_le_u64<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(8, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u64)
}

/// `read_i8` reads a single byte from `r`, as a 2's complement `i8`
fn read_i8<R>(r: &mut R) -> Result<i8, Error>
    where R: io::Read {

    Ok(try!(read_u8(r)) as i8)
}

/// `read_le_i16` reads 2 bytes as a little endian 2's complement `i16` from `r`.
fn read_le_i16<R>(r: &mut R) -> Result<i16, Error>
    where R: io::Read {

    Ok(try!(read_le_u16(r)) as i16)
}

/// `read_le_i32` reads 4 bytes as a little endian 2's complement `i32` from `r`.
fn read_le_i32<R>(r: &mut R) -> Result<i32, Error>
    where R: io::Read {

    Ok(try!(read_le_u32(r)) as i32)
}

/// `read_le_i64` reads 8 bytes as a little endian 2's complement `i64` from `r`.
fn read_le_i64<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    Ok(try!(read_le_u64(r)) as i64)
}

/// `read_le_f32` reads 8 bytes as a little endian ieee-754 binary32 encoded `f32` from `r`.
fn read_le_f32<R>(r: &mut R) -> Result<f32, Error>
    where R: io::Read {

    let u = try!(read_le_u32(r));

    Ok(unsafe { mem::transmute(u) })
}

/// `read_le_f64` reads 8 bytes as a little endian ieee-754 binary64 encoded `f64` from `r`.
fn read_le_f64<R>(r: &mut R) -> Result<f64, Error>
    where R: io::Read {

    let u = try!(read_le_u64(r));

    Ok(unsafe { mem::transmute(u) })
}
<commit_msg>Allow dead_code until the decoder is stable<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Allow dead code to silence warnings until things stabilize.
#![allow(dead_code)]

use std::error::FromError;
use std::io;
use std::mem;
use std::result;
use std::io::ReadExt;

use iter::{RexIterExt, ResultIterExt};

/// `Error` is used to report errors that occur within the decoder.
pub enum Error {
    /// `EOF` indicates that record source ended before it could be fully decoded.
    EOF,

    /// `IoError` is used to pass through std::io errors.
    IoError(io::Error),
}

impl FromError<io::Error> for Error {
    fn from_error(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

/// `read_uvarint` reads a varint encoded `u64` from `r`.
fn read_uvarint<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes()
        .take_while_incl(|x| match x { &Ok(x) => x >= 0x80, _ => true });

    // The Ok(try!(..)) just lets us convert from io::Error to Error
    result::fold(itr, 0, |sum, x| (sum << 7) + (x & 0x7F) as u64)
        .map_err(FromError::from_error)
}

/// `read_varint` reads a zig-zag varint encoded `i64` from `r`.
fn read_varint<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    let ux = try!(read_uvarint(r));

    Ok( if ux & 1 != 0 {
        let x = (!ux >> 1) as i64;
        -x
    } else {
        let x = (ux >> 1) as i64;
        x
    })
}

/// `read_u8` reads a single byte from `r`.
fn read_u8<R>(r: &mut R) -> Result<u8, Error>
    where R: io::Read {

    r.bytes()
        .take_or_err(1, Error::EOF)
        .next()
        // take_or_err guarantees that we'll get an Error at worst.
        .unwrap()
}

/// `read_le_u16` reads 2 bytes as a little endian `u16` from 'r'
fn read_le_u16<R>(r: &mut R) -> Result<u16, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(2, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u16)
}

/// `read_le_u32` reads 4 bytes as a little endian `u32` from 'r'
fn read_le_u32<R>(r: &mut R) -> Result<u32, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(4, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u32)
}

/// `read_le_u64` reads 8 bytes as a little endian `u64` from 'r'
fn read_le_u64<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(8, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u64)
}

/// `read_i8` reads a single byte from `r`, as a 2's complement `i8`
fn read_i8<R>(r: &mut R) -> Result<i8, Error>
    where R: io::Read {

    Ok(try!(read_u8(r)) as i8)
}

/// `read_le_i16` reads 2 bytes as a little endian 2's complement `i16` from `r`.
fn read_le_i16<R>(r: &mut R) -> Result<i16, Error>
    where R: io::Read {

    Ok(try!(read_le_u16(r)) as i16)
}

/// `read_le_i32` reads 4 bytes as a little endian 2's complement `i32` from `r`.
fn read_le_i32<R>(r: &mut R) -> Result<i32, Error>
    where R: io::Read {

    Ok(try!(read_le_u32(r)) as i32)
}

/// `read_le_i64` reads 8 bytes as a little endian 2's complement `i64` from `r`.
fn read_le_i64<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    Ok(try!(read_le_u64(r)) as i64)
}

/// `read_le_f32` reads 8 bytes as a little endian ieee-754 binary32 encoded `f32` from `r`.
fn read_le_f32<R>(r: &mut R) -> Result<f32, Error>
    where R: io::Read {

    let u = try!(read_le_u32(r));

    Ok(unsafe { mem::transmute(u) })
}

/// `read_le_f64` reads 8 bytes as a little endian ieee-754 binary64 encoded `f64` from `r`.
fn read_le_f64<R>(r: &mut R) -> Result<f64, Error>
    where R: io::Read {

    let u = try!(read_le_u64(r));

    Ok(unsafe { mem::transmute(u) })
}
<|endoftext|>


<commit_before>//! Features and intervals for gene annotations.

use std::collections::HashMap;

use bio::io::Strand;

use self::error::FeatureError;

pub mod error {

    use std::error::Error;
    use std::fmt;

    #[derive(Debug)]
    pub enum FeatureError {
        InvalidCoords,
    }

    impl Error for FeatureError {
        fn description(&self) -> &str {
            match *self {
                FeatureError::InvalidCoords => "interval start coordinate larger than its end coordinate"
            }
        }

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

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

/// Interface for features with start and end coordinates.
///
/// The intervals represented here are zero-based, half open intervals.
/// Coordinates start from zero and start coordinates must be less than
/// or equal to the end coordinates.
pub trait Interval: Sized {

    /// Start coordinate of the interval.
    fn start(&self) -> u64;

    /// End coordinate of the interval.
    fn end(&self) -> u64;

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Coordinate setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_coords(self, start: u64, end: u64) -> Self;

    /// Performs various validation of the interval.
    fn validate(self) -> Result<Self, FeatureError> {
        self.validate_coords()
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an intersection or not.
    fn overlaps(&self, other: &Self) -> bool {
        (other.start() <= self.start() && self.start() <= other.end()) ||
        (other.start() <= self.end() && self.end() <= other.end())
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }

    /// Performs validation of the interval coordinates.
    ///
    /// If the validation fails, an error message is returned within
    /// the `Result` type.
    fn validate_coords(self) -> Result<Self, FeatureError> {
        if self.start() > self.end() {
            return Err(FeatureError::InvalidCoords)
        }

        Ok(self)
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_interval {
    ($struct_ty:ty) => (

        impl Interval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            /// Start coordinate of the interval.
            fn start(&self) -> u64 {
                self.start
            }

            /// End coordinate of the interval.
            fn end(&self) -> u64 {
                self.end
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }

            fn with_coords(mut self, start: u64, end: u64) -> $struct_ty {
                self.start = start;
                self.end = end;
                self
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug, Default)]
pub struct Feature {
    start: u64,
    end: u64,
    name: Option<String>,
}

impl Feature {

    /// Creates a gene interval with default values.
    ///
    /// A gene interval is a container for transcript intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// let gene = Feature::gene();
    ///
    /// assert_eq!(gene.transcript().len(), 0);
    /// assert_eq!(gene.start(), 0);
    /// assert_eq!(gene.end(), 0);
    /// assert_eq!(gene.name(), None);
    /// ```
    pub fn gene() -> Gene {
        Gene::default()
    }

    /// Creates a transcript interval with default values.
    ///
    /// A transcript interval is a container for exon intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// use bio::io::Strand;
    ///
    /// let transcript = Feature::transcript();
    ///
    /// assert_eq!(transcript.exons().len(), 0);
    /// assert_eq!(transcript.strand(), &Strand::Unknown)
    /// assert_eq!(transcript.start(), 0);
    /// assert_eq!(transcript.end(), 0);
    /// assert_eq!(transcript.name(), None);
    /// ```
    pub fn transcript() -> Transcript {
        Transcript::default()
    }

    /// Creates an exon interval with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// let exon = Feature::exon();
    ///
    /// assert_eq!(exon.start(), 0);
    /// assert_eq!(exon.end(), 0);
    /// assert_eq!(exon.name(), None);
    /// ```
    pub fn exon() -> Exon {
        Exon::default()
    }

    pub fn with_coords(mut self, start: u64, end: u64) -> Feature {
        self.start = start;
        self.end = end;
        self
    }
}

impl_interval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert!(fx.validate().is_ok());
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }

    #[test]
    fn with_coords() {
        let fx = Feature::default()
            .with_coords(1, 3);
        assert_eq!(fx.start(), 1);
        assert_eq!(fx.end(), 3);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_multiples() {
        let fx = Feature::default()
            .with_name("fx")
            .with_coords(20, 30);
        assert_eq!(fx.start(), 20);
        assert_eq!(fx.end(), 30);
        assert_eq!(fx.name(), Some("fx"));
    }
}

/// Gene annotation.
#[derive(Debug, Default)]
pub struct Gene {
    name: Option<String>,
    start: u64,
    end: u64,
    transcripts: HashMap<String, Transcript>,
}

impl Gene {

    pub fn transcripts(&self) -> &HashMap<String, Transcript> {
        &self.transcripts
    }
}

impl_interval!(Gene);

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

    #[test]
    fn default() {
        let gene = Feature::gene();
        assert_eq!(gene.start(), 0);
        assert_eq!(gene.end(), 0);
        assert_eq!(gene.name(), None);
        assert_eq!(gene.transcripts().len(), 0);
    }
}

/// Transcript annotation.
#[derive(Debug)]
pub struct Transcript {
    name: Option<String>,
    strand: Strand,
    start: u64,
    end: u64,
    cds_start: Option<u64>,
    cds_end: Option<u64>,
    exons: Vec<Exon>,
}

impl Transcript {

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

    pub fn with_strand(mut self, strand: Strand) -> Transcript {
        self.strand = strand;
        self
    }

    pub fn cds_start(&self) -> Option<u64> {
        self.cds_start
    }

    pub fn with_cds_start(mut self, cds_start: u64) -> Transcript {
        self.cds_start = Some(cds_start);
        self
    }

    pub fn cds_end(&self) -> Option<u64> {
        self.cds_end
    }

    pub fn with_cds_end(mut self, cds_end: u64) -> Transcript {
        self.cds_end = Some(cds_end);
        self
    }

    pub fn exons(&self) -> &Vec<Exon> {
        &self.exons
    }
}

impl Default for Transcript {

    fn default() -> Transcript {
        Transcript {
            name: None,
            strand: Strand::Unknown,
            start: 0,
            end: 0,
            cds_start: None,
            cds_end: None,
            exons: Vec::new(),
        }
    }
}

impl_interval!(Transcript);

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

    #[test]
    fn default() {
        let trx = Feature::transcript();
        assert_eq!(trx.start(), 0);
        assert_eq!(trx.end(), 0);
        assert_eq!(trx.name(), None);
        assert_eq!(trx.strand(), &Strand::Unknown);
        assert_eq!(trx.cds_start(), None);
        assert_eq!(trx.cds_end(), None);
        assert_eq!(trx.exons().len(), 0);
    }

    #[test]
    fn with_strand() {
        let trx = Feature::transcript()
            .with_strand(Strand::Forward);
        assert_eq!(trx.strand(), &Strand::Forward);
    }

    #[test]
    fn with_cds_start() {
        let trx = Feature::transcript()
            .with_cds_start(20);
        assert_eq!(trx.cds_start(), Some(20));
    }

    #[test]
    fn with_cds_end() {
        let trx = Feature::transcript()
            .with_cds_end(40);
        assert_eq!(trx.cds_end(), Some(40))
    }
}

/// Exon annotation.
#[derive(Debug, Default)]
pub struct Exon {
    name: Option<String>,
    start: u64,
    end: u64,
}

impl_interval!(Exon);

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

    #[test]
    fn default() {
        let exon = Feature::exon();
        assert_eq!(exon.start(), 0);
        assert_eq!(exon.end(), 0);
        assert_eq!(exon.name(), None);
    }
}
<commit_msg>Add exon functions to transcript<commit_after>//! Features and intervals for gene annotations.

use std::collections::HashMap;

use bio::io::Strand;

use self::error::FeatureError;

pub mod error {

    use std::error::Error;
    use std::fmt;

    #[derive(Debug)]
    pub enum FeatureError {
        InvalidCoords,
    }

    impl Error for FeatureError {
        fn description(&self) -> &str {
            match *self {
                FeatureError::InvalidCoords => "interval start coordinate larger than its end coordinate"
            }
        }

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

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

/// Interface for features with start and end coordinates.
///
/// The intervals represented here are zero-based, half open intervals.
/// Coordinates start from zero and start coordinates must be less than
/// or equal to the end coordinates.
pub trait Interval: Sized {

    /// Start coordinate of the interval.
    fn start(&self) -> u64;

    /// End coordinate of the interval.
    fn end(&self) -> u64;

    /// Name of the interval.
    fn name(&self) -> Option<&str>;

    /// Name setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_name<T: Into<String>>(self, name: T) -> Self;

    /// Coordinate setter that returns the implementor itself.
    ///
    /// This function is expected to mutate the implementing type.
    fn with_coords(self, start: u64, end: u64) -> Self;

    /// Performs various validation of the interval.
    fn validate(self) -> Result<Self, FeatureError> {
        self.validate_coords()
    }

    /// The number of bases covered by the interval.
    fn span(&self) -> u64 {
        self.end() - self.start()
    }

    /// Whether two intervals have an intersection or not.
    fn overlaps(&self, other: &Self) -> bool {
        (other.start() <= self.start() && self.start() <= other.end()) ||
        (other.start() <= self.end() && self.end() <= other.end())
    }

    /// Whether one interval completely contains the other.
    fn envelops(&self, other: &Self) -> bool {
        self.start() <= other.start() && self.end() >= other.end()
    }

    /// Whether two intervals cover a contiguous region without any overlaps.
    fn adjacent(&self, other: &Self) -> bool {
        self.end() == other.start() || self.start() == other.end()
    }

    /// Performs validation of the interval coordinates.
    ///
    /// If the validation fails, an error message is returned within
    /// the `Result` type.
    fn validate_coords(self) -> Result<Self, FeatureError> {
        if self.start() > self.end() {
            return Err(FeatureError::InvalidCoords)
        }

        Ok(self)
    }
}

/// Macro for default function implementations of interval types.
macro_rules! impl_interval {
    ($struct_ty:ty) => (

        impl Interval for $struct_ty {

            /// Name of the interval.
            fn name(&self) -> Option<&str> {
                self.name.as_ref().map(|n| n.as_str())
            }

            /// Start coordinate of the interval.
            fn start(&self) -> u64 {
                self.start
            }

            /// End coordinate of the interval.
            fn end(&self) -> u64 {
                self.end
            }

            fn with_name<T>(mut self, name: T) -> $struct_ty
                where T: Into<String>
            {
                self.name = Some(name.into());
                self
            }

            fn with_coords(mut self, start: u64, end: u64) -> $struct_ty {
                self.start = start;
                self.end = end;
                self
            }
        }

    );
}

/// Default implementation of the `Interval` trait.
///
/// This struct also provides static methods for creating exons, transcripts, and genes.
#[derive(Debug, Default)]
pub struct Feature {
    start: u64,
    end: u64,
    name: Option<String>,
}

impl Feature {

    /// Creates a gene interval with default values.
    ///
    /// A gene interval is a container for transcript intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// let gene = Feature::gene();
    ///
    /// assert_eq!(gene.transcript().len(), 0);
    /// assert_eq!(gene.start(), 0);
    /// assert_eq!(gene.end(), 0);
    /// assert_eq!(gene.name(), None);
    /// ```
    pub fn gene() -> Gene {
        Gene::default()
    }

    /// Creates a transcript interval with default values.
    ///
    /// A transcript interval is a container for exon intervals.
    ///
    /// # Examples
    ///
    /// ```
    /// use bio::io::Strand;
    ///
    /// let transcript = Feature::transcript();
    ///
    /// assert_eq!(transcript.exons().len(), 0);
    /// assert_eq!(transcript.strand(), &Strand::Unknown)
    /// assert_eq!(transcript.start(), 0);
    /// assert_eq!(transcript.end(), 0);
    /// assert_eq!(transcript.name(), None);
    /// ```
    pub fn transcript() -> Transcript {
        Transcript::default()
    }

    /// Creates an exon interval with default values.
    ///
    /// # Examples
    ///
    /// ```
    /// let exon = Feature::exon();
    ///
    /// assert_eq!(exon.start(), 0);
    /// assert_eq!(exon.end(), 0);
    /// assert_eq!(exon.name(), None);
    /// ```
    pub fn exon() -> Exon {
        Exon::default()
    }

    pub fn with_coords(mut self, start: u64, end: u64) -> Feature {
        self.start = start;
        self.end = end;
        self
    }
}

impl_interval!(Feature);

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

    #[test]
    fn default() {
        let fx = Feature::default();
        assert_eq!(fx.start(), 0);
        assert_eq!(fx.end(), 0);
        assert!(fx.validate().is_ok());
    }

    #[test]
    fn with_name() {
        let fx1 = Feature::default()
            .with_name("fx1");
        assert_eq!(fx1.start(), 0);
        assert_eq!(fx1.end(), 0);
        assert_eq!(fx1.name(), Some("fx1"));

        let fx2 = Feature::default()
            .with_name("fx2".to_owned());
        assert_eq!(fx2.start(), 0);
        assert_eq!(fx2.end(), 0);
        assert_eq!(fx2.name(), Some("fx2"));
    }

    #[test]
    fn with_coords() {
        let fx = Feature::default()
            .with_coords(1, 3);
        assert_eq!(fx.start(), 1);
        assert_eq!(fx.end(), 3);
        assert_eq!(fx.name(), None);
    }

    #[test]
    fn with_multiples() {
        let fx = Feature::default()
            .with_name("fx")
            .with_coords(20, 30);
        assert_eq!(fx.start(), 20);
        assert_eq!(fx.end(), 30);
        assert_eq!(fx.name(), Some("fx"));
    }
}

/// Gene annotation.
#[derive(Debug, Default)]
pub struct Gene {
    name: Option<String>,
    start: u64,
    end: u64,
    transcripts: HashMap<String, Transcript>,
}

impl Gene {

    pub fn transcripts(&self) -> &HashMap<String, Transcript> {
        &self.transcripts
    }
}

impl_interval!(Gene);

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

    #[test]
    fn default() {
        let gene = Feature::gene();
        assert_eq!(gene.start(), 0);
        assert_eq!(gene.end(), 0);
        assert_eq!(gene.name(), None);
        assert_eq!(gene.transcripts().len(), 0);
    }
}

/// Transcript annotation.
#[derive(Debug)]
pub struct Transcript {
    name: Option<String>,
    strand: Strand,
    start: u64,
    end: u64,
    cds_start: Option<u64>,
    cds_end: Option<u64>,
    exons: Vec<Exon>,
}

impl Transcript {

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

    pub fn with_strand(mut self, strand: Strand) -> Transcript {
        self.strand = strand;
        self
    }

    pub fn cds_start(&self) -> Option<u64> {
        self.cds_start
    }

    pub fn with_cds_start(mut self, cds_start: u64) -> Transcript {
        self.cds_start = Some(cds_start);
        self
    }

    pub fn cds_end(&self) -> Option<u64> {
        self.cds_end
    }

    pub fn with_cds_end(mut self, cds_end: u64) -> Transcript {
        self.cds_end = Some(cds_end);
        self
    }

    pub fn exons(&self) -> &Vec<Exon> {
        &self.exons
    }

    pub fn with_exons(mut self, exons: Vec<Exon>) -> Transcript {
        self.exons = exons;
        self
    }

    pub fn insert_exon(&mut self, exon: Exon) {
        self.exons.push(exon);
    }
}

impl Default for Transcript {

    fn default() -> Transcript {
        Transcript {
            name: None,
            strand: Strand::Unknown,
            start: 0,
            end: 0,
            cds_start: None,
            cds_end: None,
            exons: Vec::new(),
        }
    }
}

impl_interval!(Transcript);

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

    #[test]
    fn default() {
        let trx = Feature::transcript();
        assert_eq!(trx.start(), 0);
        assert_eq!(trx.end(), 0);
        assert_eq!(trx.name(), None);
        assert_eq!(trx.strand(), &Strand::Unknown);
        assert_eq!(trx.cds_start(), None);
        assert_eq!(trx.cds_end(), None);
        assert_eq!(trx.exons().len(), 0);
    }

    #[test]
    fn with_strand() {
        let trx = Feature::transcript()
            .with_strand(Strand::Forward);
        assert_eq!(trx.strand(), &Strand::Forward);
    }

    #[test]
    fn with_cds_start() {
        let trx = Feature::transcript()
            .with_cds_start(20);
        assert_eq!(trx.cds_start(), Some(20));
    }

    #[test]
    fn with_cds_end() {
        let trx = Feature::transcript()
            .with_cds_end(40);
        assert_eq!(trx.cds_end(), Some(40))
    }

    #[test]
    fn with_exons() {
        let trx = Feature::transcript()
            .with_exons(vec![
                Exon::new(1, 2, Some("ex1")),
                Exon::new(10, 20, Some("ex2")),
                Exon::new(100, 200, Some("ex3")),
            ]);
        assert_eq!(trx.exons().len(), 3);
    }

    #[test]
    fn insert_exon() {
        let mut trx = Feature::transcript();
        assert_eq!(trx.exons().len(), 0);
        trx.insert_exon(Exon::new(1, 2, Some("ex")));
        assert_eq!(trx.exons().len(), 1);
    }
}

/// Exon annotation.
#[derive(Debug, Default)]
pub struct Exon {
    name: Option<String>,
    start: u64,
    end: u64,
}

impl Exon {

    fn new<T>(start: u64, end: u64, name: Option<T>) -> Exon
        where T: Into<String>
    {
        Exon { start: start, end: end,
               name: name.map(|n| n.into()) }
    }
}

impl_interval!(Exon);

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

    #[test]
    fn default() {
        let exon = Feature::exon();
        assert_eq!(exon.start(), 0);
        assert_eq!(exon.end(), 0);
        assert_eq!(exon.name(), None);
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use tbot::{connectors::Https, types::parameters};
use tokio::{
    self, select,
    stream::StreamExt,
    sync::Notify,
    time::{self, delay_queue::DelayQueue, Duration},
};

use crate::client::pull_feed;
use crate::data::{Database, Feed, FeedUpdate};
use crate::messages::{format_large_msg, Escape};

pub fn start(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    min_interval: u32,
    max_interval: u32,
) {
    let mut queue = FetchQueue::new();
    // TODO: Don't use interval, it can accumulate ticks
    // replace it with delay_until
    let mut interval = time::interval(Duration::from_secs(min_interval as u64));
    tokio::spawn(async move {
        loop {
            select! {
                _ = interval.tick() => {
                    let feeds = db.lock().unwrap().all_feeds();
                    for feed in feeds {
                        let feed_interval =
                            cmp::min(feed.ttl.map(|ttl| ttl * 60).unwrap_or(min_interval), max_interval) as u64;
                        queue.enqueue(feed, Duration::from_secs(feed_interval));
                    }
                }
                feed = queue.next() => {
                    let feed = feed.expect("unreachable");
                    let bot = bot.clone();
                    let db = db.clone();
                    tokio::spawn(async move {
                        if let Err(e) = fetch_and_push_updates(bot, db, feed).await {
                            dbg!(e);
                        }
                    });
                }
            }
        }
    });
}

async fn fetch_and_push_updates(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    feed: Feed,
) -> Result<(), tbot::errors::MethodCall> {
    let new_feed = match pull_feed(&feed.link).await {
        Ok(feed) => feed,
        Err(e) => {
            let down_time = db.lock().unwrap().get_or_update_down_time(&feed.link);
            // 5 days
            if down_time.as_secs() > 5 * 24 * 60 * 60 {
                let msg = format!(
                    "《{}》\
                     已经连续 5 天拉取出错 ({}),\
                     可能已经关闭, 请取消订阅",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&e.to_string())
                );
                push_updates(&bot, &db, feed.subscribers, parameters::Text::html(&msg)).await?;
            }
            return Ok(());
        }
    };

    let updates = db.lock().unwrap().update(&feed.link, new_feed);
    for update in updates {
        match update {
            FeedUpdate::Items(items) => {
                let msgs =
                    format_large_msg(format!("{}", Escape(&feed.title)), &items, |item| {
                        let title = item
                            .title
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.title);
                        let link = item
                            .link
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.link);
                        format!("{}", Escape(link), Escape(title))
                    });
                for msg in msgs {
                    push_updates(
                        &bot,
                        &db,
                        feed.subscribers.iter().copied(),
                        parameters::Text::html(&msg),
                    )
                    .await?;
                }
            }
            FeedUpdate::Title(new_title) => {
                let msg = format!(
                    "{} 已更名为 {}",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&new_title)
                );
                push_updates(
                    &bot,
                    &db,
                    feed.subscribers.iter().copied(),
                    parameters::Text::html(&msg),
                )
                .await?;
            }
        }
    }
    Ok(())
}

async fn push_updates<I: IntoIterator<Item = i64>>(
    bot: &tbot::Bot<Https>,
    db: &Arc<Mutex<Database>>,
    subscribers: I,
    msg: parameters::Text<'_>,
) -> Result<(), tbot::errors::MethodCall> {
    use tbot::errors::MethodCall;
    for mut subscriber in subscribers {
        'retry: for _ in 0..3 {
            match bot
                .send_message(tbot::types::chat::Id(subscriber), msg)
                .call()
                .await
            {
                Err(MethodCall::RequestError { description, .. })
                    if chat_is_unavailable(&description) =>
                {
                    db.lock().unwrap().delete_subscriber(subscriber);
                }
                Err(MethodCall::RequestError {
                    migrate_to_chat_id: Some(new_chat_id),
                    ..
                }) => {
                    db.lock()
                        .unwrap()
                        .update_subscriber(subscriber, new_chat_id.0);
                    subscriber = new_chat_id.0;
                    continue 'retry;
                }
                Err(MethodCall::RequestError {
                    retry_after: Some(delay),
                    ..
                }) => {
                    time::delay_for(Duration::from_secs(delay)).await;
                    continue 'retry;
                }
                other => {
                    other?;
                }
            }
            break 'retry;
        }
    }
    Ok(())
}

pub fn chat_is_unavailable(s: &str) -> bool {
    s.contains("Forbidden") || s.contains("chat not found")
}

#[derive(Default)]
struct FetchQueue {
    feeds: HashMap<String, Feed>,
    notifies: DelayQueue<String>,
    wakeup: Notify,
}

impl FetchQueue {
    fn new() -> Self {
        Self::default()
    }

    fn enqueue(&mut self, feed: Feed, delay: Duration) -> bool {
        let exists = self.feeds.contains_key(&feed.link);
        if !exists {
            self.notifies.insert(feed.link.clone(), delay);
            self.feeds.insert(feed.link.clone(), feed);
            self.wakeup.notify();
        }
        !exists
    }

    async fn next(&mut self) -> Result<Feed, time::Error> {
        loop {
            if let Some(feed_id) = self.notifies.next().await {
                let feed = self.feeds.remove(feed_id?.get_ref()).unwrap();
                break Ok(feed);
            } else {
                self.wakeup.notified().await;
            }
        }
    }
}
<commit_msg>Fix the fetcher starts too slow<commit_after>use std::cmp;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use tbot::{connectors::Https, types::parameters};
use tokio::{
    self, select,
    stream::StreamExt,
    sync::Notify,
    time::{self, delay_queue::DelayQueue, Duration, Instant},
};

use crate::client::pull_feed;
use crate::data::{Database, Feed, FeedUpdate};
use crate::messages::{format_large_msg, Escape};

pub fn start(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    min_interval: u32,
    max_interval: u32,
) {
    let mut queue = FetchQueue::new();
    // TODO: Don't use interval, it can accumulate ticks
    // replace it with delay_until
    let mut interval = time::interval_at(Instant::now(), Duration::from_secs(min_interval as u64));
    tokio::spawn(async move {
        loop {
            select! {
                _ = interval.tick() => {
                    let feeds = db.lock().unwrap().all_feeds();
                    for feed in feeds {
                        let feed_interval =
                            cmp::min(feed.ttl.map(|ttl| ttl * 60).unwrap_or(min_interval), max_interval) as u64;
                        queue.enqueue(feed, Duration::from_secs(feed_interval));
                    }
                }
                feed = queue.next() => {
                    let feed = feed.expect("unreachable");
                    let bot = bot.clone();
                    let db = db.clone();
                    tokio::spawn(async move {
                        if let Err(e) = fetch_and_push_updates(bot, db, feed).await {
                            dbg!(e);
                        }
                    });
                }
            }
        }
    });
}

async fn fetch_and_push_updates(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    feed: Feed,
) -> Result<(), tbot::errors::MethodCall> {
    let new_feed = match pull_feed(&feed.link).await {
        Ok(feed) => feed,
        Err(e) => {
            let down_time = db.lock().unwrap().get_or_update_down_time(&feed.link);
            // 5 days
            if down_time.as_secs() > 5 * 24 * 60 * 60 {
                let msg = format!(
                    "《{}》\
                     已经连续 5 天拉取出错 ({}),\
                     可能已经关闭, 请取消订阅",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&e.to_string())
                );
                push_updates(&bot, &db, feed.subscribers, parameters::Text::html(&msg)).await?;
            }
            return Ok(());
        }
    };

    let updates = db.lock().unwrap().update(&feed.link, new_feed);
    for update in updates {
        match update {
            FeedUpdate::Items(items) => {
                let msgs =
                    format_large_msg(format!("{}", Escape(&feed.title)), &items, |item| {
                        let title = item
                            .title
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.title);
                        let link = item
                            .link
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.link);
                        format!("{}", Escape(link), Escape(title))
                    });
                for msg in msgs {
                    push_updates(
                        &bot,
                        &db,
                        feed.subscribers.iter().copied(),
                        parameters::Text::html(&msg),
                    )
                    .await?;
                }
            }
            FeedUpdate::Title(new_title) => {
                let msg = format!(
                    "{} 已更名为 {}",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&new_title)
                );
                push_updates(
                    &bot,
                    &db,
                    feed.subscribers.iter().copied(),
                    parameters::Text::html(&msg),
                )
                .await?;
            }
        }
    }
    Ok(())
}

async fn push_updates<I: IntoIterator<Item = i64>>(
    bot: &tbot::Bot<Https>,
    db: &Arc<Mutex<Database>>,
    subscribers: I,
    msg: parameters::Text<'_>,
) -> Result<(), tbot::errors::MethodCall> {
    use tbot::errors::MethodCall;
    for mut subscriber in subscribers {
        'retry: for _ in 0..3 {
            match bot
                .send_message(tbot::types::chat::Id(subscriber), msg)
                .call()
                .await
            {
                Err(MethodCall::RequestError { description, .. })
                    if chat_is_unavailable(&description) =>
                {
                    db.lock().unwrap().delete_subscriber(subscriber);
                }
                Err(MethodCall::RequestError {
                    migrate_to_chat_id: Some(new_chat_id),
                    ..
                }) => {
                    db.lock()
                        .unwrap()
                        .update_subscriber(subscriber, new_chat_id.0);
                    subscriber = new_chat_id.0;
                    continue 'retry;
                }
                Err(MethodCall::RequestError {
                    retry_after: Some(delay),
                    ..
                }) => {
                    time::delay_for(Duration::from_secs(delay)).await;
                    continue 'retry;
                }
                other => {
                    other?;
                }
            }
            break 'retry;
        }
    }
    Ok(())
}

pub fn chat_is_unavailable(s: &str) -> bool {
    s.contains("Forbidden") || s.contains("chat not found")
}

#[derive(Default)]
struct FetchQueue {
    feeds: HashMap<String, Feed>,
    notifies: DelayQueue<String>,
    wakeup: Notify,
}

impl FetchQueue {
    fn new() -> Self {
        Self::default()
    }

    fn enqueue(&mut self, feed: Feed, delay: Duration) -> bool {
        let exists = self.feeds.contains_key(&feed.link);
        if !exists {
            self.notifies.insert(feed.link.clone(), delay);
            self.feeds.insert(feed.link.clone(), feed);
            self.wakeup.notify();
        }
        !exists
    }

    async fn next(&mut self) -> Result<Feed, time::Error> {
        loop {
            if let Some(feed_id) = self.notifies.next().await {
                let feed = self.feeds.remove(feed_id?.get_ref()).unwrap();
                break Ok(feed);
            } else {
                self.wakeup.notified().await;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This modules provides an implementation of the Lempel–Ziv–Welch Compression Algorithm

use std::io;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Vacant, Occupied};

use super::bits::BitReader;

const MAX_CODESIZE: u8 = 12;

/// Alias for a LZW code point
type Code = u16;

/// Decoding dictionary
/// It is not generic due to current limitations of Rust
/// Inspired by http://www.cplusplus.com/articles/iL18T05o/
struct DecodingDict {
    min_size: u8,
    table: Vec<(Option<Code>, u8)>,
    buffer: Vec<u8>,
}

impl DecodingDict {
    /// Creates a new dict
    fn new(min_size: u8) -> DecodingDict {
        DecodingDict {
            min_size: min_size,
            table: Vec::with_capacity(512),
            buffer: Vec::with_capacity((1 << MAX_CODESIZE as uint) - 1)
        }
    }

    /// Resets the dictionary
    fn reset(&mut self) {
        self.table.clear();
        for i in range(0, (1u16 << self.min_size as uint)) {
            self.table.push((None, i as u8));
        }
    }

    /// Inserts a value into the dict
    fn push(&mut self, key: Option<Code>, value: u8) {
        self.table.push((key, value))
    }

    /// Reconstructs the data for the corresponding code
    fn reconstruct(&mut self, code: Option<Code>) -> &[u8] {
        self.buffer.clear();
        let mut code = code;
        let mut cha;
        while let Some(k) = code {
            //(code, cha) = self.table[k as uint];
            let entry = self.table[k as uint]; code = entry.0; cha = entry.1;
            self.buffer.push(cha);
        }
        self.buffer.reverse();
        self.buffer.as_slice()
    }

    /// Returns the buffer constructed by the last reconstruction
    fn buffer(&self) -> &[u8] {
        self.buffer.as_slice()
    }

    /// Number of entries in the dictionary
    fn next_code(&self) -> u16 {
        self.table.len() as u16
    }
}

/// LZW decoder
pub struct LZWReader<R: Reader> {
    r: BitReader<R>,
    table: DecodingDict,
    code_size: u8,
    minimal_size: u8,
    clear_code: u16,
    end_code: u16,

}

impl<R: Reader> LZWReader<R> {
    /// Creates a new LZW reader with a minimum code size of `size`
    pub fn new(reader: R, size: u8) -> LZWReader<R> {
        let clear_code = 1 << size as uint;
        let end_code = clear_code + 1;
        LZWReader {
            r: BitReader::new(reader),
            table: DecodingDict::new(size),
            code_size: size + 1,
            minimal_size: size,
            clear_code: clear_code,
            end_code: end_code,
        }
    }

    /// Resets the code table
    fn reset(&mut self) {
        self.table.reset();
        self.table.push(None, 0); // clear code
        self.table.push(None, 0); // end code
        self.code_size = self.minimal_size + 1;
    }

    /// Decodes the data into a `Writer`
    pub fn decode<W: Writer>(&mut self, stream: &mut W) -> io::IoResult<()> {
        let mut prev = None;
        loop {
            let code = try!(self.r.read_bits(self.code_size)) as u16;
            if code == self.clear_code {
                self.reset();
                prev = None;
            } else if code == self.end_code {
                return Ok(())
            } else {
                let next_code = self.table.next_code();
                let data = if code == next_code {
                    let cha = self.table.reconstruct(prev)[0];
                    self.table.push(prev, cha);
                    self.table.reconstruct(Some(code))
                } else if code > next_code {
                    return Err(io::IoError {
                        kind: io::InvalidInput,
                        desc: "Invalid code",
                        detail: None
                    })
                } else {
                    let cha = self.table.reconstruct(Some(code))[0];
                    self.table.push(prev, cha);
                    self.table.buffer()
                };
                try!(stream.write(data));
                if next_code == (1 << self.code_size as uint)
                   && self.code_size < MAX_CODESIZE {
                    self.code_size += 1;
                }
                prev = Some(code);
            }
        }
    }
}<commit_msg>fix some bugs<commit_after>//! This modules provides an implementation of the Lempel–Ziv–Welch Compression Algorithm

use std::io;

use super::bits::BitReader;

const MAX_CODESIZE: u8 = 12;

/// Alias for a LZW code point
type Code = u16;

/// Decoding dictionary
/// It is not generic due to current limitations of Rust
/// Inspired by http://www.cplusplus.com/articles/iL18T05o/
struct DecodingDict {
    min_size: u8,
    table: Vec<(Option<Code>, u8)>,
    buffer: Vec<u8>,
}

impl DecodingDict {
    /// Creates a new dict
    fn new(min_size: u8) -> DecodingDict {
        DecodingDict {
            min_size: min_size,
            table: Vec::with_capacity(512),
            buffer: Vec::with_capacity((1 << MAX_CODESIZE as uint) - 1)
        }
    }

    /// Resets the dictionary
    fn reset(&mut self) {
        self.table.clear();
        for i in range(0, (1u16 << self.min_size as uint)) {
            self.table.push((None, i as u8));
        }
    }

    /// Inserts a value into the dict
    fn push(&mut self, key: Option<Code>, value: u8) {
        self.table.push((key, value))
    }

    /// Reconstructs the data for the corresponding code
    fn reconstruct(&mut self, code: Option<Code>) -> &[u8] {
        self.buffer.clear();
        let mut code = code;
        let mut cha;
        while let Some(k) = code {
            //(code, cha) = self.table[k as uint];
            let entry = self.table[k as uint]; code = entry.0; cha = entry.1;
            self.buffer.push(cha);
        }
        self.buffer.reverse();
        self.buffer.as_slice()
    }

    /// Returns the buffer constructed by the last reconstruction
    fn buffer(&self) -> &[u8] {
        self.buffer.as_slice()
    }

    /// Number of entries in the dictionary
    fn next_code(&self) -> u16 {
        self.table.len() as u16
    }
}

/// LZW decoder
pub struct LZWReader<R: Reader> {
    r: BitReader<R>,
    table: DecodingDict,
    code_size: u8,
    minimal_size: u8,
    clear_code: u16,
    end_code: u16,

}

impl<R: Reader> LZWReader<R> {
    /// Creates a new LZW reader with a minimum code size of `size`
    pub fn new(reader: R, size: u8) -> LZWReader<R> {
        let clear_code = 1 << size as uint;
        let end_code = clear_code + 1;
        LZWReader {
            r: BitReader::new(reader),
            table: DecodingDict::new(size),
            code_size: size + 1,
            minimal_size: size,
            clear_code: clear_code,
            end_code: end_code,
        }
    }

    /// Resets the code table
    fn reset(&mut self) {
        self.table.reset();
        self.table.push(None, 0); // clear code
        self.table.push(None, 0); // end code
        self.code_size = self.minimal_size + 1;
    }

    /// Decodes the data into a `Writer`
    pub fn decode<W: Writer>(&mut self, stream: &mut W) -> io::IoResult<()> {
        let mut prev = None;
        loop {
            let code = try!(self.r.read_bits(self.code_size)) as u16;
            if code == self.clear_code {
                self.reset();
                prev = None;
            } else if code == self.end_code {
                return Ok(())
            } else {
                let next_code = self.table.next_code();
                if prev.is_none() {
                    try!(stream.write_u8(code as u8));
                } else {
                    let data = if code == next_code {
                        let cha = self.table.reconstruct(prev)[0];
                        self.table.push(prev, cha);
                        self.table.reconstruct(Some(code))
                    } else if code > next_code {
                        return Err(io::IoError {
                            kind: io::InvalidInput,
                            desc: "Invalid code",
                            detail: None
                        })
                    } else {
                        let cha = self.table.reconstruct(Some(code))[0];
                        self.table.push(prev, cha);
                        self.table.buffer()
                    };
                    try!(stream.write(data));
                }
                if next_code == (1 << self.code_size as uint) - 1
                   && self.code_size < MAX_CODESIZE {
                    self.code_size += 1;
                }
                prev = Some(code);
            }
        }
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;

macro_rules! blanket_impl {
  ($trait_: ident for $($type_: ty),*) => {
    $(
      impl $trait_ for $type_ {}
    )*
  };
}

macro_rules! impl_graphql_type_for {
    ($tt: ty where name = $name: expr, description = $desc: expr) => {
        impl GraphQLType for $tt {
            fn name(&self) -> &str { $name }
            fn description(&self) -> Option<&str> { Some($desc) }
        }
    };

    ($($type_: ty),*) => {
      $(
        impl GraphQLType for $type_ {
            fn name(&self) -> &str { self.name.as_ref() }

            fn description(&self) -> Option<&str> {
                self.description.as_ref().map(|s| s.as_ref())
            }
        }
      )*
    };
}

pub trait GraphQLType {
  fn name(&self) -> &str;
  fn description(&self) -> Option<&str>;
}
impl_graphql_type_for! { GraphQLEnum }

pub trait GraphQLScalar: GraphQLType {}
blanket_impl! { GraphQLScalar for GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean }

pub struct GraphQLInt;
impl_graphql_type_for! {
    GraphQLInt where
    name = "Int",
    description = "The Int scalar type represents a signed 32‐bit numeric non‐fractional values."
}

pub struct GraphQLFloat;
impl_graphql_type_for! {
    GraphQLFloat where
    name = "Float",
    description = "The Float scalar type represents signed double-precision fractional values as specified by IEEE 754."
}

pub struct GraphQLString;
impl_graphql_type_for! {
    GraphQLString where
    name = "String",
    description = "The String scalar type represents textual data, represented as UTF-8 character sequences."
}

pub struct GraphQLBoolean;
impl_graphql_type_for! {
    GraphQLBoolean where
    name = "Boolean",
    description = "The Boolean scalar type represents true or false."
}

pub struct GraphQLEnum {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnum {
  fn values(&self) -> &HashMap<String, GraphQLEnumValue> {
    &self.values
  }
}

pub struct GraphQLEnumValue {
  value: String,
  description: Option<String>,
  depreciation_reason: Option<String>,
}

impl GraphQLEnumValue {
  pub fn new(value: &str) -> GraphQLEnumValue {
    GraphQLEnumValue {
      value: value.to_owned(),
      description: None,
      depreciation_reason: None,
    }
  }

  pub fn value(&self) -> &str {
    self.value.as_ref()
  }

  pub fn description(&self) -> Option<&str> {
    self.description.as_ref().map(|s| s.as_ref())
  }

  pub fn with_description(mut self, description: &str) -> GraphQLEnumValue {
    self.description = Some(description.to_owned());
    self
  }

  pub fn mark_depreciated(mut self, depreciation_reason: &str) -> GraphQLEnumValue {
    if depreciation_reason.trim().len() == 0 {
      panic!("Deprecation reason for {:?} can't not be empty", self.value);
    }
    self.depreciation_reason = Some(depreciation_reason.to_owned());
    self
  }
}

pub struct GraphQLEnumBuilder {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnumBuilder {
  fn new(name: &str) -> GraphQLEnumBuilder {
    GraphQLEnumBuilder {
      name: name.to_owned(),
      description: None,
      values: HashMap::new(),
    }
  }

  fn with_description(mut self, description: &str) -> GraphQLEnumBuilder {
    self.description = Some(description.to_owned());
    self
  }

  fn value_fn<F>(mut self, name: &str, f: F) -> GraphQLEnumBuilder
    where F: FnOnce(GraphQLEnumValue) -> GraphQLEnumValue
  {
    let v = f(GraphQLEnumValue::new(name));
    self.values.insert(v.value.clone(), v);
    self
  }

  fn value(mut self, name: &str) -> GraphQLEnumBuilder {
    self.values.insert(name.to_owned(), GraphQLEnumValue::new(name));
    self
  }

  fn build(self) -> GraphQLEnum {
    if self.values.len() == 0 {
      panic!("Enum {:?} must has at least one value defined.", self.name);
    }

    GraphQLEnum {
      name: self.name,
      description: self.description,
      values: self.values,
    }
  }
}

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

  #[test]
  fn test_scalar_type() {
    assert_eq!("Int", GraphQLInt.name());
    assert_eq!("Float", GraphQLFloat.name());
    assert_eq!("String", GraphQLString.name());
    assert_eq!("Boolean", GraphQLBoolean.name());
  }

  #[test]
  fn test_enum_type() {
    let rgb = GraphQLEnumBuilder::new("RGB")
                .value("RED")
                .value("GREEN")
                .value("BLUE")
                .build();
    assert_eq!(3, rgb.values().len());

    let days = GraphQLEnumBuilder::new("DAYS")
                 .with_description("Days of the week")
                 .value_fn("SAT", |v| v.with_description("Satarday"))
                 .value_fn("SUN", |v| v.with_description("Sunday"))
                 .value_fn("MON", |v| v.with_description("Monday"))
                 .value_fn("TUE", |v| v.with_description("Tuesday"))
                 .value_fn("WED", |v| v.with_description("Wedsday"))
                 .value_fn("THU", |v| v.with_description("Thusday"))
                 .value_fn("FRI", |v| v.with_description("Friday"))
                 .build();
    assert_eq!("Days of the week", days.description().unwrap_or(""));
    assert_eq!("Monday", days.values()["MON"].description().unwrap_or(""));;
  }
}
<commit_msg>fix typo and trim enum depreciation reason<commit_after>use std::collections::HashMap;

macro_rules! blanket_impl {
  ($trait_: ident for $($type_: ty),*) => {
    $(
      impl $trait_ for $type_ {}
    )*
  };
}

macro_rules! impl_graphql_type_for {
    ($tt: ty where name = $name: expr, description = $desc: expr) => {
        impl GraphQLType for $tt {
            fn name(&self) -> &str { $name }
            fn description(&self) -> Option<&str> { Some($desc) }
        }
    };

    ($($type_: ty),*) => {
      $(
        impl GraphQLType for $type_ {
            fn name(&self) -> &str { self.name.as_ref() }

            fn description(&self) -> Option<&str> {
                self.description.as_ref().map(|s| s.as_ref())
            }
        }
      )*
    };
}

pub trait GraphQLType {
  fn name(&self) -> &str;
  fn description(&self) -> Option<&str>;
}
impl_graphql_type_for! { GraphQLEnum }

pub trait GraphQLScalar: GraphQLType {}
blanket_impl! { GraphQLScalar for GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean }

pub struct GraphQLInt;
impl_graphql_type_for! {
    GraphQLInt where
    name = "Int",
    description = "The Int scalar type represents a signed 32‐bit numeric non‐fractional values."
}

pub struct GraphQLFloat;
impl_graphql_type_for! {
    GraphQLFloat where
    name = "Float",
    description = "The Float scalar type represents signed double-precision fractional values as specified by IEEE 754."
}

pub struct GraphQLString;
impl_graphql_type_for! {
    GraphQLString where
    name = "String",
    description = "The String scalar type represents textual data, represented as UTF-8 character sequences."
}

pub struct GraphQLBoolean;
impl_graphql_type_for! {
    GraphQLBoolean where
    name = "Boolean",
    description = "The Boolean scalar type represents true or false."
}

pub struct GraphQLEnum {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnum {
  fn values(&self) -> &HashMap<String, GraphQLEnumValue> {
    &self.values
  }
}

pub struct GraphQLEnumValue {
  value: String,
  description: Option<String>,
  depreciation_reason: Option<String>,
}

impl GraphQLEnumValue {
  pub fn new(value: &str) -> GraphQLEnumValue {
    GraphQLEnumValue {
      value: value.to_owned(),
      description: None,
      depreciation_reason: None,
    }
  }

  pub fn value(&self) -> &str {
    self.value.as_ref()
  }

  pub fn description(&self) -> Option<&str> {
    self.description.as_ref().map(|s| s.as_ref())
  }

  pub fn with_description(mut self, description: &str) -> GraphQLEnumValue {
    self.description = Some(description.to_owned());
    self
  }

  pub fn mark_depreciated(mut self, depreciation_reason: &str) -> GraphQLEnumValue {
    let reason = depreciation_reason.trim().to_owned();
    if reason.len() == 0 {
      panic!("Deprecation reason for enum value {:?} cannot be empty",
             self.value);
    }
    self.depreciation_reason = Some(reason);
    self
  }
}

pub struct GraphQLEnumBuilder {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnumBuilder {
  fn new(name: &str) -> GraphQLEnumBuilder {
    GraphQLEnumBuilder {
      name: name.to_owned(),
      description: None,
      values: HashMap::new(),
    }
  }

  fn with_description(mut self, description: &str) -> GraphQLEnumBuilder {
    self.description = Some(description.to_owned());
    self
  }

  fn value_fn<F>(mut self, name: &str, f: F) -> GraphQLEnumBuilder
    where F: FnOnce(GraphQLEnumValue) -> GraphQLEnumValue
  {
    let v = f(GraphQLEnumValue::new(name));
    self.values.insert(v.value.clone(), v);
    self
  }

  fn value(mut self, name: &str) -> GraphQLEnumBuilder {
    self.values.insert(name.to_owned(), GraphQLEnumValue::new(name));
    self
  }

  fn build(self) -> GraphQLEnum {
    if self.values.len() == 0 {
      panic!("Enum {:?} must has at least one value defined.", self.name);
    }

    GraphQLEnum {
      name: self.name,
      description: self.description,
      values: self.values,
    }
  }
}

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

  #[test]
  fn test_scalar_type() {
    assert_eq!("Int", GraphQLInt.name());
    assert_eq!("Float", GraphQLFloat.name());
    assert_eq!("String", GraphQLString.name());
    assert_eq!("Boolean", GraphQLBoolean.name());
  }

  #[test]
  fn test_enum_type() {
    let rgb = GraphQLEnumBuilder::new("RGB")
                .value("RED")
                .value("GREEN")
                .value("BLUE")
                .build();
    assert_eq!(3, rgb.values().len());

    let days = GraphQLEnumBuilder::new("DAYS")
                 .with_description("Days of the week")
                 .value_fn("SAT", |v| v.with_description("Satarday"))
                 .value_fn("SUN", |v| v.with_description("Sunday"))
                 .value_fn("MON", |v| v.with_description("Monday"))
                 .value_fn("TUE", |v| v.with_description("Tuesday"))
                 .value_fn("WED", |v| v.with_description("Wedsday"))
                 .value_fn("THU", |v| v.with_description("Thusday"))
                 .value_fn("FRI", |v| v.with_description("Friday"))
                 .build();
    assert_eq!("Days of the week", days.description().unwrap_or(""));
    assert_eq!("Monday", days.values()["MON"].description().unwrap_or(""));;
  }
}
<|endoftext|>


<commit_before>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType, Layout};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container = Container::new_container(geometry, None);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                self.set_active_node(active_ix)
                    .expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix] {
                            Container::View { handle, .. } => {
                                handle.set_output(output_handle);
                            },
                            Container::Container { .. } => {
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }

            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly. Might need to generalize this else where.
    /// For now, just used in workspace switching.
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<commit_msg>Fixed sending tabbed/stacked view to wksp<commit_after>use rustwlc::WlcOutput;
use petgraph::graph::NodeIndex;
use uuid::Uuid;
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType, Layout};
use ::debug_enabled;

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.tree.follow_path_until(self.tree.root_ix(),
                                                      ContainerType::Output)
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let geometry = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output");
        let worksp = Container::new_workspace(name.to_string(), geometry);

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let container = Container::new_container(geometry, None);
        let container_ix = self.tree.add_child(worksp_ix, container, false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        {
            // Update the border colors
            let container = &mut self.tree[active_ix];
            container.clear_border_color()
                .expect("Could not clear old active border color");
            container.draw_borders().expect("Could not draw borders");
        }
        let old_worksp_parent_ix = self.tree.parent_of(old_worksp_ix)
            .expect("Old workspace had no parent");
        let new_worksp_parent_ix = self.tree.parent_of(workspace_ix)
            .expect("New workspace had no parent");
        // Only set the old one to be invisible if new and old share output.
        if new_worksp_parent_ix == old_worksp_parent_ix {
            // Set the old one to invisible
            self.set_container_visibility(old_worksp_ix, false);
        } else {
            // Set all views on the target output to be invisible,
            // to clear the old workspace visibilty out.
            self.set_container_visibility(new_worksp_parent_ix, false);
        }
        // Set the new one to visible
        self.container_visibilty_wrapper(workspace_ix, true);
        // Focus on the new output
        match self.tree[new_worksp_parent_ix] {
            Container::Output { handle, .. } => {
                WlcOutput::focus(Some(handle))
            },
            _ => unreachable!()
        }
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            let siblings = self.tree.children_of(old_worksp_parent_ix);
            // Only remove if it's **NOT** the only workspace on the output.
            // AND if the new workspace is on the same output.
            if siblings.len() > 1 && old_worksp_parent_ix == new_worksp_parent_ix {
                trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                    .expect("Workspace had no name"));
                if let Err(err) = self.remove_workspace(old_worksp_ix) {
                    warn!("Tried to remove empty workspace {:#?}, error: {:?}",
                        old_worksp_ix, err);
                    debug!("{:#?}", self);
                    panic!("Could not remove old workspace");
                }
            }
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { id, ..} => {
                        self.focus_on(id).unwrap_or_else(|_| {
                            warn!("Could not focus on {:?}", id);
                        });
                    },
                    _ => unreachable!()
                }
                self.set_active_node(active_ix)
                    .expect("Could not set new active node");
                self.tree.set_ancestor_paths_active(active_ix);
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree
                    .descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.set_container_visibility(curr_work_ix, false);
            let new_output_ix = self.tree.parent_of(next_work_ix)
                .expect("Target workspace had no parent");
            match self.tree[new_output_ix] {
                Container::Output { handle: output_handle, .. } => {
                    fn set_output_recurse(this: &mut LayoutTree,
                                          node_ix: NodeIndex,
                                          output_handle: WlcOutput) {
                        match this.tree[node_ix] {
                            Container::View { handle, .. } => {
                                handle.set_output(output_handle);
                            },
                            Container::Container { .. } => {
                                for child_ix in this.tree.children_of(node_ix) {
                                    set_output_recurse(this, child_ix, output_handle)
                                }
                            },
                            _ => unreachable!()
                        }
                    }
                    set_output_recurse(self, active_ix, output_handle);
                },
                _ => unreachable!()
            }

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) || !debug_enabled() {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            debug!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // If it's a fullscreen app, then update the fullscreen lists
            self.transfer_fullscreen(curr_work_ix, next_work_ix, id);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    if let Err(err) = self.remove_view_or_container(parent_ix) {
                        error!("{:#?}\nCould not remove {:#?} from tree {:#?}", err, parent_ix, self);
                        panic!("Could not remove empty parent!");
                    }
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }
            self.container_visibilty_wrapper(curr_work_ix, true);
            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
        self.validate_path();
    }

    /// Transfers a fullscreen app from this workspace to another.
    fn transfer_fullscreen(&mut self, cur_work_ix: NodeIndex, next_work_ix: NodeIndex,
                           fullscreen_id: Uuid) {
        if let Some(fullscreen_ids) = self.tree[cur_work_ix].fullscreen_c() {
            if !fullscreen_ids.iter().any(|id| *id == fullscreen_id) {
                return;
            }
        } else {
            return;
        }
        self.tree[cur_work_ix].update_fullscreen_c(fullscreen_id, false)
            .expect("cur_work_ix was not a workspace");
        self.tree[next_work_ix].update_fullscreen_c(fullscreen_id, true)
            .expect("next_work_ix was not a workspace");
    }

    /// Wrapper around `set_container_visibility`, so that tabbed/stacked
    /// is handled correctly. Might need to generalize this else where.
    /// For now, just used in workspace switching.
    fn container_visibilty_wrapper(&mut self, node_ix: NodeIndex, val: bool) {
        let mut set = false;
        match self.tree[node_ix] {
            Container::Container { layout, .. } => {
                match layout {
                    Layout::Tabbed | Layout::Stacked => {
                        if val {
                            set = true;
                        }
                    },
                    _ => {}
                }
            },
            _ => {}
        }
        if !set {
            self.tree[node_ix].set_visibility(val);
            for child in self.tree.children_of(node_ix) {
                self.container_visibilty_wrapper(child, val)
            }
        } else {
            self.tree.next_active_node(node_ix)
                .map(|node| self.container_visibilty_wrapper(node, val));
        }
    }
}

#[cfg(test)]
mod tests {
    use ::layout::core::tree::tests::basic_tree;

    #[test]
    pub fn switch_empty_workspaces() {
        let mut tree = basic_tree();
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("5");
        tree.switch_to_workspace("4");
        tree.switch_to_workspace("2");
    }
}
<|endoftext|>