<commit_before>//! Defines a triangle mesh geometry. Intersection tests are accelerated internally
//! by storing the triangles of the mesh in a BVH

extern crate tobj;

use std::sync::Arc;
use std::path::Path;
use std::collections::HashMap;

use geometry::{Geometry, DifferentialGeometry, Boundable, BBox, BVH};
use linalg::{self, Normal, Vector, Ray, Point};

/// A mesh composed of triangles, specified by directly passing the position,
/// normal and index buffers for the triangles making up the mesh
pub struct Mesh {
    bvh: BVH<Triangle>,
}

impl Mesh {
    /// Create a new Mesh from the triangles described in the buffers passed
    /// This data could come from an OBJ file via [tobj](https://github.com/Twinklebear/tobj)
    /// for example.
    pub fn new(positions: Arc<Vec<Point>>, normals: Arc<Vec<Normal>>, texcoords: Arc<Vec<Point>>,
               indices: Vec<u32>) -> Mesh {
        let triangles = indices.chunks(3).map(|i| {
            Triangle::new(i[0] as usize, i[1] as usize, i[2] as usize, positions.clone(),
                          normals.clone(), texcoords.clone())
            }).collect();
        Mesh { bvh: BVH::new(16, triangles) }
    }
    /// Load all the meshes defined in an OBJ file and return them in a hashmap that maps the
    /// model's name in the file to its loaded mesh
    /// TODO: Currently materials are ignored
    pub fn load_obj(file_name: &Path) -> HashMap<String, Mesh> {
        match tobj::load_obj(file_name) {
            Ok((models, _)) => {
                let mut meshes = HashMap::new();
                for m in models {
                    println!("Loading model {}", m.name);
                    let mesh = m.mesh;
                    if mesh.normals.is_empty() || mesh.texcoords.is_empty() {
                        print!("Mesh::load_obj error! Normals and texture coordinates are required!");
                        println!("Skipping {}", m.name);
                        continue;
                    }
                    println!("Number of triangles {}", mesh.indices.len() / 3);
                    let positions = Arc::new(mesh.positions.chunks(3).map(|i| Point::new(i[0], i[1], i[2]))
                                             .collect());
                    let normals = Arc::new(mesh.normals.chunks(3).map(|i| Normal::new(i[0], i[1], i[2]))
                                           .collect());
                    let texcoords = Arc::new(mesh.texcoords.chunks(2).map(|i| Point::new(i[0], i[1], 0.0))
                                             .collect());
                    meshes.insert(m.name, Mesh::new(positions, normals, texcoords, mesh.indices));
                }
                meshes
            },
            Err(e) => {
                println!("Failed to load {:?} due to {:?}", file_name, e);
                HashMap::new()
            },
        }
    }
}

impl Geometry for Mesh {
    fn intersect(&self, ray: &mut linalg::Ray) -> Option<DifferentialGeometry> {
        self.bvh.intersect(ray, |r, i| i.intersect(r))
    }
}

impl Boundable for Mesh {
    fn bounds(&self) -> BBox {
        self.bvh.bounds()
    }
}

/// A triangle in some mesh. Just stores a reference to the mesh
/// and the indices of each vertex
pub struct Triangle {
    a: usize,
    b: usize,
    c: usize,
    positions: Arc<Vec<Point>>,
    normals: Arc<Vec<Normal>>,
    texcoords: Arc<Vec<Point>>,
}

impl Triangle {
    /// Create a new triangle representing a triangle within the mesh passed
    pub fn new(a: usize, b: usize, c: usize, positions: Arc<Vec<Point>>,
               normals: Arc<Vec<Normal>>, texcoords: Arc<Vec<Point>>) -> Triangle {
        Triangle { a: a, b: b, c: c, positions: positions, normals: normals,
                   texcoords: texcoords }
    }
}

impl Geometry for Triangle {
    fn intersect(&self, ray: &mut Ray) -> Option<DifferentialGeometry> {
        let pa = &self.positions[self.a];
        let pb = &self.positions[self.b];
        let pc = &self.positions[self.c];

        let e = [*pb - *pa, *pc - *pa];
        let mut s = [Vector::broadcast(0.0); 2];
        s[0] = linalg::cross(&ray.d, &e[1]);
        let div = match linalg::dot(&s[0], &e[0]) {
            // 0.0 => degenerate triangle, can't hit
            0.0 => return None,
            d => 1.0 / d,
        };

        let d = ray.o - *pa;
        let mut bary = [0.0; 3];
        bary[0] = linalg::dot(&d, &s[0]) * div;
        // Check that the first barycentric coordinate is in the triangle bounds
        if bary[0] < -1.0e-8 || bary[0] > 1.0 {
            return None;
        }

        s[1] = linalg::cross(&d, &e[0]);
        bary[1] = linalg::dot(&ray.d, &s[1]) * div;
        // Check the second barycentric coordinate is in the triangle bounds
        if bary[1] < -1.0e-8 || bary[0] + bary[1] > 1.0 {
            return None;
        }

        // We've hit the triangle with the ray, now check the hit location is in the ray range
        let t = linalg::dot(&e[1], &s[1]) * div;
        if t < ray.min_t || t > ray.max_t {
            return None;
        }
        bary[2] = 1.0 - bary[0] - bary[1];
        ray.max_t = t;
        let p = ray.at(t);

        // Now compute normal at this location on the triangle
        let na = &self.normals[self.a];
        let nb = &self.normals[self.b];
        let nc = &self.normals[self.c];
        let n = (bary[2] * *na + bary[0] * *nb + bary[1] * *nc).normalized();

        // Compute parameterization of surface and various derivatives for texturing
        // Triangles are parameterized by the obj texcoords at the vertices
        let ta = &self.texcoords[self.a];
        let tb = &self.texcoords[self.b];
        let tc = &self.texcoords[self.c];
        // Triangle points can be found by p_i = p_0 + u_i dp/du + v_i dp/dv
        // we use this property to find the derivatives dp/du and dp/dv
        let du = [ta.x - tc.x, tb.x - tc.x];
        let dv = [ta.y - tc.y, tb.y - tc.y];
        let det = du[0] * dv[1] - dv[0] * du[1];
        //If the texcoords are degenerate pick arbitrary coordinate system
        let (dp_du, dp_dv) =
            if det == 0.0 {
                linalg::coordinate_system(&linalg::cross(&e[1], &e[0]).normalized())
            }
            else {
                let det = 1.0 / det;
                let dp = [*pa - *pc, *pb - *pc];
                let dp_du = (dv[1] * dp[0] - dv[0] * dp[1]) * det;
                let dp_dv = (-du[1] * dp[0] + du[0] * dp[1]) * det;
                (dp_du, dp_dv)
            };
        Some(DifferentialGeometry::new(&p, &n, &dp_du, &dp_dv, self))
    }
}

impl Boundable for Triangle {
    fn bounds(&self) -> BBox {
        BBox::singular(self.positions[self.a])
            .point_union(&self.positions[self.b])
            .point_union(&self.positions[self.c])
    }
}

<commit_msg>Mesh now returns a map of name -> Arc<Mesh> which is easier to use<commit_after>//! Defines a triangle mesh geometry. Intersection tests are accelerated internally
//! by storing the triangles of the mesh in a BVH

extern crate tobj;

use std::sync::Arc;
use std::path::Path;
use std::collections::HashMap;

use geometry::{Geometry, DifferentialGeometry, Boundable, BBox, BVH};
use linalg::{self, Normal, Vector, Ray, Point};

/// A mesh composed of triangles, specified by directly passing the position,
/// normal and index buffers for the triangles making up the mesh
pub struct Mesh {
    bvh: BVH<Triangle>,
}

impl Mesh {
    /// Create a new Mesh from the triangles described in the buffers passed
    /// This data could come from an OBJ file via [tobj](https://github.com/Twinklebear/tobj)
    /// for example.
    pub fn new(positions: Arc<Vec<Point>>, normals: Arc<Vec<Normal>>, texcoords: Arc<Vec<Point>>,
               indices: Vec<u32>) -> Mesh {
        let triangles = indices.chunks(3).map(|i| {
            Triangle::new(i[0] as usize, i[1] as usize, i[2] as usize, positions.clone(),
                          normals.clone(), texcoords.clone())
            }).collect();
        Mesh { bvh: BVH::new(16, triangles) }
    }
    /// Load all the meshes defined in an OBJ file and return them in a hashmap that maps the
    /// model's name in the file to its loaded mesh
    /// TODO: Currently materials are ignored
    pub fn load_obj(file_name: &Path) -> HashMap<String, Arc<Mesh>> {
        match tobj::load_obj(file_name) {
            Ok((models, _)) => {
                let mut meshes = HashMap::new();
                for m in models {
                    println!("Loading model {}", m.name);
                    let mesh = m.mesh;
                    if mesh.normals.is_empty() || mesh.texcoords.is_empty() {
                        print!("Mesh::load_obj error! Normals and texture coordinates are required!");
                        println!("Skipping {}", m.name);
                        continue;
                    }
                    println!("Number of triangles {}", mesh.indices.len() / 3);
                    let positions = Arc::new(mesh.positions.chunks(3).map(|i| Point::new(i[0], i[1], i[2]))
                                             .collect());
                    let normals = Arc::new(mesh.normals.chunks(3).map(|i| Normal::new(i[0], i[1], i[2]))
                                           .collect());
                    let texcoords = Arc::new(mesh.texcoords.chunks(2).map(|i| Point::new(i[0], i[1], 0.0))
                                             .collect());
                    meshes.insert(m.name, Arc::new(Mesh::new(positions, normals, texcoords, mesh.indices)));
                }
                meshes
            },
            Err(e) => {
                println!("Failed to load {:?} due to {:?}", file_name, e);
                HashMap::new()
            },
        }
    }
}

impl Geometry for Mesh {
    fn intersect(&self, ray: &mut linalg::Ray) -> Option<DifferentialGeometry> {
        self.bvh.intersect(ray, |r, i| i.intersect(r))
    }
}

impl Boundable for Mesh {
    fn bounds(&self) -> BBox {
        self.bvh.bounds()
    }
}

/// A triangle in some mesh. Just stores a reference to the mesh
/// and the indices of each vertex
pub struct Triangle {
    a: usize,
    b: usize,
    c: usize,
    positions: Arc<Vec<Point>>,
    normals: Arc<Vec<Normal>>,
    texcoords: Arc<Vec<Point>>,
}

impl Triangle {
    /// Create a new triangle representing a triangle within the mesh passed
    pub fn new(a: usize, b: usize, c: usize, positions: Arc<Vec<Point>>,
               normals: Arc<Vec<Normal>>, texcoords: Arc<Vec<Point>>) -> Triangle {
        Triangle { a: a, b: b, c: c, positions: positions, normals: normals,
                   texcoords: texcoords }
    }
}

impl Geometry for Triangle {
    fn intersect(&self, ray: &mut Ray) -> Option<DifferentialGeometry> {
        let pa = &self.positions[self.a];
        let pb = &self.positions[self.b];
        let pc = &self.positions[self.c];

        let e = [*pb - *pa, *pc - *pa];
        let mut s = [Vector::broadcast(0.0); 2];
        s[0] = linalg::cross(&ray.d, &e[1]);
        let div = match linalg::dot(&s[0], &e[0]) {
            // 0.0 => degenerate triangle, can't hit
            0.0 => return None,
            d => 1.0 / d,
        };

        let d = ray.o - *pa;
        let mut bary = [0.0; 3];
        bary[0] = linalg::dot(&d, &s[0]) * div;
        // Check that the first barycentric coordinate is in the triangle bounds
        if bary[0] < -1.0e-8 || bary[0] > 1.0 {
            return None;
        }

        s[1] = linalg::cross(&d, &e[0]);
        bary[1] = linalg::dot(&ray.d, &s[1]) * div;
        // Check the second barycentric coordinate is in the triangle bounds
        if bary[1] < -1.0e-8 || bary[0] + bary[1] > 1.0 {
            return None;
        }

        // We've hit the triangle with the ray, now check the hit location is in the ray range
        let t = linalg::dot(&e[1], &s[1]) * div;
        if t < ray.min_t || t > ray.max_t {
            return None;
        }
        bary[2] = 1.0 - bary[0] - bary[1];
        ray.max_t = t;
        let p = ray.at(t);

        // Now compute normal at this location on the triangle
        let na = &self.normals[self.a];
        let nb = &self.normals[self.b];
        let nc = &self.normals[self.c];
        let n = (bary[2] * *na + bary[0] * *nb + bary[1] * *nc).normalized();

        // Compute parameterization of surface and various derivatives for texturing
        // Triangles are parameterized by the obj texcoords at the vertices
        let ta = &self.texcoords[self.a];
        let tb = &self.texcoords[self.b];
        let tc = &self.texcoords[self.c];
        // Triangle points can be found by p_i = p_0 + u_i dp/du + v_i dp/dv
        // we use this property to find the derivatives dp/du and dp/dv
        let du = [ta.x - tc.x, tb.x - tc.x];
        let dv = [ta.y - tc.y, tb.y - tc.y];
        let det = du[0] * dv[1] - dv[0] * du[1];
        //If the texcoords are degenerate pick arbitrary coordinate system
        let (dp_du, dp_dv) =
            if det == 0.0 {
                linalg::coordinate_system(&linalg::cross(&e[1], &e[0]).normalized())
            }
            else {
                let det = 1.0 / det;
                let dp = [*pa - *pc, *pb - *pc];
                let dp_du = (dv[1] * dp[0] - dv[0] * dp[1]) * det;
                let dp_dv = (-du[1] * dp[0] + du[0] * dp[1]) * det;
                (dp_du, dp_dv)
            };
        Some(DifferentialGeometry::new(&p, &n, &dp_du, &dp_dv, self))
    }
}

impl Boundable for Triangle {
    fn bounds(&self) -> BBox {
        BBox::singular(self.positions[self.a])
            .point_union(&self.positions[self.b])
            .point_union(&self.positions[self.c])
    }
}

<|endoftext|>


<commit_before>/**
   A somewhat reduced test case to expose some Valgrind issues.

   This originally came from the word-count benchmark.
*/

use std;

import std::io;
import option = std::option::t;
import std::option::some;
import std::option::none;
import std::str;
import std::vec;
import std::map;

fn map(str filename, map_reduce::putter emit) {
    emit(filename, "1");
}

mod map_reduce {
    export putter;
    export mapper;
    export map_reduce;

    type putter = fn(str, str) -> ();

    type mapper = fn(str, putter);

    tag ctrl_proto {
        find_reducer(str, chan[int]);
        mapper_done;
    }

    fn start_mappers(chan[ctrl_proto] ctrl,
                     vec[str] inputs) {
        for(str i in inputs) {
            spawn map_task(ctrl, i);
        }
    }

    fn map_task(chan[ctrl_proto] ctrl,
                str input) {

        auto intermediates = map::new_str_hash();

        fn emit(&map::hashmap[str, int] im,
                chan[ctrl_proto] ctrl,
                str key, str val) {
            auto c;
            alt(im.find(key)) {
                case(some(?_c)) {
                    c = _c
                }
                case(none) {
                    auto p = port();
                    log_err "sending find_reducer";
                    ctrl <| find_reducer(key, chan(p));
                    log_err "receiving";
                    p |> c;
                    log_err c;
                    im.insert(key, c);
                }
            }
        }

        map(input, bind emit(intermediates, ctrl, _, _));
        ctrl <| mapper_done;
    }

    fn map_reduce (vec[str] inputs) {
        auto ctrl = port[ctrl_proto]();

        // This task becomes the master control task. It spawns others
        // to do the rest.

        let map::hashmap[str, int] reducers;

        reducers = map::new_str_hash();

        start_mappers(chan(ctrl), inputs);

        auto num_mappers = vec::len(inputs) as int;

        while(num_mappers > 0) {
            auto m;
            ctrl |> m;

            alt(m) {
                case(mapper_done) { num_mappers -= 1; }
                case(find_reducer(?k, ?cc)) {
                    auto c;
                    alt(reducers.find(k)) {
                        case(some(?_c)) { c = _c; }
                        case(none) {
                            c = 0;
                        }
                    }
                    cc <| c;
                }
            }
        }
    }
}

fn main(vec[str] argv) {
    map_reduce::map_reduce(["../src/test/run-pass/hashmap-memory.rs"]);
}
<commit_msg>Attempt to put out burning Windows tinderbox.<commit_after>/**
   A somewhat reduced test case to expose some Valgrind issues.

   This originally came from the word-count benchmark.
*/

use std;

import std::io;
import option = std::option::t;
import std::option::some;
import std::option::none;
import std::str;
import std::vec;
import std::map;

fn map(str filename, map_reduce::putter emit) {
    emit(filename, "1");
}

mod map_reduce {
    export putter;
    export mapper;
    export map_reduce;

    type putter = fn(str, str) -> ();

    type mapper = fn(str, putter);

    tag ctrl_proto {
        find_reducer(str, chan[int]);
        mapper_done;
    }

    fn start_mappers(chan[ctrl_proto] ctrl,
                     vec[str] inputs) {
        for(str i in inputs) {
            spawn map_task(ctrl, i);
        }
    }

    fn map_task(chan[ctrl_proto] ctrl,
                str input) {

        auto intermediates = map::new_str_hash();

        fn emit(&map::hashmap[str, int] im,
                chan[ctrl_proto] ctrl,
                str key, str val) {
            auto c;
            alt(im.find(key)) {
                case(some(?_c)) {
                    c = _c
                }
                case(none) {
                    auto p = port();
                    log_err "sending find_reducer";
                    ctrl <| find_reducer(key, chan(p));
                    log_err "receiving";
                    p |> c;
                    log_err c;
                    im.insert(key, c);
                }
            }
        }

        map(input, bind emit(intermediates, ctrl, _, _));
        ctrl <| mapper_done;
    }

    fn map_reduce (vec[str] inputs) {
        auto ctrl = port[ctrl_proto]();

        // This task becomes the master control task. It spawns others
        // to do the rest.

        let map::hashmap[str, int] reducers;

        reducers = map::new_str_hash();

        start_mappers(chan(ctrl), inputs);

        auto num_mappers = vec::len(inputs) as int;

        while(num_mappers > 0) {
            auto m;
            ctrl |> m;

            alt(m) {
                case(mapper_done) { num_mappers -= 1; }
                case(find_reducer(?k, ?cc)) {
                    auto c;
                    alt(reducers.find(k)) {
                        case(some(?_c)) { c = _c; }
                        case(none) {
                            c = 0;
                        }
                    }
                    cc <| c;
                }
            }
        }
    }
}

fn main() {
    map_reduce::map_reduce(["../src/test/run-pass/hashmap-memory.rs"]);
}
<|endoftext|>


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

//! Specified color values.

use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError};
#[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor;
use itoa;
use parser::{ParserContext, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::color::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseError};
use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue};

/// Specified color value
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Color {
    /// The 'currentColor' keyword
    CurrentColor,
    /// A specific RGBA color
    Numeric {
        /// Parsed RGBA color
        parsed: RGBA,
        /// Authored representation
        authored: Option<Box<str>>,
    },
    /// A complex color value from computed value
    Complex(ComputedColor),

    /// A system color
    #[cfg(feature = "gecko")]
    System(SystemColor),
    /// A special color keyword value used in Gecko
    #[cfg(feature = "gecko")]
    Special(gecko::SpecialColorKeyword),
    /// Quirksmode-only rule for inheriting color from the body
    #[cfg(feature = "gecko")]
    InheritFromBodyQuirk,
}

no_viewport_percentage!(Color);

#[cfg(feature = "gecko")]
mod gecko {
    use style_traits::ToCss;

    define_css_keyword_enum! { SpecialColorKeyword:
        "-moz-default-color" => MozDefaultColor,
        "-moz-default-background-color" => MozDefaultBackgroundColor,
        "-moz-hyperlinktext" => MozHyperlinktext,
        "-moz-activehyperlinktext" => MozActiveHyperlinktext,
        "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
    }
}

impl From<RGBA> for Color {
    fn from(value: RGBA) -> Self {
        Color::rgba(value)
    }
}

impl Parse for Color {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Currently we only store authored value for color keywords,
        // because all browsers serialize those values as keywords for
        // specified value.
        let start_position = input.position();
        let authored = match input.next() {
            Ok(Token::Ident(s)) => Some(s.to_lowercase().into_boxed_str()),
            _ => None,
        };
        input.reset(start_position);
        if let Ok(value) = input.try(CSSParserColor::parse) {
            Ok(match value {
                CSSParserColor::CurrentColor => Color::CurrentColor,
                CSSParserColor::RGBA(rgba) => Color::Numeric {
                    parsed: rgba,
                    authored: authored,
                },
            })
        } else {
            #[cfg(feature = "gecko")] {
                if let Ok(system) = input.try(SystemColor::parse) {
                    Ok(Color::System(system))
                } else {
                    gecko::SpecialColorKeyword::parse(input).map(Color::Special)
                }
            }
            #[cfg(not(feature = "gecko"))] {
                Err(StyleParseError::UnspecifiedError.into())
            }
        }
    }
}

impl ToCss for Color {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
            Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
            Color::Complex(_) => Ok(()),
            #[cfg(feature = "gecko")]
            Color::System(system) => system.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::Special(special) => special.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => Ok(()),
        }
    }
}

/// A wrapper of cssparser::Color::parse_hash.
///
/// That function should never return CurrentColor, so it makes no sense
/// to handle a cssparser::Color here. This should really be done in
/// cssparser directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
    CSSParserColor::parse_hash(value).map(|color| {
        match color {
            CSSParserColor::RGBA(rgba) => rgba,
            CSSParserColor::CurrentColor =>
                unreachable!("parse_hash should never return currentcolor"),
        }
    })
}

impl Color {
    /// Returns currentcolor value.
    #[inline]
    pub fn currentcolor() -> Color {
        Color::CurrentColor
    }

    /// Returns transparent value.
    #[inline]
    pub fn transparent() -> Color {
        // We should probably set authored to "transparent", but maybe it doesn't matter.
        Color::rgba(RGBA::transparent())
    }

    /// Returns a numeric RGBA color value.
    #[inline]
    pub fn rgba(rgba: RGBA) -> Self {
        Color::Numeric {
            parsed: rgba,
            authored: None,
        }
    }

    /// Parse a color, with quirks.
    ///
    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
    pub fn parse_quirky<'i, 't>(context: &ParserContext,
                                input: &mut Parser<'i, 't>,
                                allow_quirks: AllowQuirks)
                                -> Result<Self, ParseError<'i>> {
        input.try(|i| Self::parse(context, i)).or_else(|_| {
            if !allow_quirks.allowed(context.quirks_mode) {
                return Err(StyleParseError::UnspecifiedError.into());
            }
            Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
        })
    }

    /// Parse a <quirky-color> value.
    ///
    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
    fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
        let (value, unit) = match input.next()? {
            Token::Number { int_value: Some(integer), .. } => {
                (integer, None)
            },
            Token::Dimension { int_value: Some(integer), unit, .. } => {
                (integer, Some(unit))
            },
            Token::Ident(ident) => {
                if ident.len() != 3 && ident.len() != 6 {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                return parse_hash_color(ident.as_bytes())
                    .map_err(|()| StyleParseError::UnspecifiedError.into());
            }
            t => {
                return Err(BasicParseError::UnexpectedToken(t).into());
            },
        };
        if value < 0 {
            return Err(StyleParseError::UnspecifiedError.into());
        }
        let length = if value <= 9 {
            1
        } else if value <= 99 {
            2
        } else if value <= 999 {
            3
        } else if value <= 9999 {
            4
        } else if value <= 99999 {
            5
        } else if value <= 999999 {
            6
        } else {
            return Err(StyleParseError::UnspecifiedError.into())
        };
        let total = length + unit.as_ref().map_or(0, |d| d.len());
        if total > 6 {
            return Err(StyleParseError::UnspecifiedError.into());
        }
        let mut serialization = [b'0'; 6];
        let space_padding = 6 - total;
        let mut written = space_padding;
        written += itoa::write(&mut serialization[written..], value).unwrap();
        if let Some(unit) = unit {
            written += (&mut serialization[written..]).write(unit.as_bytes()).unwrap();
        }
        debug_assert!(written == 6);
        parse_hash_color(&serialization).map_err(|()| StyleParseError::UnspecifiedError.into())
    }

    /// Returns false if the color is completely transparent, and
    /// true otherwise.
    pub fn is_non_transparent(&self) -> bool {
        match *self {
            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
            _ => true,
        }
    }
}

#[cfg(feature = "gecko")]
fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
    use gecko::values::convert_nscolor_to_rgba;
    ComputedColor::rgba(convert_nscolor_to_rgba(color))
}

impl ToComputedValue for Color {
    type ComputedValue = ComputedColor;

    fn to_computed_value(&self, _context: &Context) -> ComputedColor {
        match *self {
            Color::CurrentColor => ComputedColor::currentcolor(),
            Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
            Color::Complex(ref complex) => *complex,
            #[cfg(feature = "gecko")]
            Color::System(system) =>
                convert_nscolor_to_computedcolor(system.to_computed_value(_context)),
            #[cfg(feature = "gecko")]
            Color::Special(special) => {
                use self::gecko::SpecialColorKeyword as Keyword;
                let pres_context = _context.device().pres_context();
                convert_nscolor_to_computedcolor(match special {
                    Keyword::MozDefaultColor => pres_context.mDefaultColor,
                    Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
                    Keyword::MozHyperlinktext => pres_context.mLinkColor,
                    Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
                    Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
                })
            }
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => {
                use dom::TElement;
                use gecko::wrapper::GeckoElement;
                use gecko_bindings::bindings::Gecko_GetBody;
                let pres_context = _context.device().pres_context();
                let body = unsafe {
                    Gecko_GetBody(pres_context)
                };
                if let Some(body) = body {
                    let wrap = GeckoElement(body);
                    let borrow = wrap.borrow_data();
                    ComputedColor::rgba(borrow.as_ref().unwrap()
                                              .styles.primary()
                                              .get_color()
                                              .clone_color())
                } else {
                    convert_nscolor_to_computedcolor(pres_context.mDefaultColor)
                }
            },
        }
    }

    fn from_computed_value(computed: &ComputedColor) -> Self {
        if computed.is_numeric() {
            Color::rgba(computed.color)
        } else if computed.is_currentcolor() {
            Color::currentcolor()
        } else {
            Color::Complex(*computed)
        }
    }
}

/// Specified color value, but resolved to just RGBA for computed value
/// with value from color property at the same context.
#[derive(Clone, Debug, PartialEq, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct RGBAColor(pub Color);

no_viewport_percentage!(RGBAColor);

impl Parse for RGBAColor {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse(context, input).map(RGBAColor)
    }
}

impl ToComputedValue for RGBAColor {
    type ComputedValue = RGBA;

    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.style().get_color().clone_color())
    }

    fn from_computed_value(computed: &RGBA) -> Self {
        RGBAColor(Color::rgba(*computed))
    }
}

impl From<Color> for RGBAColor {
    fn from(color: Color) -> RGBAColor {
        RGBAColor(color)
    }
}
<commit_msg>Don't panic when body element don't have style data.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Specified color values.

use cssparser::{Color as CSSParserColor, Parser, RGBA, Token, BasicParseError};
#[cfg(feature = "gecko")]
use gecko_bindings::structs::nscolor;
use itoa;
use parser::{ParserContext, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::color::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::{ToCss, ParseError, StyleParseError};
use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue};

/// Specified color value
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Color {
    /// The 'currentColor' keyword
    CurrentColor,
    /// A specific RGBA color
    Numeric {
        /// Parsed RGBA color
        parsed: RGBA,
        /// Authored representation
        authored: Option<Box<str>>,
    },
    /// A complex color value from computed value
    Complex(ComputedColor),

    /// A system color
    #[cfg(feature = "gecko")]
    System(SystemColor),
    /// A special color keyword value used in Gecko
    #[cfg(feature = "gecko")]
    Special(gecko::SpecialColorKeyword),
    /// Quirksmode-only rule for inheriting color from the body
    #[cfg(feature = "gecko")]
    InheritFromBodyQuirk,
}

no_viewport_percentage!(Color);

#[cfg(feature = "gecko")]
mod gecko {
    use style_traits::ToCss;

    define_css_keyword_enum! { SpecialColorKeyword:
        "-moz-default-color" => MozDefaultColor,
        "-moz-default-background-color" => MozDefaultBackgroundColor,
        "-moz-hyperlinktext" => MozHyperlinktext,
        "-moz-activehyperlinktext" => MozActiveHyperlinktext,
        "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
    }
}

impl From<RGBA> for Color {
    fn from(value: RGBA) -> Self {
        Color::rgba(value)
    }
}

impl Parse for Color {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        // Currently we only store authored value for color keywords,
        // because all browsers serialize those values as keywords for
        // specified value.
        let start_position = input.position();
        let authored = match input.next() {
            Ok(Token::Ident(s)) => Some(s.to_lowercase().into_boxed_str()),
            _ => None,
        };
        input.reset(start_position);
        if let Ok(value) = input.try(CSSParserColor::parse) {
            Ok(match value {
                CSSParserColor::CurrentColor => Color::CurrentColor,
                CSSParserColor::RGBA(rgba) => Color::Numeric {
                    parsed: rgba,
                    authored: authored,
                },
            })
        } else {
            #[cfg(feature = "gecko")] {
                if let Ok(system) = input.try(SystemColor::parse) {
                    Ok(Color::System(system))
                } else {
                    gecko::SpecialColorKeyword::parse(input).map(Color::Special)
                }
            }
            #[cfg(not(feature = "gecko"))] {
                Err(StyleParseError::UnspecifiedError.into())
            }
        }
    }
}

impl ToCss for Color {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
            Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
            Color::Complex(_) => Ok(()),
            #[cfg(feature = "gecko")]
            Color::System(system) => system.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::Special(special) => special.to_css(dest),
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => Ok(()),
        }
    }
}

/// A wrapper of cssparser::Color::parse_hash.
///
/// That function should never return CurrentColor, so it makes no sense
/// to handle a cssparser::Color here. This should really be done in
/// cssparser directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
    CSSParserColor::parse_hash(value).map(|color| {
        match color {
            CSSParserColor::RGBA(rgba) => rgba,
            CSSParserColor::CurrentColor =>
                unreachable!("parse_hash should never return currentcolor"),
        }
    })
}

impl Color {
    /// Returns currentcolor value.
    #[inline]
    pub fn currentcolor() -> Color {
        Color::CurrentColor
    }

    /// Returns transparent value.
    #[inline]
    pub fn transparent() -> Color {
        // We should probably set authored to "transparent", but maybe it doesn't matter.
        Color::rgba(RGBA::transparent())
    }

    /// Returns a numeric RGBA color value.
    #[inline]
    pub fn rgba(rgba: RGBA) -> Self {
        Color::Numeric {
            parsed: rgba,
            authored: None,
        }
    }

    /// Parse a color, with quirks.
    ///
    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
    pub fn parse_quirky<'i, 't>(context: &ParserContext,
                                input: &mut Parser<'i, 't>,
                                allow_quirks: AllowQuirks)
                                -> Result<Self, ParseError<'i>> {
        input.try(|i| Self::parse(context, i)).or_else(|_| {
            if !allow_quirks.allowed(context.quirks_mode) {
                return Err(StyleParseError::UnspecifiedError.into());
            }
            Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
        })
    }

    /// Parse a <quirky-color> value.
    ///
    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
    fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
        let (value, unit) = match input.next()? {
            Token::Number { int_value: Some(integer), .. } => {
                (integer, None)
            },
            Token::Dimension { int_value: Some(integer), unit, .. } => {
                (integer, Some(unit))
            },
            Token::Ident(ident) => {
                if ident.len() != 3 && ident.len() != 6 {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                return parse_hash_color(ident.as_bytes())
                    .map_err(|()| StyleParseError::UnspecifiedError.into());
            }
            t => {
                return Err(BasicParseError::UnexpectedToken(t).into());
            },
        };
        if value < 0 {
            return Err(StyleParseError::UnspecifiedError.into());
        }
        let length = if value <= 9 {
            1
        } else if value <= 99 {
            2
        } else if value <= 999 {
            3
        } else if value <= 9999 {
            4
        } else if value <= 99999 {
            5
        } else if value <= 999999 {
            6
        } else {
            return Err(StyleParseError::UnspecifiedError.into())
        };
        let total = length + unit.as_ref().map_or(0, |d| d.len());
        if total > 6 {
            return Err(StyleParseError::UnspecifiedError.into());
        }
        let mut serialization = [b'0'; 6];
        let space_padding = 6 - total;
        let mut written = space_padding;
        written += itoa::write(&mut serialization[written..], value).unwrap();
        if let Some(unit) = unit {
            written += (&mut serialization[written..]).write(unit.as_bytes()).unwrap();
        }
        debug_assert!(written == 6);
        parse_hash_color(&serialization).map_err(|()| StyleParseError::UnspecifiedError.into())
    }

    /// Returns false if the color is completely transparent, and
    /// true otherwise.
    pub fn is_non_transparent(&self) -> bool {
        match *self {
            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
            _ => true,
        }
    }
}

#[cfg(feature = "gecko")]
fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
    use gecko::values::convert_nscolor_to_rgba;
    ComputedColor::rgba(convert_nscolor_to_rgba(color))
}

impl ToComputedValue for Color {
    type ComputedValue = ComputedColor;

    fn to_computed_value(&self, _context: &Context) -> ComputedColor {
        match *self {
            Color::CurrentColor => ComputedColor::currentcolor(),
            Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
            Color::Complex(ref complex) => *complex,
            #[cfg(feature = "gecko")]
            Color::System(system) =>
                convert_nscolor_to_computedcolor(system.to_computed_value(_context)),
            #[cfg(feature = "gecko")]
            Color::Special(special) => {
                use self::gecko::SpecialColorKeyword as Keyword;
                let pres_context = _context.device().pres_context();
                convert_nscolor_to_computedcolor(match special {
                    Keyword::MozDefaultColor => pres_context.mDefaultColor,
                    Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
                    Keyword::MozHyperlinktext => pres_context.mLinkColor,
                    Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
                    Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
                })
            }
            #[cfg(feature = "gecko")]
            Color::InheritFromBodyQuirk => {
                use dom::TElement;
                use gecko::wrapper::GeckoElement;
                use gecko_bindings::bindings::Gecko_GetBody;
                let pres_context = _context.device().pres_context();
                let body = unsafe { Gecko_GetBody(pres_context) }.map(GeckoElement);
                let data = body.as_ref().and_then(|wrap| wrap.borrow_data());
                if let Some(data) = data {
                    ComputedColor::rgba(data.styles.primary()
                                            .get_color()
                                            .clone_color())
                } else {
                    convert_nscolor_to_computedcolor(pres_context.mDefaultColor)
                }
            },
        }
    }

    fn from_computed_value(computed: &ComputedColor) -> Self {
        if computed.is_numeric() {
            Color::rgba(computed.color)
        } else if computed.is_currentcolor() {
            Color::currentcolor()
        } else {
            Color::Complex(*computed)
        }
    }
}

/// Specified color value, but resolved to just RGBA for computed value
/// with value from color property at the same context.
#[derive(Clone, Debug, PartialEq, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct RGBAColor(pub Color);

no_viewport_percentage!(RGBAColor);

impl Parse for RGBAColor {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        Color::parse(context, input).map(RGBAColor)
    }
}

impl ToComputedValue for RGBAColor {
    type ComputedValue = RGBA;

    fn to_computed_value(&self, context: &Context) -> RGBA {
        self.0.to_computed_value(context)
            .to_rgba(context.style().get_color().clone_color())
    }

    fn from_computed_value(computed: &RGBA) -> Self {
        RGBAColor(Color::rgba(*computed))
    }
}

impl From<Color> for RGBAColor {
    fn from(color: Color) -> RGBAColor {
        RGBAColor(color)
    }
}
<|endoftext|>


<commit_before>pub type clock_t = i64;
pub type suseconds_t = i64;
pub type dev_t = i32;
pub type sigset_t = ::c_uint;
pub type blksize_t = ::int32_t;
pub type fsblkcnt_t = ::uint64_t;
pub type fsfilcnt_t = ::uint64_t;
pub type pthread_attr_t = *mut ::c_void;
pub type pthread_mutex_t = *mut ::c_void;
pub type pthread_mutexattr_t = *mut ::c_void;
pub type pthread_cond_t = *mut ::c_void;
pub type pthread_rwlock_t = *mut ::c_void;

s! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_namelen: u8,
        __d_padding: [u8; 4],
        pub d_name: [::c_char; 256],
    }

    pub struct glob_t {
        pub gl_pathc:   ::c_int,
        __unused1:      ::c_int,
        pub gl_offs:    ::c_int,
        __unused2:      ::c_int,
        pub gl_pathv:   *mut *mut ::c_char,

        __unused3: *mut ::c_void,

        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
        __unused6: *mut ::c_void,
        __unused7: *mut ::c_void,
        __unused8: *mut ::c_void,
        __unused9: *mut ::c_void,
    }

    pub struct stat {
        pub st_mode: ::mode_t,
        pub st_dev: ::dev_t,
        pub st_ino: ::ino_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::dev_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        pub st_size: ::off_t,
        pub st_blocks: ::blkcnt_t,
        pub st_blksize: ::blksize_t,
        pub st_flags: ::uint32_t,
        pub st_gen: ::uint32_t,
        pub st_birthtime: ::time_t,
        pub st_birthtime_nsec: ::c_long,
    }

    pub struct statvfs {
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_favail: ::fsfilcnt_t,
        pub f_fsid: ::c_ulong,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
    }

    pub struct addrinfo {
        pub ai_flags: ::c_int,
        pub ai_family: ::c_int,
        pub ai_socktype: ::c_int,
        pub ai_protocol: ::c_int,
        pub ai_addrlen: ::socklen_t,
        pub ai_addr: *mut ::sockaddr,
        pub ai_canonname: *mut ::c_char,
        pub ai_next: *mut ::addrinfo,
    }

    pub struct sockaddr_storage {
        pub ss_len: u8,
        pub ss_family: ::sa_family_t,
        __ss_pad1: [u8; 6],
        __ss_pad2: i64,
        __ss_pad3: [u8; 240],
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_code: ::c_int,
        pub si_errno: ::c_int,
        pub si_addr: *mut ::c_char,
        __pad: [u8; 108],
    }

    pub struct Dl_info {
        pub dli_fname: *const ::c_char,
        pub dli_fbase: *mut ::c_void,
        pub dli_sname: *const ::c_char,
        pub dli_saddr: *mut ::c_void,
    }
}

pub const O_CLOEXEC: ::c_int = 0x10000;

pub const MS_SYNC : ::c_int = 0x0002;
pub const MS_INVALIDATE : ::c_int = 0x0004;

pub const PTHREAD_STACK_MIN : ::size_t = 2048;

pub const ENOATTR : ::c_int = 83;
pub const EILSEQ : ::c_int = 84;
pub const EOVERFLOW : ::c_int = 87;
pub const ECANCELED : ::c_int = 88;
pub const EIDRM : ::c_int = 89;
pub const ENOMSG : ::c_int = 90;
pub const ENOTSUP : ::c_int = 91;
pub const ELAST : ::c_int = 91;

pub const F_DUPFD_CLOEXEC : ::c_int = 10;

pub const RLIM_NLIMITS: ::c_int = 9;

pub const SO_SNDTIMEO: ::c_int = 0x1005;
pub const SO_RCVTIMEO: ::c_int = 0x1006;

pub const KERN_PROC : ::c_int = 66;
pub const O_DSYNC : ::c_int = 128;

pub const MAP_RENAME : ::c_int = 0x0000;
pub const MAP_NORESERVE : ::c_int = 0x0000;
pub const MAP_HASSEMAPHORE : ::c_int = 0x0000;

pub const EIPSEC : ::c_int = 82;
pub const ENOMEDIUM : ::c_int = 85;
pub const EMEDIUMTYPE : ::c_int = 86;

pub const RUSAGE_THREAD: ::c_int = 1;

pub const MAP_COPY : ::c_int = 0x0002;
pub const MAP_NOEXTEND : ::c_int = 0x0000;

pub const _SC_CLK_TCK : ::c_int = 3;
pub const _SC_IOV_MAX : ::c_int = 51;
pub const _SC_GETGR_R_SIZE_MAX : ::c_int = 100;
pub const _SC_GETPW_R_SIZE_MAX : ::c_int = 101;
pub const _SC_LOGIN_NAME_MAX : ::c_int = 102;
pub const _SC_MQ_PRIO_MAX : ::c_int = 59;
pub const _SC_THREADS : ::c_int = 91;
pub const _SC_THREAD_ATTR_STACKADDR : ::c_int = 77;
pub const _SC_THREAD_ATTR_STACKSIZE : ::c_int = 78;
pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : ::c_int = 80;
pub const _SC_THREAD_KEYS_MAX : ::c_int = 81;
pub const _SC_THREAD_PRIO_INHERIT : ::c_int = 82;
pub const _SC_THREAD_PRIO_PROTECT : ::c_int = 83;
pub const _SC_THREAD_PRIORITY_SCHEDULING : ::c_int = 84;
pub const _SC_THREAD_PROCESS_SHARED : ::c_int = 85;
pub const _SC_THREAD_SAFE_FUNCTIONS : ::c_int = 103;
pub const _SC_THREAD_STACK_MIN : ::c_int = 89;
pub const _SC_THREAD_THREADS_MAX : ::c_int = 90;
pub const _SC_TTY_NAME_MAX : ::c_int = 107;
pub const _SC_ATEXIT_MAX : ::c_int = 46;
pub const _SC_AIO_LISTIO_MAX : ::c_int = 42;
pub const _SC_AIO_MAX : ::c_int = 43;
pub const _SC_ASYNCHRONOUS_IO : ::c_int = 45;
pub const _SC_MAPPED_FILES : ::c_int = 53;
pub const _SC_MEMLOCK : ::c_int = 54;
pub const _SC_MEMLOCK_RANGE : ::c_int = 55;
pub const _SC_MEMORY_PROTECTION : ::c_int = 56;
pub const _SC_MESSAGE_PASSING : ::c_int = 57;
pub const _SC_MQ_OPEN_MAX : ::c_int = 58;
pub const _SC_PRIORITY_SCHEDULING : ::c_int = 61;
pub const _SC_SEMAPHORES : ::c_int = 67;
pub const _SC_SHARED_MEMORY_OBJECTS : ::c_int = 68;
pub const _SC_SYNCHRONIZED_IO : ::c_int = 75;
pub const _SC_TIMERS : ::c_int = 94;
pub const _SC_XOPEN_CRYPT : ::c_int = 117;
pub const _SC_XOPEN_ENH_I18N : ::c_int = 118;
pub const _SC_XOPEN_LEGACY : ::c_int = 119;
pub const _SC_XOPEN_REALTIME : ::c_int = 120;
pub const _SC_XOPEN_REALTIME_THREADS : ::c_int = 121;
pub const _SC_XOPEN_UNIX : ::c_int = 123;
pub const _SC_XOPEN_VERSION : ::c_int = 125;
pub const _SC_SEM_NSEMS_MAX : ::c_int = 31;
pub const _SC_SEM_VALUE_MAX : ::c_int = 32;
pub const _SC_AIO_PRIO_DELTA_MAX : ::c_int = 44;
pub const _SC_DELAYTIMER_MAX : ::c_int = 50;
pub const _SC_PRIORITIZED_IO : ::c_int = 60;
pub const _SC_REALTIME_SIGNALS : ::c_int = 64;
pub const _SC_RTSIG_MAX : ::c_int = 66;
pub const _SC_SIGQUEUE_MAX : ::c_int = 70;
pub const _SC_TIMER_MAX : ::c_int = 93;

pub const SIGSTKSZ: ::size_t = 40960;

pub const FD_SETSIZE: usize = 1024;

pub const ST_NOSUID: ::c_ulong = 2;

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _;
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _;
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _;
pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2;

pub const KERN_PROC_ARGS: ::c_int = 55;

pub const TMP_MAX : ::c_uint = 0x7fffffff;

pub const NI_MAXHOST: ::size_t = 256;

// syscall numbers
pub const SYS_getentropy: ::c_int = 7;

extern {
    pub fn getnameinfo(sa: *const ::sockaddr,
                       salen: ::socklen_t,
                       host: *mut ::c_char,
                       hostlen: ::size_t,
                       serv: *mut ::c_char,
                       servlen: ::size_t,
                       flags: ::c_int) -> ::c_int;
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int)
                    -> ::c_int;
    pub fn sysctl(name: *const ::c_int,
                  namelen: ::c_uint,
                  oldp: *mut ::c_void,
                  oldlenp: *mut ::size_t,
                  newp: *mut ::c_void,
                  newlen: ::size_t)
                  -> ::c_int;
}
<commit_msg>provide getentropy(2) instead of SYS_entropy<commit_after>pub type clock_t = i64;
pub type suseconds_t = i64;
pub type dev_t = i32;
pub type sigset_t = ::c_uint;
pub type blksize_t = ::int32_t;
pub type fsblkcnt_t = ::uint64_t;
pub type fsfilcnt_t = ::uint64_t;
pub type pthread_attr_t = *mut ::c_void;
pub type pthread_mutex_t = *mut ::c_void;
pub type pthread_mutexattr_t = *mut ::c_void;
pub type pthread_cond_t = *mut ::c_void;
pub type pthread_rwlock_t = *mut ::c_void;

s! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_namelen: u8,
        __d_padding: [u8; 4],
        pub d_name: [::c_char; 256],
    }

    pub struct glob_t {
        pub gl_pathc:   ::c_int,
        __unused1:      ::c_int,
        pub gl_offs:    ::c_int,
        __unused2:      ::c_int,
        pub gl_pathv:   *mut *mut ::c_char,

        __unused3: *mut ::c_void,

        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
        __unused6: *mut ::c_void,
        __unused7: *mut ::c_void,
        __unused8: *mut ::c_void,
        __unused9: *mut ::c_void,
    }

    pub struct stat {
        pub st_mode: ::mode_t,
        pub st_dev: ::dev_t,
        pub st_ino: ::ino_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::dev_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        pub st_size: ::off_t,
        pub st_blocks: ::blkcnt_t,
        pub st_blksize: ::blksize_t,
        pub st_flags: ::uint32_t,
        pub st_gen: ::uint32_t,
        pub st_birthtime: ::time_t,
        pub st_birthtime_nsec: ::c_long,
    }

    pub struct statvfs {
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_favail: ::fsfilcnt_t,
        pub f_fsid: ::c_ulong,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
    }

    pub struct addrinfo {
        pub ai_flags: ::c_int,
        pub ai_family: ::c_int,
        pub ai_socktype: ::c_int,
        pub ai_protocol: ::c_int,
        pub ai_addrlen: ::socklen_t,
        pub ai_addr: *mut ::sockaddr,
        pub ai_canonname: *mut ::c_char,
        pub ai_next: *mut ::addrinfo,
    }

    pub struct sockaddr_storage {
        pub ss_len: u8,
        pub ss_family: ::sa_family_t,
        __ss_pad1: [u8; 6],
        __ss_pad2: i64,
        __ss_pad3: [u8; 240],
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_code: ::c_int,
        pub si_errno: ::c_int,
        pub si_addr: *mut ::c_char,
        __pad: [u8; 108],
    }

    pub struct Dl_info {
        pub dli_fname: *const ::c_char,
        pub dli_fbase: *mut ::c_void,
        pub dli_sname: *const ::c_char,
        pub dli_saddr: *mut ::c_void,
    }
}

pub const O_CLOEXEC: ::c_int = 0x10000;

pub const MS_SYNC : ::c_int = 0x0002;
pub const MS_INVALIDATE : ::c_int = 0x0004;

pub const PTHREAD_STACK_MIN : ::size_t = 2048;

pub const ENOATTR : ::c_int = 83;
pub const EILSEQ : ::c_int = 84;
pub const EOVERFLOW : ::c_int = 87;
pub const ECANCELED : ::c_int = 88;
pub const EIDRM : ::c_int = 89;
pub const ENOMSG : ::c_int = 90;
pub const ENOTSUP : ::c_int = 91;
pub const ELAST : ::c_int = 91;

pub const F_DUPFD_CLOEXEC : ::c_int = 10;

pub const RLIM_NLIMITS: ::c_int = 9;

pub const SO_SNDTIMEO: ::c_int = 0x1005;
pub const SO_RCVTIMEO: ::c_int = 0x1006;

pub const KERN_PROC : ::c_int = 66;
pub const O_DSYNC : ::c_int = 128;

pub const MAP_RENAME : ::c_int = 0x0000;
pub const MAP_NORESERVE : ::c_int = 0x0000;
pub const MAP_HASSEMAPHORE : ::c_int = 0x0000;

pub const EIPSEC : ::c_int = 82;
pub const ENOMEDIUM : ::c_int = 85;
pub const EMEDIUMTYPE : ::c_int = 86;

pub const RUSAGE_THREAD: ::c_int = 1;

pub const MAP_COPY : ::c_int = 0x0002;
pub const MAP_NOEXTEND : ::c_int = 0x0000;

pub const _SC_CLK_TCK : ::c_int = 3;
pub const _SC_IOV_MAX : ::c_int = 51;
pub const _SC_GETGR_R_SIZE_MAX : ::c_int = 100;
pub const _SC_GETPW_R_SIZE_MAX : ::c_int = 101;
pub const _SC_LOGIN_NAME_MAX : ::c_int = 102;
pub const _SC_MQ_PRIO_MAX : ::c_int = 59;
pub const _SC_THREADS : ::c_int = 91;
pub const _SC_THREAD_ATTR_STACKADDR : ::c_int = 77;
pub const _SC_THREAD_ATTR_STACKSIZE : ::c_int = 78;
pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : ::c_int = 80;
pub const _SC_THREAD_KEYS_MAX : ::c_int = 81;
pub const _SC_THREAD_PRIO_INHERIT : ::c_int = 82;
pub const _SC_THREAD_PRIO_PROTECT : ::c_int = 83;
pub const _SC_THREAD_PRIORITY_SCHEDULING : ::c_int = 84;
pub const _SC_THREAD_PROCESS_SHARED : ::c_int = 85;
pub const _SC_THREAD_SAFE_FUNCTIONS : ::c_int = 103;
pub const _SC_THREAD_STACK_MIN : ::c_int = 89;
pub const _SC_THREAD_THREADS_MAX : ::c_int = 90;
pub const _SC_TTY_NAME_MAX : ::c_int = 107;
pub const _SC_ATEXIT_MAX : ::c_int = 46;
pub const _SC_AIO_LISTIO_MAX : ::c_int = 42;
pub const _SC_AIO_MAX : ::c_int = 43;
pub const _SC_ASYNCHRONOUS_IO : ::c_int = 45;
pub const _SC_MAPPED_FILES : ::c_int = 53;
pub const _SC_MEMLOCK : ::c_int = 54;
pub const _SC_MEMLOCK_RANGE : ::c_int = 55;
pub const _SC_MEMORY_PROTECTION : ::c_int = 56;
pub const _SC_MESSAGE_PASSING : ::c_int = 57;
pub const _SC_MQ_OPEN_MAX : ::c_int = 58;
pub const _SC_PRIORITY_SCHEDULING : ::c_int = 61;
pub const _SC_SEMAPHORES : ::c_int = 67;
pub const _SC_SHARED_MEMORY_OBJECTS : ::c_int = 68;
pub const _SC_SYNCHRONIZED_IO : ::c_int = 75;
pub const _SC_TIMERS : ::c_int = 94;
pub const _SC_XOPEN_CRYPT : ::c_int = 117;
pub const _SC_XOPEN_ENH_I18N : ::c_int = 118;
pub const _SC_XOPEN_LEGACY : ::c_int = 119;
pub const _SC_XOPEN_REALTIME : ::c_int = 120;
pub const _SC_XOPEN_REALTIME_THREADS : ::c_int = 121;
pub const _SC_XOPEN_UNIX : ::c_int = 123;
pub const _SC_XOPEN_VERSION : ::c_int = 125;
pub const _SC_SEM_NSEMS_MAX : ::c_int = 31;
pub const _SC_SEM_VALUE_MAX : ::c_int = 32;
pub const _SC_AIO_PRIO_DELTA_MAX : ::c_int = 44;
pub const _SC_DELAYTIMER_MAX : ::c_int = 50;
pub const _SC_PRIORITIZED_IO : ::c_int = 60;
pub const _SC_REALTIME_SIGNALS : ::c_int = 64;
pub const _SC_RTSIG_MAX : ::c_int = 66;
pub const _SC_SIGQUEUE_MAX : ::c_int = 70;
pub const _SC_TIMER_MAX : ::c_int = 93;

pub const SIGSTKSZ: ::size_t = 40960;

pub const FD_SETSIZE: usize = 1024;

pub const ST_NOSUID: ::c_ulong = 2;

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _;
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _;
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _;
pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2;

pub const KERN_PROC_ARGS: ::c_int = 55;

pub const TMP_MAX : ::c_uint = 0x7fffffff;

pub const NI_MAXHOST: ::size_t = 256;

extern {
    pub fn getnameinfo(sa: *const ::sockaddr,
                       salen: ::socklen_t,
                       host: *mut ::c_char,
                       hostlen: ::size_t,
                       serv: *mut ::c_char,
                       servlen: ::size_t,
                       flags: ::c_int) -> ::c_int;
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int)
                    -> ::c_int;
    pub fn sysctl(name: *const ::c_int,
                  namelen: ::c_uint,
                  oldp: *mut ::c_void,
                  oldlenp: *mut ::size_t,
                  newp: *mut ::c_void,
                  newlen: ::size_t)
                  -> ::c_int;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
}
<|endoftext|>


<commit_before>use std::cell::{Cell, UnsafeCell};
use std::fmt;
use std::marker::PhantomData;

/// This holds the backing allocation for the `Window` of a `Adaptor`.
///
/// See [sliding_windows](index.html) for more information.
pub struct Storage<T> {
    window_size: usize,
    // this is the offset of the first element
    window_offset: Cell<usize>,
    /// acts as a refcount
    uniquely_owned: Cell<bool>,
    data: UnsafeCell<Vec<T>>,
}

impl<T> Storage<T> {
    /// Create a new `Storage` with a given window size.
    /// This will allocate twice as much memory as is needed to store the Window for performance reasons.
    ///
    /// If you want to use as few memory as possible, but more CPU, consider using ```Storage::new_exact()``` instead.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(window_size: usize) -> Storage<T> {
        Storage::from_vec(Vec::with_capacity(window_size), window_size)
    }

    /// Create a new `Storage` with a given window size from a given struct implementing `Into<Vec>`.
    /// The contents of the Vec will be removed.
    /// This will reuse the allocation of the Vec instead of allocating new memory.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn from_vec<S: Into<Vec<T>>>(vec: S, window_size: usize) -> Storage<T> {
        Storage {
            window_size: window_size,
            window_offset: Cell::new(0),
            uniquely_owned: Cell::new(true),
            data: UnsafeCell::new(vec.into())
        }
    }

    fn new_window<'a>(&'a self) -> Window<'a, T> {
        // assert that the last window went out of scope
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        self.uniquely_owned.set(false);

        Window { drop_flag: &self.uniquely_owned, data: &mut data[..], window_offset: window_offset }
    }

    // push value onto self, return true if window is full (for initialization)
    // this assumes that data.capacity >= self.window_size
    fn push(&self, elt: T) -> bool {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        // if storage is not full simply push the element
        // this is only the case when filling storage initially
        if data.len() < self.window_size
        {
            data.push(elt);
            return data.len() == self.window_size;
        }

        debug_assert!(data.len() == self.window_size);

        // the storage is full, overwrite the last element
        let new_offset;
        if window_offset >= (self.window_size - 1) {
            new_offset = 0;
        } else {
            new_offset = window_offset + 1;
        }

        data[window_offset] = elt;
        self.window_offset.set(new_offset);
        true
    }

    // clear backing storage
    fn clear(&self) {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        data.clear();
    }
}

impl<T> Into<Vec<T>> for Storage<T> {
    fn into(self) -> Vec<T> {
        assert!(self.uniquely_owned.get(), "Storage dereferenced before previous Window went out of scope");
        unsafe {
            self.data.into_inner()
        }
    }
}

/// This is the `Item` type of the `Adaptor` iterator.
///
/// # Usage:
///
/// `&Window<'a, T>` implements `into_iter()`, which returns an Iterator over `&T`.
///
/// ```
/// use sliding_windows::IterExt;
/// use sliding_windows::Storage;
///
/// let mut storage: Storage<u32> = Storage::new(3);
/// let mut windowed_iter = (0..5).sliding_windows(&mut storage);
///
/// for mut window in windowed_iter {
///     // extra scope, so that later mutable borrow is possible
///     {
///         for x in &window {
///             // work with data immutably
///         }
///     }
///
///     // mutable
///     let mut iter_mut = window.iter_mut();
///     for x in iter_mut {
///         // work with data mutably (affecting the next windows of course)
///     }
/// }
/// ```
///
/// See [sliding_windows](index.html) for more information.
pub struct Window<'a, T: 'a> {
    drop_flag: &'a Cell<bool>,
    // index of first element
    window_offset: usize,
    data: &'a mut [T],
}

impl<'a, T> Window<'a, T>
{
    pub fn iter(&self) -> WindowIter<T> {
        WindowIter {
            data: self.data,
            current_index: self.window_offset,
            iteration_num: 0
        }
    }

    pub fn iter_mut(&mut self) -> WindowIterMut<T> {
        WindowIterMut {
            data: self.data.as_mut_ptr(),
            data_len: self.data.len(),
            current_index: self.window_offset,
            iteration_num: 0,
            _p: PhantomData
        }
    }
}

impl<'a, T> fmt::Debug for Window<'a, T> where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Window")?;
        return f.debug_list().entries(self.into_iter()).finish();
    }
}

impl<'a, T> Drop for Window<'a, T> {
    fn drop(&mut self) {
        // set flag to indicate this window was dropped
        self.drop_flag.set(true);
    }
}

impl<'a, 'b, T> PartialEq<&'b [T]> for Window<'a, T> where T: PartialEq
{
    fn eq(&self, other: &&'b [T]) -> bool {
        if self.data.len() != other.len() { return false }
        for (i, x) in self.into_iter().enumerate() {
            if *x != other[i] { return false }
        }
        true
    }
}

impl<'a, T> IntoIterator for &'a Window<'a, T>
{
    type Item = &'a T;
    type IntoIter = WindowIter<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

pub struct WindowIter<'a, T: 'a>
{
    data: &'a [T],
    current_index: usize,
    // number of next() calls made which returned Some(_)
    iteration_num: usize,
}

impl<'a, T> Iterator for WindowIter<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let current_element = &self.data[self.current_index];

        if self.iteration_num >= self.data.len() {
            // the end was reached
            return None;
        } else if self.current_index >= (self.data.len() - 1) {
            // wrap around if the increment would create an invalid index
            self.current_index = 0;
        } else {
            self.current_index += 1;
        }

        self.iteration_num += 1;
        Some(current_element)
    }
}

pub struct WindowIterMut<'a, T: 'a>
{
    data: *mut T,
    data_len: usize,
    current_index: usize,
    // number of next() calls made which returned Some(_)
    iteration_num: usize,
    _p: PhantomData<&'a T>,
}

impl<'a, T> Iterator for WindowIterMut<'a, T>
{
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let current_element = unsafe { self.data.offset(self.current_index as isize).as_mut().unwrap() };

        if self.iteration_num >= self.data_len {
            // the end was reached
            return None;
        } else if self.current_index >= (self.data_len - 1) {
            // wrap around if the increment would create an invalid index
            self.current_index = 0;
        } else {
            self.current_index += 1;
        }

        self.iteration_num += 1;
        Some(current_element)
    }
}

// TODO add ExactSizeIterator
// TODO add other stuff like DoubleEndedIterator etc.

/// See [sliding_windows](index.html) for more information.
pub struct Adaptor<'a, I: Iterator> where <I as Iterator>::Item: 'a {
    iter: I,
    done: bool,
    storage: &'a Storage<I::Item>,
}

impl<'a, I: Iterator> Adaptor<'a, I> {
    /// This creates a new Adaptor. Usually you should be using
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(iter: I, storage: &'a Storage<I::Item>) -> Adaptor<'a, I> {
        // in case the storage was reused
        storage.clear();

        Adaptor {
            iter: iter,
            done: false,
            storage: storage,
        }
    }
}

impl<'a, I: Iterator> Iterator for Adaptor<'a, I> {
    type Item = Window<'a, I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done || self.storage.window_size == 0 {
            return None;
        }
        self.done = true;

        for elt in &mut self.iter {
            self.done = false;
            if self.storage.push(elt) {
                break;
            }
        }

        if !self.done {
            // return new window
            Some(self.storage.new_window())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = self.storage.window_size;
        let (mut lower, mut upper): (usize, Option<usize>) = self.iter.size_hint();

        if size == 0 {
            return (0, None);
        }

        lower = match lower {
            0 => 0,
            x if x >= size => x - size + 1,
            _ => 1
        };

        upper = upper.map(|upper|
            match upper {
                0 => 0,
                x if x >= size => x - size + 1,
                _ => 1
            }
        );

        (lower, upper)
    }
}
<commit_msg>fix some doc comments<commit_after>use std::cell::{Cell, UnsafeCell};
use std::fmt;
use std::marker::PhantomData;

/// This holds the backing allocation for the `Window` of an `Adaptor`.
///
/// See [sliding_windows](index.html) for more information.
pub struct Storage<T> {
    window_size: usize,
    // this is the offset of the first element
    window_offset: Cell<usize>,
    /// acts as a refcount
    uniquely_owned: Cell<bool>,
    data: UnsafeCell<Vec<T>>,
}

impl<T> Storage<T> {
    /// Create a new `Storage` with a given window size.
    /// This will allocate `window_size * sizeof::<T>` bytes on the heap.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(window_size: usize) -> Storage<T> {
        Storage::from_vec(Vec::with_capacity(window_size), window_size)
    }

    /// Create a new `Storage` with a given window size from a given type implementing `Into<Vec>`.
    /// The contents of the Vec will be removed.
    /// This will reuse the allocation of the Vec instead of allocating new memory.
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn from_vec<S: Into<Vec<T>>>(vec: S, window_size: usize) -> Storage<T> {
        Storage {
            window_size: window_size,
            window_offset: Cell::new(0),
            uniquely_owned: Cell::new(true),
            data: UnsafeCell::new(vec.into())
        }
    }

    fn new_window<'a>(&'a self) -> Window<'a, T> {
        // assert that the last window went out of scope
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        self.uniquely_owned.set(false);

        Window { drop_flag: &self.uniquely_owned, data: &mut data[..], window_offset: window_offset }
    }

    // push value onto self, return true if window is full (for initialization)
    // this assumes that data.capacity >= self.window_size
    fn push(&self, elt: T) -> bool {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        let window_offset = self.window_offset.get();

        // if storage is not full simply push the element
        // this is only the case when filling storage initially
        if data.len() < self.window_size
        {
            data.push(elt);
            return data.len() == self.window_size;
        }

        debug_assert!(data.len() == self.window_size);

        // the storage is full, overwrite the last element
        let new_offset;
        if window_offset >= (self.window_size - 1) {
            new_offset = 0;
        } else {
            new_offset = window_offset + 1;
        }

        data[window_offset] = elt;
        self.window_offset.set(new_offset);
        true
    }

    // clear backing storage
    fn clear(&self) {
        assert!(self.uniquely_owned.get(), "next() called before previous Window went out of scope");
        let data = unsafe { &mut *self.data.get() };
        data.clear();
    }
}

impl<T> Into<Vec<T>> for Storage<T> {
    fn into(self) -> Vec<T> {
        assert!(self.uniquely_owned.get(), "Storage dereferenced before previous Window went out of scope");
        unsafe {
            self.data.into_inner()
        }
    }
}

/// This is the `Item` type of the `Adaptor` iterator.
///
/// # Usage:
///
/// Use [WindowIter](struct.WindowIter.html) or [WindowIterMut](struct.WindowIterMut.html) to access the elements of the Window.
///
/// ```
/// use sliding_windows::IterExt;
/// use sliding_windows::Storage;
///
/// let mut storage: Storage<u32> = Storage::new(3);
/// let mut windowed_iter = (0..5).sliding_windows(&mut storage);
///
/// for mut window in windowed_iter {
///     // extra scope, so that later mutable borrow is possible
///     {
///         for x in &window {
///             // work with data immutably
///         }
///     }
///
///     // mutable
///     let mut iter_mut = window.iter_mut();
///     for x in iter_mut {
///         // work with data mutably (affecting the next windows of course)
///     }
/// }
/// ```
///
/// See [sliding_windows](index.html) for more information.
pub struct Window<'a, T: 'a> {
    drop_flag: &'a Cell<bool>,
    // index of first element
    window_offset: usize,
    data: &'a mut [T],
}

impl<'a, T> Window<'a, T>
{
    pub fn iter(&self) -> WindowIter<T> {
        WindowIter {
            data: self.data,
            current_index: self.window_offset,
            iteration_num: 0
        }
    }

    pub fn iter_mut(&mut self) -> WindowIterMut<T> {
        WindowIterMut {
            data: self.data.as_mut_ptr(),
            data_len: self.data.len(),
            current_index: self.window_offset,
            iteration_num: 0,
            _p: PhantomData
        }
    }
}

impl<'a, T> fmt::Debug for Window<'a, T> where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Window")?;
        return f.debug_list().entries(self.into_iter()).finish();
    }
}

impl<'a, T> Drop for Window<'a, T> {
    fn drop(&mut self) {
        // set flag to indicate this window was dropped
        self.drop_flag.set(true);
    }
}

impl<'a, 'b, T> PartialEq<&'b [T]> for Window<'a, T> where T: PartialEq
{
    fn eq(&self, other: &&'b [T]) -> bool {
        if self.data.len() != other.len() { return false }
        for (i, x) in self.into_iter().enumerate() {
            if *x != other[i] { return false }
        }
        true
    }
}

impl<'a, T> IntoIterator for &'a Window<'a, T>
{
    type Item = &'a T;
    type IntoIter = WindowIter<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

pub struct WindowIter<'a, T: 'a>
{
    data: &'a [T],
    current_index: usize,
    // number of next() calls made which returned Some(_)
    iteration_num: usize,
}

impl<'a, T> Iterator for WindowIter<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let current_element = &self.data[self.current_index];

        if self.iteration_num >= self.data.len() {
            // the end was reached
            return None;
        } else if self.current_index >= (self.data.len() - 1) {
            // wrap around if the increment would create an invalid index
            self.current_index = 0;
        } else {
            self.current_index += 1;
        }

        self.iteration_num += 1;
        Some(current_element)
    }
}

pub struct WindowIterMut<'a, T: 'a>
{
    data: *mut T,
    data_len: usize,
    current_index: usize,
    // number of next() calls made which returned Some(_)
    iteration_num: usize,
    _p: PhantomData<&'a T>,
}

impl<'a, T> Iterator for WindowIterMut<'a, T>
{
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let current_element = unsafe { self.data.offset(self.current_index as isize).as_mut().unwrap() };

        if self.iteration_num >= self.data_len {
            // the end was reached
            return None;
        } else if self.current_index >= (self.data_len - 1) {
            // wrap around if the increment would create an invalid index
            self.current_index = 0;
        } else {
            self.current_index += 1;
        }

        self.iteration_num += 1;
        Some(current_element)
    }
}

// TODO add ExactSizeIterator
// TODO add other stuff like DoubleEndedIterator etc.

/// See [sliding_windows](index.html) for more information.
pub struct Adaptor<'a, I: Iterator> where <I as Iterator>::Item: 'a {
    iter: I,
    done: bool,
    storage: &'a Storage<I::Item>,
}

impl<'a, I: Iterator> Adaptor<'a, I> {
    /// This creates a new Adaptor. Usually you should be using
    ///
    /// See [sliding_windows](index.html) for more information.
    pub fn new(iter: I, storage: &'a Storage<I::Item>) -> Adaptor<'a, I> {
        // in case the storage was reused
        storage.clear();

        Adaptor {
            iter: iter,
            done: false,
            storage: storage,
        }
    }
}

impl<'a, I: Iterator> Iterator for Adaptor<'a, I> {
    type Item = Window<'a, I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done || self.storage.window_size == 0 {
            return None;
        }
        self.done = true;

        for elt in &mut self.iter {
            self.done = false;
            if self.storage.push(elt) {
                break;
            }
        }

        if !self.done {
            // return new window
            Some(self.storage.new_window())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = self.storage.window_size;
        let (mut lower, mut upper): (usize, Option<usize>) = self.iter.size_hint();

        if size == 0 {
            return (0, None);
        }

        lower = match lower {
            0 => 0,
            x if x >= size => x - size + 1,
            _ => 1
        };

        upper = upper.map(|upper|
            match upper {
                0 => 0,
                x if x >= size => x - size + 1,
                _ => 1
            }
        );

        (lower, upper)
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::new(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    pub fn iter_ids(&self, m: &Module) -> Result<IntoIter<FileID>, StorageBackendError>
    {
        let globstr = self.prefix_of_files_for_module(m) + "*.imag";
        debug!("Globstring = {}", globstr);
        glob(&globstr[..])
            .and_then(|globlist| {
                debug!("Iterating over globlist");
                Ok(globlist.filter_map(Result::ok)
                           .map(|pbuf| FileID::from(&pbuf))
                           .collect::<Vec<FileID>>()
                           .into_iter())
            })
            .map_err(|e| {
                debug!("glob() returned error: {:?}", e);
                let serr = StorageBackendError::new(
                        "iter_ids()",
                        "Cannot iter on file ids",
                        None);
                // Why the hack is Error not implemented for glob::PatternError
                // serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Result<IntoIter<File<'a>>, StorageBackendError>
        where HP: FileHeaderParser
    {
        self.iter_ids(m)
            .and_then(|ids| {
                debug!("Iterating ids and building files from them");
                debug!("  number of ids = {}", ids.len());
                Ok(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                        .collect::<Vec<File>>()
                        .into_iter())
            })
            .map_err(|e| {
                debug!("StorageBackend::iter_ids() returned error = {:?}", e);
                let mut serr = StorageBackendError::new("iter_files()",
                                           "Cannot iter on files",
                                           None);
                serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success opening file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::new(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        let idstr   : String        = id.clone().into();
        let idtype  : FileIDType    = id.into();
        let typestr : String        = idtype.into();

        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("        id: '{}'", idstr);
        debug!("      type: '{}'", typestr);

        self.prefix_of_files_for_module(owner) +
            "-" + &typestr[..] +
            "-" + &idstr[..] +
            ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {

    fn new<S>(action: S, desc: S, data: Option<String>) -> StorageBackendError
        where S: Into<String>
    {
        StorageBackendError {
            action:         action.into(),
            desc:           desc.into(),
            data_dump:      data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::new(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>(partly) Rewrite StorageBackend::get_file_by_id(), so we can get a file with a partially available ID<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::new(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    pub fn iter_ids(&self, m: &Module) -> Result<IntoIter<FileID>, StorageBackendError>
    {
        let globstr = self.prefix_of_files_for_module(m) + "*.imag";
        debug!("Globstring = {}", globstr);
        glob(&globstr[..])
            .and_then(|globlist| {
                debug!("Iterating over globlist");
                Ok(globlist.filter_map(Result::ok)
                           .map(|pbuf| FileID::from(&pbuf))
                           .collect::<Vec<FileID>>()
                           .into_iter())
            })
            .map_err(|e| {
                debug!("glob() returned error: {:?}", e);
                let serr = StorageBackendError::new(
                        "iter_ids()",
                        "Cannot iter on file ids",
                        None);
                // Why the hack is Error not implemented for glob::PatternError
                // serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Result<IntoIter<File<'a>>, StorageBackendError>
        where HP: FileHeaderParser
    {
        self.iter_ids(m)
            .and_then(|ids| {
                debug!("Iterating ids and building files from them");
                debug!("  number of ids = {}", ids.len());
                Ok(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                        .collect::<Vec<File>>()
                        .into_iter())
            })
            .map_err(|e| {
                debug!("StorageBackend::iter_ids() returned error = {:?}", e);
                let mut serr = StorageBackendError::new("iter_files()",
                                           "Cannot iter on files",
                                           None);
                serr.caused_by = Some(Box::new(e));
                serr
            })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::new(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::new(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        use std::ops::Index;

        debug!("Searching for file with id '{}'", id);

        if id.get_type() == FileIDType::NONE {
            // We don't know the hash type, so we glob() around a bit.

            let globstr = self.prefix_of_files_for_module(m) + "*" + ".imag";
            glob(&globstr[..]).map(|globlist| {
                let mut vec = globlist.filter_map(Result::ok)
                                      .map(|pbuf| FileID::from(&pbuf))
                                      .filter_map(|id| self.get_file_by_id(m, &id, p))
                                      .collect::<Vec<File>>();
                vec.reverse();
                vec.pop()
            }).map_err(|e| e).unwrap()
        } else {
            // The (hash)type is already in the FileID object, so we can just
            // build a path from the information we already have
            if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
                let mut s = String::new();
                fs.read_to_string(&mut s);
                debug!("Success opening file with id '{}'", id);
                debug!("Parsing to internal structure now");
                p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
            } else {
                debug!("No file with id '{}'", id);
                None
            }
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::new(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        let idstr   : String        = id.clone().into();
        let idtype  : FileIDType    = id.into();
        let typestr : String        = idtype.into();

        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("        id: '{}'", idstr);
        debug!("      type: '{}'", typestr);

        self.prefix_of_files_for_module(owner) +
            "-" + &typestr[..] +
            "-" + &idstr[..] +
            ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {

    fn new<S>(action: S, desc: S, data: Option<String>) -> StorageBackendError
        where S: Into<String>
    {
        StorageBackendError {
            action:         action.into(),
            desc:           desc.into(),
            data_dump:      data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::new(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>