<commit_before>use itertools::Itertools;
use std::hash::Hash;
use std::iter::FromIterator;

use generate::{HashIndexer, IndexVertices, IntoTriangles, IntoVertices, Topological, Triangulate};
use graph::geometry::{Attribute, Geometry};
use graph::storage::{EdgeKey, FaceKey, Key, OpaqueKey, Storage, VertexKey};

#[derive(Clone, Debug)]
pub struct Vertex<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) edge: Option<EdgeKey<K>>,
}

impl<T, K> Vertex<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new() -> Self {
        Vertex::with_geometry(T::default())
    }

    fn with_geometry(geometry: T) -> Self {
        Vertex {
            geometry: geometry,
            edge: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Edge<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) vertex: VertexKey<K>,
    pub(super) opposite: Option<EdgeKey<K>>,
    pub(super) next: Option<EdgeKey<K>>,
    pub(super) face: Option<FaceKey<K>>,
}

impl<T, K> Edge<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new(vertex: VertexKey<K>) -> Self {
        Edge::with_geometry(vertex, T::default())
    }

    fn with_geometry(vertex: VertexKey<K>, geometry: T) -> Self {
        Edge {
            geometry: geometry,
            vertex: vertex,
            opposite: None,
            next: None,
            face: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Face<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) edge: EdgeKey<K>,
}

impl<T, K> Face<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new(edge: EdgeKey<K>) -> Self {
        Face::with_geometry(edge, T::default())
    }

    fn with_geometry(edge: EdgeKey<K>, geometry: T) -> Self {
        Face {
            geometry: geometry,
            edge: edge,
        }
    }
}

pub struct Mesh<G, K = u64>
where
    G: Geometry,
    K: Key,
{
    pub(super) vertices: Storage<K, Vertex<G::Vertex, K>>,
    pub(super) edges: Storage<K, Edge<G::Edge, K>>,
    pub(super) faces: Storage<K, Face<G::Face, K>>,
}

impl<G, K> Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    pub fn new() -> Self {
        Mesh {
            vertices: Storage::new(),
            edges: Storage::new(),
            faces: Storage::new(),
        }
    }

    fn insert_vertex(&mut self, geometry: G::Vertex) -> VertexKey<K> {
        self.vertices.insert(Vertex::with_geometry(geometry)).into()
    }

    fn insert_edge(
        &mut self,
        vertices: (VertexKey<K>, VertexKey<K>),
        geometry: G::Edge,
    ) -> Result<EdgeKey<K>, ()> {
        let (i, j) = vertices;
        let ij = self.edges.insert(Edge::with_geometry(j, geometry));
        self.vertices.get_mut(&i.to_inner()).unwrap().edge = Some(ij.into());
        Ok(ij.into())
    }

    fn connect_edges_in_face(&mut self, face: FaceKey<K>, edges: (EdgeKey<K>, EdgeKey<K>)) {
        let edge = self.edges.get_mut(&edges.0.to_inner()).unwrap();
        edge.next = edges.1.into();
        edge.face = face.into();
    }

    fn insert_triangle(
        &mut self,
        edges: (EdgeKey<K>, EdgeKey<K>, EdgeKey<K>),
        geometry: G::Face,
    ) -> Result<FaceKey<K>, ()> {
        let (ij, jk, ki) = edges;
        let face = self.faces
            .insert(Face::with_geometry(ij.into(), geometry))
            .into();
        self.connect_edges_in_face(face, (ij, jk));
        self.connect_edges_in_face(face, (jk, ki));
        self.connect_edges_in_face(face, (ki, ij));
        Ok(face)
    }
}

impl<G, K> AsRef<Mesh<G, K>> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<G, K> AsMut<Mesh<G, K>> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<G, K, T> FromIterator<T> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
    T: IntoTriangles + IntoVertices + Topological,
    T::Vertex: Eq + Hash + Into<G::Vertex>,
{
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut mesh = Mesh::new();
        let (indeces, vertices) = input
            .into_iter()
            .triangulate()
            .index_vertices(HashIndexer::default());
        let vertices = vertices
            .into_iter()
            .map(|vertex| mesh.insert_vertex(vertex.into()))
            .collect::<Vec<_>>();
        for mut triangle in &indeces.into_iter().chunks(3) {
            // Map from the indeces into the original buffers to the keys
            // referring to the vertices in the mesh.
            let (i, j, k) = (
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
            );
            let (ij, jk, ki) = (
                mesh.insert_edge((i, j), G::Edge::default()).unwrap(),
                mesh.insert_edge((j, k), G::Edge::default()).unwrap(),
                mesh.insert_edge((k, i), G::Edge::default()).unwrap(),
            );
            mesh.insert_triangle((ij, jk, ki), G::Face::default());
        }
        mesh
    }
}
<commit_msg>Rename `i, j, k` triple to `a, b, c`.<commit_after>use itertools::Itertools;
use std::hash::Hash;
use std::iter::FromIterator;

use generate::{HashIndexer, IndexVertices, IntoTriangles, IntoVertices, Topological, Triangulate};
use graph::geometry::{Attribute, Geometry};
use graph::storage::{EdgeKey, FaceKey, Key, OpaqueKey, Storage, VertexKey};

#[derive(Clone, Debug)]
pub struct Vertex<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) edge: Option<EdgeKey<K>>,
}

impl<T, K> Vertex<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new() -> Self {
        Vertex::with_geometry(T::default())
    }

    fn with_geometry(geometry: T) -> Self {
        Vertex {
            geometry: geometry,
            edge: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Edge<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) vertex: VertexKey<K>,
    pub(super) opposite: Option<EdgeKey<K>>,
    pub(super) next: Option<EdgeKey<K>>,
    pub(super) face: Option<FaceKey<K>>,
}

impl<T, K> Edge<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new(vertex: VertexKey<K>) -> Self {
        Edge::with_geometry(vertex, T::default())
    }

    fn with_geometry(vertex: VertexKey<K>, geometry: T) -> Self {
        Edge {
            geometry: geometry,
            vertex: vertex,
            opposite: None,
            next: None,
            face: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct Face<T, K>
where
    T: Attribute,
    K: Key,
{
    pub geometry: T,
    pub(super) edge: EdgeKey<K>,
}

impl<T, K> Face<T, K>
where
    T: Attribute,
    K: Key,
{
    fn new(edge: EdgeKey<K>) -> Self {
        Face::with_geometry(edge, T::default())
    }

    fn with_geometry(edge: EdgeKey<K>, geometry: T) -> Self {
        Face {
            geometry: geometry,
            edge: edge,
        }
    }
}

pub struct Mesh<G, K = u64>
where
    G: Geometry,
    K: Key,
{
    pub(super) vertices: Storage<K, Vertex<G::Vertex, K>>,
    pub(super) edges: Storage<K, Edge<G::Edge, K>>,
    pub(super) faces: Storage<K, Face<G::Face, K>>,
}

impl<G, K> Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    pub fn new() -> Self {
        Mesh {
            vertices: Storage::new(),
            edges: Storage::new(),
            faces: Storage::new(),
        }
    }

    fn insert_vertex(&mut self, geometry: G::Vertex) -> VertexKey<K> {
        self.vertices.insert(Vertex::with_geometry(geometry)).into()
    }

    fn insert_edge(
        &mut self,
        vertices: (VertexKey<K>, VertexKey<K>),
        geometry: G::Edge,
    ) -> Result<EdgeKey<K>, ()> {
        let (a, b) = vertices;
        let ab = self.edges.insert(Edge::with_geometry(b, geometry));
        self.vertices.get_mut(&a.to_inner()).unwrap().edge = Some(ab.into());
        Ok(ab.into())
    }

    fn connect_edges_in_face(&mut self, face: FaceKey<K>, edges: (EdgeKey<K>, EdgeKey<K>)) {
        let edge = self.edges.get_mut(&edges.0.to_inner()).unwrap();
        edge.next = edges.1.into();
        edge.face = face.into();
    }

    fn insert_triangle(
        &mut self,
        edges: (EdgeKey<K>, EdgeKey<K>, EdgeKey<K>),
        geometry: G::Face,
    ) -> Result<FaceKey<K>, ()> {
        let (ab, bc, ca) = edges;
        let face = self.faces
            .insert(Face::with_geometry(ab.into(), geometry))
            .into();
        self.connect_edges_in_face(face, (ab, bc));
        self.connect_edges_in_face(face, (bc, ca));
        self.connect_edges_in_face(face, (ca, ab));
        Ok(face)
    }
}

impl<G, K> AsRef<Mesh<G, K>> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<G, K> AsMut<Mesh<G, K>> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<G, K, T> FromIterator<T> for Mesh<G, K>
where
    G: Geometry,
    K: Key,
    T: IntoTriangles + IntoVertices + Topological,
    T::Vertex: Eq + Hash + Into<G::Vertex>,
{
    fn from_iter<I>(input: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut mesh = Mesh::new();
        let (indeces, vertices) = input
            .into_iter()
            .triangulate()
            .index_vertices(HashIndexer::default());
        let vertices = vertices
            .into_iter()
            .map(|vertex| mesh.insert_vertex(vertex.into()))
            .collect::<Vec<_>>();
        for mut triangle in &indeces.into_iter().chunks(3) {
            // Map from the indeces into the original buffers to the keys
            // referring to the vertices in the mesh.
            let (a, b, c) = (
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
                vertices[triangle.next().unwrap()],
            );
            let (ab, bc, ca) = (
                mesh.insert_edge((a, b), G::Edge::default()).unwrap(),
                mesh.insert_edge((b, c), G::Edge::default()).unwrap(),
                mesh.insert_edge((c, a), G::Edge::default()).unwrap(),
            );
            mesh.insert_triangle((ab, bc, ca), G::Face::default())
                .unwrap();
        }
        mesh
    }
}
<|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 https://mozilla.org/MPL/2.0/.

use std::path::PathBuf;

use ra_ap_hir::{self as hir};
use ra_ap_ide_db::RootDatabase;

pub(crate) mod attr;
pub(crate) mod visibility;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FunctionNode {
    is_unsafe: bool,
    is_async: bool,
    is_const: bool,
}

impl FunctionNode {
    pub fn display_name(&self) -> Option<String> {
        let mut keywords = vec![];
        if self.is_const {
            keywords.push("const");
        }
        if self.is_async {
            keywords.push("async");
        }
        if self.is_unsafe {
            keywords.push("unsafe");
        }
        keywords.push("fn");
        Some(keywords.join(" "))
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TypeNode {
    Struct,
    Union,
    Enum,
    BuiltinType,
}

impl TypeNode {
    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Struct => Some("struct".to_owned()),
            Self::Union => Some("union".to_owned()),
            Self::Enum => Some("enum".to_owned()),
            Self::BuiltinType => Some("builtin".to_owned()),
        }
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ValueNode {
    Const,
    Static,
}

impl ValueNode {
    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Const => Some("const".to_owned()),
            Self::Static => Some("static".to_owned()),
        }
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NodeKind {
    Crate,
    Function(FunctionNode),
    Module,
    Orphan,
    Trait,
    Type(TypeNode),
    TypeAlias,
    Value(ValueNode),
}

impl NodeKind {
    pub fn from(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<Self> {
        match module_def {
            hir::ModuleDef::Module(module) => {
                if module == module.crate_root(db) {
                    Some(NodeKind::Crate)
                } else {
                    Some(NodeKind::Module)
                }
            }
            hir::ModuleDef::Function(function) => Some(NodeKind::Function(FunctionNode {
                is_unsafe: function.is_unsafe_to_call(db),
                is_async: function.is_async(db),
                is_const: function.is_const(db),
            })),
            hir::ModuleDef::Adt(hir::Adt::Struct(_)) => Some(NodeKind::Type(TypeNode::Struct)),
            hir::ModuleDef::Adt(hir::Adt::Union(_)) => Some(NodeKind::Type(TypeNode::Union)),
            hir::ModuleDef::Adt(hir::Adt::Enum(_)) => Some(NodeKind::Type(TypeNode::Enum)),
            hir::ModuleDef::Variant(_) => None,
            hir::ModuleDef::Const(_) => Some(NodeKind::Value(ValueNode::Const)),
            hir::ModuleDef::Static(_) => Some(NodeKind::Value(ValueNode::Static)),
            hir::ModuleDef::Trait(_) => Some(NodeKind::Trait),
            hir::ModuleDef::TypeAlias(_) => Some(NodeKind::TypeAlias),
            hir::ModuleDef::BuiltinType(_) => Some(NodeKind::Type(TypeNode::BuiltinType)),
            hir::ModuleDef::Macro(_) => None,
        }
    }

    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Crate => Some("crate".to_owned()),
            Self::Function(node) => node.display_name(),
            Self::Module => Some("mod".to_owned()),
            Self::Orphan => None,
            Self::Trait => Some("trait".to_owned()),
            Self::Type(node) => node.display_name(),
            Self::TypeAlias => Some("type".to_owned()),
            Self::Value(node) => node.display_name(),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Node {
    pub krate: Option<String>,
    pub path: Vec<String>,
    pub file_path: Option<PathBuf>,
    pub kind: NodeKind,
    pub visibility: Option<visibility::NodeVisibility>,
    pub attrs: attr::NodeAttrs,
}

impl Node {
    pub fn display_name(&self) -> String {
        self.path
            .last()
            .expect("Expected path with at least one component")
            .clone()
    }

    pub fn display_path(&self) -> String {
        self.path.join("::")
    }

    pub fn crate_display_name(&self) -> String {
        self.path
            .first()
            .expect("Expected path with at least one component")
            .clone()
    }
}
<commit_msg>Make traits display their optional `unsafe` modifier<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 https://mozilla.org/MPL/2.0/.

use std::path::PathBuf;

use ra_ap_hir::{self as hir};
use ra_ap_ide_db::RootDatabase;

pub(crate) mod attr;
pub(crate) mod visibility;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FunctionNode {
    is_unsafe: bool,
    is_async: bool,
    is_const: bool,
}

impl FunctionNode {
    pub fn display_name(&self) -> Option<String> {
        let mut keywords = vec![];
        if self.is_const {
            keywords.push("const");
        }
        if self.is_async {
            keywords.push("async");
        }
        if self.is_unsafe {
            keywords.push("unsafe");
        }
        keywords.push("fn");
        Some(keywords.join(" "))
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TraitNode {
    is_unsafe: bool,
}

impl TraitNode {
    pub fn display_name(&self) -> Option<String> {
        let mut keywords = vec![];
        if self.is_unsafe {
            keywords.push("unsafe");
        }
        keywords.push("trait");
        Some(keywords.join(" "))
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TypeNode {
    Struct,
    Union,
    Enum,
    BuiltinType,
}

impl TypeNode {
    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Struct => Some("struct".to_owned()),
            Self::Union => Some("union".to_owned()),
            Self::Enum => Some("enum".to_owned()),
            Self::BuiltinType => Some("builtin".to_owned()),
        }
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ValueNode {
    Const,
    Static,
}

impl ValueNode {
    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Const => Some("const".to_owned()),
            Self::Static => Some("static".to_owned()),
        }
    }
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NodeKind {
    Crate,
    Function(FunctionNode),
    Module,
    Orphan,
    Trait(TraitNode),
    Type(TypeNode),
    TypeAlias,
    Value(ValueNode),
}

impl NodeKind {
    pub fn from(module_def: hir::ModuleDef, db: &RootDatabase) -> Option<Self> {
        match module_def {
            hir::ModuleDef::Module(def) => {
                if def.is_crate_root(db) {
                    Some(NodeKind::Crate)
                } else {
                    Some(NodeKind::Module)
                }
            }
            hir::ModuleDef::Function(def) => Some(NodeKind::Function(FunctionNode {
                is_unsafe: def.is_unsafe_to_call(db),
                is_async: def.is_async(db),
                is_const: def.is_const(db),
            })),
            hir::ModuleDef::Adt(def) => match def {
                hir::Adt::Struct(_) => Some(NodeKind::Type(TypeNode::Struct)),
                hir::Adt::Union(_) => Some(NodeKind::Type(TypeNode::Union)),
                hir::Adt::Enum(_) => Some(NodeKind::Type(TypeNode::Enum)),
            },
            hir::ModuleDef::Variant(_) => None,
            hir::ModuleDef::Const(_) => Some(NodeKind::Value(ValueNode::Const)),
            hir::ModuleDef::Static(_) => Some(NodeKind::Value(ValueNode::Static)),
            hir::ModuleDef::Trait(def) => Some(NodeKind::Trait(TraitNode {
                is_unsafe: def.is_unsafe(db),
            })),
            hir::ModuleDef::TypeAlias(_) => Some(NodeKind::TypeAlias),
            hir::ModuleDef::BuiltinType(_) => Some(NodeKind::Type(TypeNode::BuiltinType)),
            hir::ModuleDef::Macro(_) => None,
        }
    }

    pub fn display_name(&self) -> Option<String> {
        match self {
            Self::Crate => Some("crate".to_owned()),
            Self::Function(node) => node.display_name(),
            Self::Module => Some("mod".to_owned()),
            Self::Orphan => None,
            Self::Trait(node) => node.display_name(),
            Self::Type(node) => node.display_name(),
            Self::TypeAlias => Some("type".to_owned()),
            Self::Value(node) => node.display_name(),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Node {
    pub krate: Option<String>,
    pub path: Vec<String>,
    pub file_path: Option<PathBuf>,
    pub kind: NodeKind,
    pub visibility: Option<visibility::NodeVisibility>,
    pub attrs: attr::NodeAttrs,
}

impl Node {
    pub fn display_name(&self) -> String {
        self.path
            .last()
            .expect("Expected path with at least one component")
            .clone()
    }

    pub fn display_path(&self) -> String {
        self.path.join("::")
    }

    pub fn crate_display_name(&self) -> String {
        self.path
            .first()
            .expect("Expected path with at least one component")
            .clone()
    }
}
<|endoftext|>


<commit_before>#![feature(box_into_inner)]

#[derive(Debug)]
struct List {
    v: i32,
    next: Option<Box<Self>>,
}

impl List {
    fn new(mut input: Vec<i32>) -> Option<Self> {
        let mut this;
        let mut tail = None;
        loop {
            if let Some(i) = input.pop() {
                this = Self { v: i, next: tail };
                tail = Some(Box::new(this));
            } else {
                return Some(Box::into_inner(tail.unwrap()));
            };
        }
    }

    fn new_helper(mut input: Vec<Self>) -> Result<Self, String> {
        let mut this = match input.pop() {
            Some(tail) => tail,
            None => return Err("are you fucking kidding me?".to_string()),
        };

        loop {
            if let Some(mut tail) = input.pop() {
                tail.next = Some(Box::new(this));
                this = tail;
            } else {
                return Ok(this);
            };
        }
    }

    fn for_dear_uncle_shi(self, k: usize) -> Self {
        let mut head = self;
        let mut next = head.next.take();
        let mut cache = vec![];
        for ind in 0..k {
            cache.push(head);
            match next {
                Some(n) => {
                    head = Box::into_inner(n);
                    next = head.next.take();
                }
                None => {
                    if ind != k - 1 {
                        return Self::new_helper(cache).unwrap();
                    } else {
                        cache.reverse();
                        return Self::new_helper(cache).unwrap();
                    }
                }
            }
        }

        head.next = next;
        cache[0].next = Some(Box::new(head.for_dear_uncle_shi(k)));
        cache.reverse();
        Self::new_helper(cache).unwrap()
    }
}

fn main() {
    // dbg!(List::new(vec![1, 2, 3, 4, 5, 6, 7, 8]));
    // dbg!(List::new_helper(vec![
    //     List { v: 3, next: None },
    //     List { v: 2, next: None },
    //     List { v: 1, next: None }
    // ]));

    let a = List::new(vec![1, 2, 3, 4, 5, 6]).unwrap();
    dbg!(a.for_dear_uncle_shi(3));
    let a = List::new(vec![1, 2, 3, 4, 5, 6]).unwrap();
    dbg!(a.for_dear_uncle_shi(4));
}
<commit_msg>a hammer<commit_after>//#![feature(box_into_inner)]

#[derive(Debug)]
struct List {
    v: i32,
    next: Option<Box<Self>>,
}

impl List {
    fn new(mut input: Vec<i32>) -> Option<Self> {
        let mut this = if let Some(i) = input.pop() {
            Self { v: i, next: None }
        } else {
            return None;
        };

        loop {
            if let Some(i) = input.pop() {
                this = Self {
                    v: i,
                    next: Some(Box::new(this)),
                }
            } else {
                return Some(this);
            };
        }
    }

    fn new_helper(mut input: Vec<Self>) -> Result<Self, String> {
        let mut this = match input.pop() {
            Some(tail) => tail,
            None => return Err("are you fucking kidding me?".to_string()),
        };

        loop {
            if let Some(mut tail) = input.pop() {
                tail.next = Some(Box::new(this));
                this = tail;
            } else {
                return Ok(this);
            };
        }
    }

    fn for_dear_uncle_shi(self, k: usize) -> Self {
        let mut head = self;
        let mut next = head.next.take();
        let mut cache = vec![];
        for ind in 0..k {
            cache.push(head);
            match next {
                Some(n) => {
                    head = *n;
                    next = head.next.take();
                }
                None => {
                    if ind != k - 1 {
                        return Self::new_helper(cache).unwrap();
                    } else {
                        cache.reverse();
                        return Self::new_helper(cache).unwrap();
                    }
                }
            }
        }

        head.next = next;
        cache[0].next = Some(Box::new(head.for_dear_uncle_shi(k)));
        cache.reverse();
        Self::new_helper(cache).unwrap()
    }
}

fn main() {
    // dbg!(List::new(vec![1, 2, 3, 4, 5, 6, 7, 8]));
    // dbg!(List::new_helper(vec![
    //     List { v: 3, next: None },
    //     List { v: 2, next: None },
    //     List { v: 1, next: None }
    // ]));

    let a = List::new(vec![1, 2, 3, 4, 5, 6]).unwrap();
    dbg!(a.for_dear_uncle_shi(3));
    let a = List::new(vec![1, 2, 3, 4, 5, 6]).unwrap();
    dbg!(a.for_dear_uncle_shi(4));
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Read;
use std::io::Write;
use std::io::Seek;
use std::path::Path;
use std::process::Command;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_source, read_jumps};
use tools::format::format_file_data;
use tools::config;
use tools::languages;
use languages::FormatAs;

use tools::output::{PanelItem, PanelSection};

fn format_documentation(input_fname: &str, output_fname: &str) {
    let _ = Command::new("pandoc")
        .arg("--css")
        .arg("/static/css/pandoc.css")
        .arg("-o")
        .arg(output_fname)
        .arg("-w")
        .arg("html")
        .arg(input_fname)
        .status();
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let (base_args, fname_args) = args.split_at(3);

    let cfg = config::load(&base_args[1], false);
    println!("Config file read");

    let tree_name = &base_args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let jumps_fname = format!("{}/jumps", tree_config.paths.index_path);
    //let jumps : std::collections::HashMap<String, tools::analysis::Jump> = std::collections::HashMap::new();
    let jumps = read_jumps(&jumps_fname);
    println!("Jumps read");

    let (blame_commit, head_oid) = match &tree_config.git {
        &Some(ref git) => {
            let head_oid = git.repo.refname_to_id("HEAD").unwrap();
            let blame_oid = git.blame_repo.refname_to_id("HEAD").unwrap();
            let blame_commit = Some(git.blame_repo.find_commit(blame_oid).unwrap());
            (blame_commit, Some(head_oid))
        },
        &None => (None, None),
    };
    let blame_commit_ref = match blame_commit { Some(ref bc) => Some(bc), None => None };

    for path in fname_args {
        println!("File {}", path);

        let output_fname = format!("{}/file/{}", tree_config.paths.index_path, path);
        let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);

        let format = languages::select_formatting(path);
        match format {
            FormatAs::FormatDoc(_) => {
                let _ = format_documentation(&source_fname, &output_fname);
                continue;
            },
            _ => {},
        };

        let output_file = File::create(output_fname).unwrap();
        let mut writer = BufWriter::new(output_file);

        let source_file = match File::open(source_fname.clone()) {
            Ok(f) => f,
            Err(_) => {
                println!("Unable to open file");
                continue;
            },
        };

        let p = Path::new(&source_fname);
        let metadata = fs::symlink_metadata(p).unwrap();
        if metadata.file_type().is_symlink() {
            let dest = fs::read_link(p).unwrap();
            write!(writer, "Symlink to {}", dest.to_str().unwrap()).unwrap();
            continue;
        }

        let mut reader = BufReader::new(&source_file);

        match format {
            FormatAs::Binary => {
                let _ = io::copy(&mut reader, &mut writer);
                continue;
            },
            _ => {},
        };

        let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
        let analysis = read_analysis(&analysis_fname, &read_source);

        let mut input = String::new();
        match reader.read_to_string(&mut input) {
            Ok(_) => {},
            Err(_) => {
                let mut bytes = Vec::new();
                reader.seek(std::io::SeekFrom::Start(0)).unwrap();
                match reader.read_to_end(&mut bytes) {
                    Ok(_) => {
                        input.push_str(&bytes.iter().map(|c| *c as char).collect::<String>());
                    },
                    Err(e) => {
                        println!("Unable to read file: {:?}", e);
                        continue;
                    }
                }
            }
        }

        let panel = if path.contains("__GENERATED__") {
            vec![]
        } else if let Some(oid) = head_oid {
            vec![PanelSection {
                name: "Revision control".to_owned(),
                items: vec![PanelItem {
                    title: "Permalink".to_owned(),
                    link: format!("/{}/rev/{}/{}", tree_name, oid, path),
                    update_link_lineno: true,
                }, PanelItem {
                    title: "Log".to_owned(),
                    link: format!("https://hg.mozilla.org/mozilla-central/log/tip/{}", path),
                    update_link_lineno: false,
                 }, PanelItem {
                    title: "Raw".to_owned(),
                    link: format!("https://hg.mozilla.org/mozilla-central/raw-file/{}/{}", oid, path),
                    update_link_lineno: false,
                }, PanelItem {
                    title: "Blame".to_owned(),
                    link: "javascript:alert('Hover over the gray bar on the left to see blame information.')".to_owned(),
                    update_link_lineno: false,
                }],
            }]
        } else {
            vec![]
        };

        format_file_data(&cfg,
                         tree_name,
                         &panel,
                         None,
                         blame_commit_ref,
                         path,
                         input,
                         &jumps,
                         &analysis,
                         &mut writer).unwrap();
    }
}
<commit_msg>Use GitHub over hg.m.o for raw file links<commit_after>use std::env;
use std::fs;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Read;
use std::io::Write;
use std::io::Seek;
use std::path::Path;
use std::process::Command;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_source, read_jumps};
use tools::format::format_file_data;
use tools::config;
use tools::languages;
use languages::FormatAs;

use tools::output::{PanelItem, PanelSection};

fn format_documentation(input_fname: &str, output_fname: &str) {
    let _ = Command::new("pandoc")
        .arg("--css")
        .arg("/static/css/pandoc.css")
        .arg("-o")
        .arg(output_fname)
        .arg("-w")
        .arg("html")
        .arg(input_fname)
        .status();
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let (base_args, fname_args) = args.split_at(3);

    let cfg = config::load(&base_args[1], false);
    println!("Config file read");

    let tree_name = &base_args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let jumps_fname = format!("{}/jumps", tree_config.paths.index_path);
    //let jumps : std::collections::HashMap<String, tools::analysis::Jump> = std::collections::HashMap::new();
    let jumps = read_jumps(&jumps_fname);
    println!("Jumps read");

    let (blame_commit, head_oid) = match &tree_config.git {
        &Some(ref git) => {
            let head_oid = git.repo.refname_to_id("HEAD").unwrap();
            let blame_oid = git.blame_repo.refname_to_id("HEAD").unwrap();
            let blame_commit = Some(git.blame_repo.find_commit(blame_oid).unwrap());
            (blame_commit, Some(head_oid))
        },
        &None => (None, None),
    };
    let blame_commit_ref = match blame_commit { Some(ref bc) => Some(bc), None => None };

    for path in fname_args {
        println!("File {}", path);

        let output_fname = format!("{}/file/{}", tree_config.paths.index_path, path);
        let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);

        let format = languages::select_formatting(path);
        match format {
            FormatAs::FormatDoc(_) => {
                let _ = format_documentation(&source_fname, &output_fname);
                continue;
            },
            _ => {},
        };

        let output_file = File::create(output_fname).unwrap();
        let mut writer = BufWriter::new(output_file);

        let source_file = match File::open(source_fname.clone()) {
            Ok(f) => f,
            Err(_) => {
                println!("Unable to open file");
                continue;
            },
        };

        let p = Path::new(&source_fname);
        let metadata = fs::symlink_metadata(p).unwrap();
        if metadata.file_type().is_symlink() {
            let dest = fs::read_link(p).unwrap();
            write!(writer, "Symlink to {}", dest.to_str().unwrap()).unwrap();
            continue;
        }

        let mut reader = BufReader::new(&source_file);

        match format {
            FormatAs::Binary => {
                let _ = io::copy(&mut reader, &mut writer);
                continue;
            },
            _ => {},
        };

        let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
        let analysis = read_analysis(&analysis_fname, &read_source);

        let mut input = String::new();
        match reader.read_to_string(&mut input) {
            Ok(_) => {},
            Err(_) => {
                let mut bytes = Vec::new();
                reader.seek(std::io::SeekFrom::Start(0)).unwrap();
                match reader.read_to_end(&mut bytes) {
                    Ok(_) => {
                        input.push_str(&bytes.iter().map(|c| *c as char).collect::<String>());
                    },
                    Err(e) => {
                        println!("Unable to read file: {:?}", e);
                        continue;
                    }
                }
            }
        }

        let panel = if path.contains("__GENERATED__") {
            vec![]
        } else if let Some(oid) = head_oid {
            vec![PanelSection {
                name: "Revision control".to_owned(),
                items: vec![PanelItem {
                    title: "Permalink".to_owned(),
                    link: format!("/{}/rev/{}/{}", tree_name, oid, path),
                    update_link_lineno: true,
                }, PanelItem {
                    title: "Log".to_owned(),
                    link: format!("https://hg.mozilla.org/mozilla-central/log/tip/{}", path),
                    update_link_lineno: false,
                 }, PanelItem {
                    title: "Raw".to_owned(),
                    link: format!("https://raw.githubusercontent.com/mozilla/gecko-dev/{}/{}", oid, path),
                    update_link_lineno: false,
                }, PanelItem {
                    title: "Blame".to_owned(),
                    link: "javascript:alert('Hover over the gray bar on the left to see blame information.')".to_owned(),
                    update_link_lineno: false,
                }],
            }]
        } else {
            vec![]
        };

        format_file_data(&cfg,
                         tree_name,
                         &panel,
                         None,
                         blame_commit_ref,
                         path,
                         input,
                         &jumps,
                         &analysis,
                         &mut writer).unwrap();
    }
}
<|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/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId};
use canvas_traits::webgl::{WebGLResult, WebGLError, webgl_channel};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLFramebufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::webglobject::WebGLObject;
use dom::webglrenderbuffer::WebGLRenderbuffer;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom::webgltexture::WebGLTexture;
use dom_struct::dom_struct;
use std::cell::Cell;

#[must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
enum WebGLFramebufferAttachment {
    Renderbuffer(Dom<WebGLRenderbuffer>),
    Texture { texture: Dom<WebGLTexture>, level: i32 },
}

#[derive(Clone, JSTraceable, MallocSizeOf)]
pub enum WebGLFramebufferAttachmentRoot {
    Renderbuffer(DomRoot<WebGLRenderbuffer>),
    Texture(DomRoot<WebGLTexture>),
}

#[dom_struct]
pub struct WebGLFramebuffer {
    webgl_object: WebGLObject,
    id: WebGLFramebufferId,
    /// target can only be gl::FRAMEBUFFER at the moment
    target: Cell<Option<u32>>,
    is_deleted: Cell<bool>,
    size: Cell<Option<(i32, i32)>>,
    status: Cell<u32>,
    // The attachment points for textures and renderbuffers on this
    // FBO.
    color: DomRefCell<Option<WebGLFramebufferAttachment>>,
    depth: DomRefCell<Option<WebGLFramebufferAttachment>>,
    stencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
    depthstencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
}

impl WebGLFramebuffer {
    fn new_inherited(context: &WebGLRenderingContext, id: WebGLFramebufferId) -> Self {
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            target: Cell::new(None),
            is_deleted: Cell::new(false),
            size: Cell::new(None),
            status: Cell::new(constants::FRAMEBUFFER_UNSUPPORTED),
            color: DomRefCell::new(None),
            depth: DomRefCell::new(None),
            stencil: DomRefCell::new(None),
            depthstencil: DomRefCell::new(None),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateFramebuffer(sender));
        receiver.recv().unwrap().map(|id| WebGLFramebuffer::new(context, id))
    }

    pub fn new(
        context: &WebGLRenderingContext,
        id: WebGLFramebufferId,
    ) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLFramebuffer::new_inherited(context, id)),
            &*context.global(),
            WebGLFramebufferBinding::Wrap,
        )
    }
}

impl WebGLFramebuffer {
    pub fn id(&self) -> WebGLFramebufferId {
        self.id
    }

    pub fn bind(&self, target: u32) {
        // Update the framebuffer status on binding.  It may have
        // changed if its attachments were resized or deleted while
        // we've been unbound.
        self.update_status();

        self.target.set(Some(target));
        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Explicit(self.id)),
        );
    }

    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);
            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteFramebuffer(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn size(&self) -> Option<(i32, i32)> {
        self.size.get()
    }

    fn update_status(&self) {
        let c = self.color.borrow();
        let z = self.depth.borrow();
        let s = self.stencil.borrow();
        let zs = self.depthstencil.borrow();
        let has_c = c.is_some();
        let has_z = z.is_some();
        let has_s = s.is_some();
        let has_zs = zs.is_some();
        let attachments = [&*c, &*z, &*s, &*zs];

        // From the WebGL spec, 6.6 ("Framebuffer Object Attachments"):
        //
        //    "In the WebGL API, it is an error to concurrently attach
        //     renderbuffers to the following combinations of
        //     attachment points:
        //
        //     DEPTH_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
        //     STENCIL_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
        //     DEPTH_ATTACHMENT + STENCIL_ATTACHMENT
        //
        //     If any of the constraints above are violated, then:
        //
        //     checkFramebufferStatus must return FRAMEBUFFER_UNSUPPORTED."
        if (has_zs && (has_z || has_s)) ||
            (has_z && has_s) {
            self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
            return;
        }

        let mut fb_size = None;
        for attachment in &attachments {
            // Get the size of this attachment.
            let size = match **attachment {
                Some(WebGLFramebufferAttachment::Renderbuffer(ref att_rb)) => {
                    att_rb.size()
                }
                Some(WebGLFramebufferAttachment::Texture { texture: ref att_tex, level } ) => {
                    let info = att_tex.image_info_at_face(0, level as u32);
                    Some((info.width() as i32, info.height() as i32))
                }
                None => None,
            };

            // Make sure that, if we've found any other attachment,
            // that the size matches.
            if size.is_some() {
                if fb_size.is_some() && size != fb_size {
                    self.status.set(constants::FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
                    return;
                } else {
                    fb_size = size;
                }
            }
        }
        self.size.set(fb_size);

        if has_c || has_z || has_zs || has_s {
            if self.size.get().map_or(false, |(w, h)| w != 0 && h != 0) {
                self.status.set(constants::FRAMEBUFFER_COMPLETE);
            } else {
                self.status.set(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
            }
        } else {
            self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
        }
    }

    pub fn check_status(&self) -> u32 {
        return self.status.get();
    }

    pub fn renderbuffer(&self, attachment: u32, rb: Option<&WebGLRenderbuffer>) -> WebGLResult<()> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return Err(WebGLError::InvalidEnum),
        };

        let rb_id = match rb {
            Some(rb) => {
                *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Renderbuffer(Dom::from_ref(rb)));
                Some(rb.id())
            }

            _ => {
                *binding.borrow_mut() = None;
                None
            }
        };

        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::FramebufferRenderbuffer(
                constants::FRAMEBUFFER,
                attachment,
                constants::RENDERBUFFER,
                rb_id,
            ),
        );

        self.update_status();
        Ok(())
    }

    pub fn attachment(&self, attachment: u32) -> Option<WebGLFramebufferAttachmentRoot> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return None,
        };

        binding.borrow().as_ref().map(|bin| {
            match bin {
                &WebGLFramebufferAttachment::Renderbuffer(ref rb) =>
                    WebGLFramebufferAttachmentRoot::Renderbuffer(DomRoot::from_ref(&rb)),
                &WebGLFramebufferAttachment::Texture { ref texture, .. } =>
                    WebGLFramebufferAttachmentRoot::Texture(DomRoot::from_ref(&texture)),
            }
        })
    }

    pub fn texture2d(&self, attachment: u32, textarget: u32, texture: Option<&WebGLTexture>,
                     level: i32) -> WebGLResult<()> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return Err(WebGLError::InvalidEnum),
        };

        let tex_id = match texture {
            // Note, from the GLES 2.0.25 spec, page 113:
            //      "If texture is zero, then textarget and level are ignored."
            Some(texture) => {
                // From the GLES 2.0.25 spec, page 113:
                //
                //     "level specifies the mipmap level of the texture image
                //      to be attached to the framebuffer and must be
                //      0. Otherwise, INVALID_VALUE is generated."
                if level != 0 {
                    return Err(WebGLError::InvalidValue);
                }

                //     "If texture is not zero, then texture must either
                //      name an existing texture object with an target of
                //      textarget, or texture must name an existing cube
                //      map texture and textarget must be one of:
                //      TEXTURE_CUBE_MAP_POSITIVE_X,
                //      TEXTURE_CUBE_MAP_POSITIVE_Y,
                //      TEXTURE_CUBE_MAP_POSITIVE_Z,
                //      TEXTURE_CUBE_MAP_NEGATIVE_X,
                //      TEXTURE_CUBE_MAP_NEGATIVE_Y, or
                //      TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise,
                //      INVALID_OPERATION is generated."
                let is_cube = match textarget {
                    constants::TEXTURE_2D => false,

                    constants::TEXTURE_CUBE_MAP_POSITIVE_X => true,
                    constants::TEXTURE_CUBE_MAP_POSITIVE_Y => true,
                    constants::TEXTURE_CUBE_MAP_POSITIVE_Z => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_X => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => true,

                    _ => return Err(WebGLError::InvalidEnum),
                };

                match texture.target() {
                    Some(constants::TEXTURE_CUBE_MAP) if is_cube => {}
                    Some(_) if !is_cube => {}
                    _ => return Err(WebGLError::InvalidOperation),
                }

                *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Texture {
                    texture: Dom::from_ref(texture),
                    level: level }
                );

                Some(texture.id())
            }

            _ => {
                *binding.borrow_mut() = None;
                None
            }
        };

        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::FramebufferTexture2D(
                constants::FRAMEBUFFER,
                attachment,
                textarget,
                tex_id,
                level,
            ),
        );

        self.update_status();
        Ok(())
    }

    fn with_matching_renderbuffers<F>(&self, rb: &WebGLRenderbuffer, mut closure: F)
        where F: FnMut(&DomRefCell<Option<WebGLFramebufferAttachment>>)
    {
        let attachments = [&self.color,
                           &self.depth,
                           &self.stencil,
                           &self.depthstencil];

        for attachment in &attachments {
            let matched = {
                match *attachment.borrow() {
                    Some(WebGLFramebufferAttachment::Renderbuffer(ref att_rb))
                        if rb.id() == att_rb.id() => true,
                    _ => false,
                }
            };

            if matched {
                closure(attachment);
            }
        }
    }

    fn with_matching_textures<F>(&self, texture: &WebGLTexture, mut closure: F)
        where F: FnMut(&DomRefCell<Option<WebGLFramebufferAttachment>>)
    {
        let attachments = [&self.color,
                           &self.depth,
                           &self.stencil,
                           &self.depthstencil];

        for attachment in &attachments {
            let matched = {
                match *attachment.borrow() {
                    Some(WebGLFramebufferAttachment::Texture { texture: ref att_texture, .. })
                        if texture.id() == att_texture.id() => true,
                    _ => false,
                }
            };

            if matched {
                closure(attachment);
            }
        }
    }

    pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) {
        self.with_matching_renderbuffers(rb, |att| {
            *att.borrow_mut() = None;
            self.update_status();
        });
    }

    pub fn detach_texture(&self, texture: &WebGLTexture) {
        self.with_matching_textures(texture, |att| {
            *att.borrow_mut() = None;
            self.update_status();
        });
    }

    pub fn invalidate_renderbuffer(&self, rb: &WebGLRenderbuffer) {
        self.with_matching_renderbuffers(rb, |_att| {
            self.update_status();
        });
    }

    pub fn invalidate_texture(&self, texture: &WebGLTexture) {
        self.with_matching_textures(texture, |_att| {
            self.update_status();
        });
    }

    pub fn target(&self) -> Option<u32> {
        self.target.get()
    }
}

impl Drop for WebGLFramebuffer {
    fn drop(&mut self) {
        self.delete();
    }
}
<commit_msg>webgl: Mark framebuffers as incomplete if attachments do not meet format requirements.<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/. */

// https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
use canvas_traits::webgl::{WebGLCommand, WebGLFramebufferBindingRequest, WebGLFramebufferId};
use canvas_traits::webgl::{WebGLResult, WebGLError, webgl_channel};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::WebGLFramebufferBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::webglobject::WebGLObject;
use dom::webglrenderbuffer::WebGLRenderbuffer;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom::webgltexture::WebGLTexture;
use dom_struct::dom_struct;
use std::cell::Cell;

#[must_root]
#[derive(Clone, JSTraceable, MallocSizeOf)]
enum WebGLFramebufferAttachment {
    Renderbuffer(Dom<WebGLRenderbuffer>),
    Texture { texture: Dom<WebGLTexture>, level: i32 },
}

#[derive(Clone, JSTraceable, MallocSizeOf)]
pub enum WebGLFramebufferAttachmentRoot {
    Renderbuffer(DomRoot<WebGLRenderbuffer>),
    Texture(DomRoot<WebGLTexture>),
}

#[dom_struct]
pub struct WebGLFramebuffer {
    webgl_object: WebGLObject,
    id: WebGLFramebufferId,
    /// target can only be gl::FRAMEBUFFER at the moment
    target: Cell<Option<u32>>,
    is_deleted: Cell<bool>,
    size: Cell<Option<(i32, i32)>>,
    status: Cell<u32>,
    // The attachment points for textures and renderbuffers on this
    // FBO.
    color: DomRefCell<Option<WebGLFramebufferAttachment>>,
    depth: DomRefCell<Option<WebGLFramebufferAttachment>>,
    stencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
    depthstencil: DomRefCell<Option<WebGLFramebufferAttachment>>,
}

impl WebGLFramebuffer {
    fn new_inherited(context: &WebGLRenderingContext, id: WebGLFramebufferId) -> Self {
        Self {
            webgl_object: WebGLObject::new_inherited(context),
            id: id,
            target: Cell::new(None),
            is_deleted: Cell::new(false),
            size: Cell::new(None),
            status: Cell::new(constants::FRAMEBUFFER_UNSUPPORTED),
            color: DomRefCell::new(None),
            depth: DomRefCell::new(None),
            stencil: DomRefCell::new(None),
            depthstencil: DomRefCell::new(None),
        }
    }

    pub fn maybe_new(context: &WebGLRenderingContext) -> Option<DomRoot<Self>> {
        let (sender, receiver) = webgl_channel().unwrap();
        context.send_command(WebGLCommand::CreateFramebuffer(sender));
        receiver.recv().unwrap().map(|id| WebGLFramebuffer::new(context, id))
    }

    pub fn new(
        context: &WebGLRenderingContext,
        id: WebGLFramebufferId,
    ) -> DomRoot<Self> {
        reflect_dom_object(
            Box::new(WebGLFramebuffer::new_inherited(context, id)),
            &*context.global(),
            WebGLFramebufferBinding::Wrap,
        )
    }
}

impl WebGLFramebuffer {
    pub fn id(&self) -> WebGLFramebufferId {
        self.id
    }

    pub fn bind(&self, target: u32) {
        // Update the framebuffer status on binding.  It may have
        // changed if its attachments were resized or deleted while
        // we've been unbound.
        self.update_status();

        self.target.set(Some(target));
        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::BindFramebuffer(target, WebGLFramebufferBindingRequest::Explicit(self.id)),
        );
    }

    pub fn delete(&self) {
        if !self.is_deleted.get() {
            self.is_deleted.set(true);
            self.upcast::<WebGLObject>()
                .context()
                .send_command(WebGLCommand::DeleteFramebuffer(self.id));
        }
    }

    pub fn is_deleted(&self) -> bool {
        self.is_deleted.get()
    }

    pub fn size(&self) -> Option<(i32, i32)> {
        self.size.get()
    }

    fn update_status(&self) {
        let c = self.color.borrow();
        let z = self.depth.borrow();
        let s = self.stencil.borrow();
        let zs = self.depthstencil.borrow();
        let has_c = c.is_some();
        let has_z = z.is_some();
        let has_s = s.is_some();
        let has_zs = zs.is_some();
        let attachments = [&*c, &*z, &*s, &*zs];
        let attachment_constraints = [
            &[constants::RGBA4, constants::RGB5_A1, constants::RGB565][..],
            &[constants::DEPTH_COMPONENT16][..],
            &[constants::STENCIL_INDEX8][..],
            &[constants::DEPTH_STENCIL][..],
        ];

        // From the WebGL spec, 6.6 ("Framebuffer Object Attachments"):
        //
        //    "In the WebGL API, it is an error to concurrently attach
        //     renderbuffers to the following combinations of
        //     attachment points:
        //
        //     DEPTH_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
        //     STENCIL_ATTACHMENT + DEPTH_STENCIL_ATTACHMENT
        //     DEPTH_ATTACHMENT + STENCIL_ATTACHMENT
        //
        //     If any of the constraints above are violated, then:
        //
        //     checkFramebufferStatus must return FRAMEBUFFER_UNSUPPORTED."
        if (has_zs && (has_z || has_s)) ||
            (has_z && has_s) {
            self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
            return;
        }

        let mut fb_size = None;
        for (attachment, constraints) in attachments.iter().zip(&attachment_constraints) {
            // Get the size of this attachment.
            let (format, size) = match **attachment {
                Some(WebGLFramebufferAttachment::Renderbuffer(ref att_rb)) => {
                    (Some(att_rb.internal_format()), att_rb.size())
                }
                Some(WebGLFramebufferAttachment::Texture { texture: ref att_tex, level } ) => {
                    let info = att_tex.image_info_at_face(0, level as u32);
                    (info.data_type().map(|t| t.as_gl_constant()),
                     Some((info.width() as i32, info.height() as i32)))
                }
                None => (None, None),
            };

            // Make sure that, if we've found any other attachment,
            // that the size matches.
            if size.is_some() {
                if fb_size.is_some() && size != fb_size {
                    self.status.set(constants::FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
                    return;
                } else {
                    fb_size = size;
                }
            }

            if let Some(format) = format {
                if constraints.iter().all(|c| *c != format) {
                    self.status.set(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
                    return;
                }
            }
        }
        self.size.set(fb_size);

        if has_c || has_z || has_zs || has_s {
            if self.size.get().map_or(false, |(w, h)| w != 0 && h != 0) {
                self.status.set(constants::FRAMEBUFFER_COMPLETE);
            } else {
                self.status.set(constants::FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
            }
        } else {
            self.status.set(constants::FRAMEBUFFER_UNSUPPORTED);
        }
    }

    pub fn check_status(&self) -> u32 {
        return self.status.get();
    }

    pub fn renderbuffer(&self, attachment: u32, rb: Option<&WebGLRenderbuffer>) -> WebGLResult<()> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return Err(WebGLError::InvalidEnum),
        };

        let rb_id = match rb {
            Some(rb) => {
                *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Renderbuffer(Dom::from_ref(rb)));
                Some(rb.id())
            }

            _ => {
                *binding.borrow_mut() = None;
                None
            }
        };

        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::FramebufferRenderbuffer(
                constants::FRAMEBUFFER,
                attachment,
                constants::RENDERBUFFER,
                rb_id,
            ),
        );

        self.update_status();
        Ok(())
    }

    pub fn attachment(&self, attachment: u32) -> Option<WebGLFramebufferAttachmentRoot> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return None,
        };

        binding.borrow().as_ref().map(|bin| {
            match bin {
                &WebGLFramebufferAttachment::Renderbuffer(ref rb) =>
                    WebGLFramebufferAttachmentRoot::Renderbuffer(DomRoot::from_ref(&rb)),
                &WebGLFramebufferAttachment::Texture { ref texture, .. } =>
                    WebGLFramebufferAttachmentRoot::Texture(DomRoot::from_ref(&texture)),
            }
        })
    }

    pub fn texture2d(&self, attachment: u32, textarget: u32, texture: Option<&WebGLTexture>,
                     level: i32) -> WebGLResult<()> {
        let binding = match attachment {
            constants::COLOR_ATTACHMENT0 => &self.color,
            constants::DEPTH_ATTACHMENT => &self.depth,
            constants::STENCIL_ATTACHMENT => &self.stencil,
            constants::DEPTH_STENCIL_ATTACHMENT => &self.depthstencil,
            _ => return Err(WebGLError::InvalidEnum),
        };

        let tex_id = match texture {
            // Note, from the GLES 2.0.25 spec, page 113:
            //      "If texture is zero, then textarget and level are ignored."
            Some(texture) => {
                // From the GLES 2.0.25 spec, page 113:
                //
                //     "level specifies the mipmap level of the texture image
                //      to be attached to the framebuffer and must be
                //      0. Otherwise, INVALID_VALUE is generated."
                if level != 0 {
                    return Err(WebGLError::InvalidValue);
                }

                //     "If texture is not zero, then texture must either
                //      name an existing texture object with an target of
                //      textarget, or texture must name an existing cube
                //      map texture and textarget must be one of:
                //      TEXTURE_CUBE_MAP_POSITIVE_X,
                //      TEXTURE_CUBE_MAP_POSITIVE_Y,
                //      TEXTURE_CUBE_MAP_POSITIVE_Z,
                //      TEXTURE_CUBE_MAP_NEGATIVE_X,
                //      TEXTURE_CUBE_MAP_NEGATIVE_Y, or
                //      TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise,
                //      INVALID_OPERATION is generated."
                let is_cube = match textarget {
                    constants::TEXTURE_2D => false,

                    constants::TEXTURE_CUBE_MAP_POSITIVE_X => true,
                    constants::TEXTURE_CUBE_MAP_POSITIVE_Y => true,
                    constants::TEXTURE_CUBE_MAP_POSITIVE_Z => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_X => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => true,
                    constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => true,

                    _ => return Err(WebGLError::InvalidEnum),
                };

                match texture.target() {
                    Some(constants::TEXTURE_CUBE_MAP) if is_cube => {}
                    Some(_) if !is_cube => {}
                    _ => return Err(WebGLError::InvalidOperation),
                }

                *binding.borrow_mut() = Some(WebGLFramebufferAttachment::Texture {
                    texture: Dom::from_ref(texture),
                    level: level }
                );

                Some(texture.id())
            }

            _ => {
                *binding.borrow_mut() = None;
                None
            }
        };

        self.upcast::<WebGLObject>().context().send_command(
            WebGLCommand::FramebufferTexture2D(
                constants::FRAMEBUFFER,
                attachment,
                textarget,
                tex_id,
                level,
            ),
        );

        self.update_status();
        Ok(())
    }

    fn with_matching_renderbuffers<F>(&self, rb: &WebGLRenderbuffer, mut closure: F)
        where F: FnMut(&DomRefCell<Option<WebGLFramebufferAttachment>>)
    {
        let attachments = [&self.color,
                           &self.depth,
                           &self.stencil,
                           &self.depthstencil];

        for attachment in &attachments {
            let matched = {
                match *attachment.borrow() {
                    Some(WebGLFramebufferAttachment::Renderbuffer(ref att_rb))
                        if rb.id() == att_rb.id() => true,
                    _ => false,
                }
            };

            if matched {
                closure(attachment);
            }
        }
    }

    fn with_matching_textures<F>(&self, texture: &WebGLTexture, mut closure: F)
        where F: FnMut(&DomRefCell<Option<WebGLFramebufferAttachment>>)
    {
        let attachments = [&self.color,
                           &self.depth,
                           &self.stencil,
                           &self.depthstencil];

        for attachment in &attachments {
            let matched = {
                match *attachment.borrow() {
                    Some(WebGLFramebufferAttachment::Texture { texture: ref att_texture, .. })
                        if texture.id() == att_texture.id() => true,
                    _ => false,
                }
            };

            if matched {
                closure(attachment);
            }
        }
    }

    pub fn detach_renderbuffer(&self, rb: &WebGLRenderbuffer) {
        self.with_matching_renderbuffers(rb, |att| {
            *att.borrow_mut() = None;
            self.update_status();
        });
    }

    pub fn detach_texture(&self, texture: &WebGLTexture) {
        self.with_matching_textures(texture, |att| {
            *att.borrow_mut() = None;
            self.update_status();
        });
    }

    pub fn invalidate_renderbuffer(&self, rb: &WebGLRenderbuffer) {
        self.with_matching_renderbuffers(rb, |_att| {
            self.update_status();
        });
    }

    pub fn invalidate_texture(&self, texture: &WebGLTexture) {
        self.with_matching_textures(texture, |_att| {
            self.update_status();
        });
    }

    pub fn target(&self) -> Option<u32> {
        self.target.get()
    }
}

impl Drop for WebGLFramebuffer {
    fn drop(&mut self) {
        self.delete();
    }
}
<|endoftext|>


<commit_before>use {TypedDecider, DeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision, Threadsafe,
     Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

#[derive(Debug, Clone)]
/// Implements the virtual scheduling description of the Generic Cell
/// Rate Algorithm, attributed to ITU-T in recommendation I.371
/// Traffic control and congestion control in B-ISDN; from
/// [Wikipedia](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm).
///
///
/// While algorithms like leaky-bucket rate limiters allow cells to be
/// distributed across time in any way, GCRA is a rate-limiting *and*
/// traffic-shaping algorithm. It mandates that a minimum amount of
/// time passes between cells being measured. For example, if your API
/// mandates that only 20 requests can be made per second, GCRA will
/// ensure that each request is at least 50ms apart from the previous
/// request. This makes GCRA suitable for shaping traffic in
/// networking and telecom equipment (it was initially made for
/// asynchronous transfer mode networks), or for outgoing workloads on
/// *consumers* of attention, e.g. distributing outgoing emails across
/// a day.
///
/// In a blatant side-stepping of the above traffic-shaping criteria,
/// this implementation of GCRA comes with an extension that allows
/// measuring multiple cells at once, assuming that if a pause of
/// `n*(the minimum time between cells)` has passed, we can allow a
/// single big batch of `n` cells through. This assumption may not be
/// correct for your application, but if you depend on GCRA's
/// traffic-shaping properties, it's better to not use the `_n`
/// suffixed check functions.
///
/// # Example
/// In this example, we construct a rate-limiter with the GCR
/// algorithm that can accomodate 20 cells per second. This translates
/// to the GCRA parameters τ=1s, T=50ms (that's 1s / 20 cells).
///
/// ```
/// # use ratelimit_meter::{Decider, GCRA, Decision};
/// # use std::time::{Instant, Duration};
/// let mut limiter = GCRA::for_capacity(20).unwrap().cell_weight(1).unwrap().build();
/// let now = Instant::now();
/// let ms = Duration::from_millis(1);
/// assert_eq!(Decision::Yes, limiter.check_at(now).unwrap()); // the first cell is free
/// for i in 0..20 {
///     // Spam a lot:
///     assert_eq!(Decision::Yes, limiter.check_at(now).unwrap(), "at {}", i);
/// }
/// // We have exceeded the bucket capacity:
/// assert!(!limiter.check_at(now).unwrap().is_compliant());
///
/// // After a sufficient time period, cells are allowed again:
/// assert_eq!(Decision::Yes, limiter.check_at(now + ms*50).unwrap());
pub struct GCRA {
    // The "weight" of a single packet in units of time.
    t: Duration,

    // The "capacity" of the bucket.
    tau: Duration,

    // The theoretical arrival time of the next packet.
    tat: Option<Instant>,
}

/// A builder object that can be used to construct rate-limiters as
/// meters.
pub struct Builder {
    capacity: u32,
    cell_weight: u32,
    time_unit: Duration,
}

/// Constructs a concrete GCRA instance.
impl Builder {
    /// Sets the "weight" of each cell being checked against the
    /// bucket. Each cell fills the bucket by this much.
    pub fn cell_weight<'a>(&'a mut self, weight: u32) -> Result<&'a mut Builder> {
        if self.cell_weight > self.capacity {
            return Err(ErrorKind::InconsistentCapacity(self.capacity, weight).into());
        }
        self.cell_weight = weight;
        Ok(self)
    }

    /// Sets the "unit of time" within which the bucket drains.
    ///
    /// The assumption is that in a period of `time_unit` (if no cells
    /// are being checked), the bucket is fully drained.
    pub fn per<'a>(&'a mut self, time_unit: Duration) -> &'a mut Builder {
        self.time_unit = time_unit;
        self
    }

    /// Builds and returns a thread-safe GCRA decider.
    pub fn build_sync(&self) -> Threadsafe<GCRA> {
        Threadsafe::new(self.build())
    }

    /// Builds a single-threaded GCRA decider.
    pub fn build(&self) -> GCRA {
        GCRA {
            t: (self.time_unit / self.capacity) * self.cell_weight,
            tau: self.time_unit,
            tat: None,
        }
    }
}

impl GCRA {
    /// Constructs a builder object for a GCRA rate-limiter with the
    /// given capacity per second, at cell weight=1. See
    /// [`Builder`](gcra/struct.Builder.html) for options.
    pub fn for_capacity(capacity: u32) -> Result<Builder> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        Ok(Builder {
            capacity: capacity,
            cell_weight: 1,
            time_unit: Duration::from_secs(1),
        })
    }

    /// Constructs a GCRA rate-limiter with the parameters T (the
    /// minimum amount of time that single cells are spaced apart),
    /// tau (τ, the number of cells that fit into this buffer), and an
    /// optional t_at (the earliest instant that the rate-limiter
    /// would accept another cell).
    pub fn with_parameters(t: Duration, tau: Duration, tat: Option<Instant>) -> GCRA {
        GCRA {
            t: t,
            tau: tau,
            tat: tat,
        }
    }
}

impl TypedDecider for GCRA {
    /// In GCRA, negative decisions come with the time at which the
    /// next cell was expected to arrive; client code of GCRA can use
    /// this to decide what to do with the non-conforming cell.
    type T = Instant;
}

impl Decider for GCRA {}

impl DeciderImpl for GCRA {
    /// Tests if a single cell can be accomodated by the
    /// rate-limiter. This is the method described directly in the
    /// GCRA algorithm, and is the fastest.
    fn test_and_update(&mut self, t0: Instant) -> Result<Decision<Instant>> {
        let tat = self.tat.unwrap_or(t0);

        if t0 < tat - self.tau {
            return Ok(Decision::No(tat));
        }
        self.tat = Some(cmp::max(tat, t0) + self.t);
        Ok(Decision::Yes)
    }
}

impl MultiDeciderImpl for GCRA {
    /// Tests if a `n` cells can be accomodated by the rate-limiter
    /// and updates rate limiter state iff they can be.
    ///
    /// As this method is an extension of GCRA (using multiplication),
    /// it is likely not as fast (and not as obviously "right") as the
    /// single-cell variant.
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Instant>> {
        let tat = self.tat.unwrap_or(t0);
        let tat = match n {
            0 => t0,
            1 => tat,
            _ => {
                let weight = self.t * (n - 1);
                if (weight + self.t) > self.tau {
                    // The bucket capacity can never accomodate this request
                    return Err(ErrorKind::InsufficientCapacity(n).into());
                }
                tat + weight
            }
        };

        if t0 < tat - self.tau {
            return Ok(Decision::No(tat));
        }
        let additional_weight = match n {
            0 => Duration::new(0, 0),
            1 => self.t,
            _ => self.t * n,
        };
        self.tat = Some(cmp::max(tat, t0) + additional_weight);
        Ok(Decision::Yes)
    }
}

/// This crate's GCRA implementation also allows checking multiple
/// cells at once, assuming that (counter the traffic-shaping
/// properties of GCRA) if a sufficiently long pause (`n*t`) has
/// occurred between cells, the algorithm can accomodate `n` cells.
///
/// As this assumption does not necessarily hold in all circumstances,
/// users of this trait on GCRA limiters should ensure that this is
/// ok.
impl MultiDecider for GCRA {}

/// Allows converting from a GCRA builder directly into a
/// GCRA decider. Same as
/// [the borrowed implementation](#impl-From<&'a Builder>), except for
/// owned `Builder`s.
/// # Example:
/// ```
/// use ratelimit_meter::{GCRA, Decider, Decision};
/// let mut gcra: GCRA = GCRA::for_capacity(50).unwrap().into();
/// assert_eq!(Decision::Yes, gcra.check().unwrap());
/// ```
impl From<Builder> for GCRA {
    fn from(b: Builder) -> Self {
        b.build()
    }
}

/// Allows converting a GCRA builder directly into a GCRA decider.
/// # Example:
/// ```
/// use ratelimit_meter::{GCRA, Decider, Decision};
/// let mut gcra: GCRA = GCRA::for_capacity(50).unwrap().cell_weight(2).unwrap().into();
/// assert_eq!(Decision::Yes, gcra.check().unwrap());
/// ```
impl<'a> From<&'a mut Builder> for GCRA {
    fn from(b: &'a mut Builder) -> Self {
        b.build()
    }
}
<commit_msg>Implement parameter extraction functions for GCRA<commit_after>use {TypedDecider, DeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision, Threadsafe,
     Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

#[derive(Debug, Clone)]
/// Implements the virtual scheduling description of the Generic Cell
/// Rate Algorithm, attributed to ITU-T in recommendation I.371
/// Traffic control and congestion control in B-ISDN; from
/// [Wikipedia](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm).
///
///
/// While algorithms like leaky-bucket rate limiters allow cells to be
/// distributed across time in any way, GCRA is a rate-limiting *and*
/// traffic-shaping algorithm. It mandates that a minimum amount of
/// time passes between cells being measured. For example, if your API
/// mandates that only 20 requests can be made per second, GCRA will
/// ensure that each request is at least 50ms apart from the previous
/// request. This makes GCRA suitable for shaping traffic in
/// networking and telecom equipment (it was initially made for
/// asynchronous transfer mode networks), or for outgoing workloads on
/// *consumers* of attention, e.g. distributing outgoing emails across
/// a day.
///
/// In a blatant side-stepping of the above traffic-shaping criteria,
/// this implementation of GCRA comes with an extension that allows
/// measuring multiple cells at once, assuming that if a pause of
/// `n*(the minimum time between cells)` has passed, we can allow a
/// single big batch of `n` cells through. This assumption may not be
/// correct for your application, but if you depend on GCRA's
/// traffic-shaping properties, it's better to not use the `_n`
/// suffixed check functions.
///
/// # Example
/// In this example, we construct a rate-limiter with the GCR
/// algorithm that can accomodate 20 cells per second. This translates
/// to the GCRA parameters τ=1s, T=50ms (that's 1s / 20 cells).
///
/// ```
/// # use ratelimit_meter::{Decider, GCRA, Decision};
/// # use std::time::{Instant, Duration};
/// let mut limiter = GCRA::for_capacity(20).unwrap().cell_weight(1).unwrap().build();
/// let now = Instant::now();
/// let ms = Duration::from_millis(1);
/// assert_eq!(Decision::Yes, limiter.check_at(now).unwrap()); // the first cell is free
/// for i in 0..20 {
///     // Spam a lot:
///     assert_eq!(Decision::Yes, limiter.check_at(now).unwrap(), "at {}", i);
/// }
/// // We have exceeded the bucket capacity:
/// assert!(!limiter.check_at(now).unwrap().is_compliant());
///
/// // After a sufficient time period, cells are allowed again:
/// assert_eq!(Decision::Yes, limiter.check_at(now + ms*50).unwrap());
pub struct GCRA {
    // The "weight" of a single packet in units of time.
    t: Duration,

    // The "capacity" of the bucket.
    tau: Duration,

    // The theoretical arrival time of the next packet.
    tat: Option<Instant>,
}

/// A builder object that can be used to construct rate-limiters as
/// meters.
pub struct Builder {
    capacity: u32,
    cell_weight: u32,
    time_unit: Duration,
}

/// Constructs a concrete GCRA instance.
impl Builder {
    /// Sets the "weight" of each cell being checked against the
    /// bucket. Each cell fills the bucket by this much.
    pub fn cell_weight<'a>(&'a mut self, weight: u32) -> Result<&'a mut Builder> {
        if self.cell_weight > self.capacity {
            return Err(ErrorKind::InconsistentCapacity(self.capacity, weight).into());
        }
        self.cell_weight = weight;
        Ok(self)
    }

    /// Sets the "unit of time" within which the bucket drains.
    ///
    /// The assumption is that in a period of `time_unit` (if no cells
    /// are being checked), the bucket is fully drained.
    pub fn per<'a>(&'a mut self, time_unit: Duration) -> &'a mut Builder {
        self.time_unit = time_unit;
        self
    }

    /// Builds and returns a thread-safe GCRA decider.
    pub fn build_sync(&self) -> Threadsafe<GCRA> {
        Threadsafe::new(self.build())
    }

    /// Builds a single-threaded GCRA decider.
    pub fn build(&self) -> GCRA {
        GCRA {
            t: (self.time_unit / self.capacity) * self.cell_weight,
            tau: self.time_unit,
            tat: None,
        }
    }
}

impl GCRA {
    /// Constructs a builder object for a GCRA rate-limiter with the
    /// given capacity per second, at cell weight=1. See
    /// [`Builder`](gcra/struct.Builder.html) for options.
    pub fn for_capacity(capacity: u32) -> Result<Builder> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        Ok(Builder {
            capacity: capacity,
            cell_weight: 1,
            time_unit: Duration::from_secs(1),
        })
    }

    /// Constructs a GCRA rate-limiter with the parameters T (the
    /// minimum amount of time that single cells are spaced apart),
    /// tau (τ, the number of cells that fit into this buffer), and an
    /// optional t_at (the earliest instant that the rate-limiter
    /// would accept another cell).
    pub fn with_parameters(t: Duration, tau: Duration, tat: Option<Instant>) -> GCRA {
        GCRA {
            t: t,
            tau: tau,
            tat: tat,
        }
    }
}

impl TypedDecider for GCRA {
    /// In GCRA, negative decisions come with the time at which the
    /// next cell was expected to arrive; client code of GCRA can use
    /// this to decide what to do with the non-conforming cell.
    type T = Instant;
}

impl Decider for GCRA {}

impl DeciderImpl for GCRA {
    /// Tests if a single cell can be accomodated by the
    /// rate-limiter. This is the method described directly in the
    /// GCRA algorithm, and is the fastest.
    fn test_and_update(&mut self, t0: Instant) -> Result<Decision<Instant>> {
        let tat = self.tat.unwrap_or(t0);

        if t0 < tat - self.tau {
            return Ok(Decision::No(tat));
        }
        self.tat = Some(cmp::max(tat, t0) + self.t);
        Ok(Decision::Yes)
    }
}

impl MultiDeciderImpl for GCRA {
    /// Tests if a `n` cells can be accomodated by the rate-limiter
    /// and updates rate limiter state iff they can be.
    ///
    /// As this method is an extension of GCRA (using multiplication),
    /// it is likely not as fast (and not as obviously "right") as the
    /// single-cell variant.
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Instant>> {
        let tat = self.tat.unwrap_or(t0);
        let tat = match n {
            0 => t0,
            1 => tat,
            _ => {
                let weight = self.t * (n - 1);
                if (weight + self.t) > self.tau {
                    // The bucket capacity can never accomodate this request
                    return Err(ErrorKind::InsufficientCapacity(n).into());
                }
                tat + weight
            }
        };

        if t0 < tat - self.tau {
            return Ok(Decision::No(tat));
        }
        let additional_weight = match n {
            0 => Duration::new(0, 0),
            1 => self.t,
            _ => self.t * n,
        };
        self.tat = Some(cmp::max(tat, t0) + additional_weight);
        Ok(Decision::Yes)
    }
}

/// This crate's GCRA implementation also allows checking multiple
/// cells at once, assuming that (counter the traffic-shaping
/// properties of GCRA) if a sufficiently long pause (`n*t`) has
/// occurred between cells, the algorithm can accomodate `n` cells.
///
/// As this assumption does not necessarily hold in all circumstances,
/// users of this trait on GCRA limiters should ensure that this is
/// ok.
impl MultiDecider for GCRA {}

/// Allows converting from a GCRA builder directly into a
/// GCRA decider. Same as
/// [the borrowed implementation](#impl-From<&'a Builder>), except for
/// owned `Builder`s.
/// # Example:
/// ```
/// use ratelimit_meter::{GCRA, Decider, Decision};
/// let mut gcra: GCRA = GCRA::for_capacity(50).unwrap().into();
/// assert_eq!(Decision::Yes, gcra.check().unwrap());
/// ```
impl From<Builder> for GCRA {
    fn from(b: Builder) -> Self {
        b.build()
    }
}

/// Allows converting a GCRA builder directly into a GCRA decider.
/// # Example:
/// ```
/// use ratelimit_meter::{GCRA, Decider, Decision};
/// let mut gcra: GCRA = GCRA::for_capacity(50).unwrap().cell_weight(2).unwrap().into();
/// assert_eq!(Decision::Yes, gcra.check().unwrap());
/// ```
impl<'a> From<&'a mut Builder> for GCRA {
    fn from(b: &'a mut Builder) -> Self {
        b.build()
    }
}

/// Allows converting a GCRA into a tuple containing its T (the
/// minimum amount of time that single cells are spaced apart), tau
/// (τ, the number of cells that fit into this buffer), and an
/// optional t_at (the earliest instant that the rate-limiter would
/// accept another cell).
///
/// These parameters can be used with
/// [`.with_parameters`](#method.with_parameters) to persist and
/// construct a copy of the GCRA rate-limiter.
impl<'a> Into<(Duration, Duration, Option<Instant>)> for &'a GCRA {
    fn into(self) -> (Duration, Duration, Option<Instant>) {
        (self.t, self.tau, self.tat)
    }
}

/// Allows converting the parameters returned from
/// [`Into<(Duration, Duration, Option<Instant>)>`](#impl-Into<(Duration, Duration, Option<Instant>)>)
/// back into a GCRA.
impl From<(Duration, Duration, Option<Instant>)> for GCRA {
    fn from(params: (Duration, Duration, Option<Instant>)) -> GCRA {
        let (t, tau, tat) = params;
        GCRA::with_parameters(t, tau, tat)
    }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;

use CreationError::{self, OsError};

use winit;

use Api;
use ContextError;
use GlAttributes;
use GlContext;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;

use api::egl;
use api::egl::Context as EglContext;

mod ffi;

pub struct Window {
    context: EglContext,
    winit_window: winit::Window,
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

impl Window {
    pub fn new(events_loop: &winit::EventsLoop,
               _: &WindowAttributes,
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&Window>,
               _: &PlatformSpecificWindowBuilderAttributes,
               winit_builder: winit::WindowBuilder)
               -> Result<Window, CreationError> {
        let winit_window = winit_builder.build(events_loop).unwrap();
        let opengl = opengl.clone().map_sharing(|w| &w.context);
        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }
        let context = try!(EglContext::new(egl::ffi::egl::Egl,
                                           pf_reqs,
                                           &opengl,
                                           egl::NativeDisplay::Android)
            .and_then(|p| p.finish(native_window as *const _)));
        Ok(Window {
            context: context,
            winit_window: winit_window,
        })
    }

    pub fn id(&self) -> winit::WindowId {
        self.winit_window.id()
    }

    pub fn set_title(&self, title: &str) {
        self.winit_window.set_title(title)
    }

    pub fn show(&self) {
        self.winit_window.show()
    }

    pub fn hide(&self) {
        self.winit_window.hide()
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        self.winit_window.get_position()
    }

    pub fn set_position(&self, x: i32, y: i32) {
        self.winit_window.set_position(x, y)
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_points(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size()
    }

    pub fn get_inner_size_pixels(&self) -> Option<(u32, u32)> {
        self.winit_window.get_inner_size().map(|(x, y)| {
            let hidpi = self.hidpi_factor();
            ((x as f32 * hidpi) as u32, (y as f32 * hidpi) as u32)
        })
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.winit_window.get_outer_size()
    }

    pub fn set_inner_size(&self, x: u32, y: u32) {
        self.winit_window.set_inner_size(x, y)
    }

    pub unsafe fn platform_display(&self) -> *mut libc::c_void {
        self.winit_window.platform_display()
    }

    #[inline]
    pub fn as_winit_window(&self) -> &winit::Window {
        &self.winit_window
    }

    #[inline]
    pub fn as_winit_window_mut(&mut self) -> &mut winit::Window {
        &mut self.winit_window
    }

    pub unsafe fn platform_window(&self) -> *mut libc::c_void {
        self.winit_window.platform_window()
    }

    pub fn set_cursor(&self, cursor: winit::MouseCursor) {
        self.winit_window.set_cursor(cursor);
    }

    pub fn hidpi_factor(&self) -> f32 {
        self.winit_window.hidpi_factor()
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        self.winit_window.set_cursor_position(x, y)
    }

    pub fn set_cursor_state(&self, state: winit::CursorState) -> Result<(), String> {
        self.winit_window.set_cursor_state(state)
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl GlContext for Window {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.context.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.context.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.context.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.context.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.context.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.context.get_pixel_format()
    }
}

pub struct HeadlessContext(EglContext);

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(dimensions: (u32, u32),
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&HeadlessContext>,
               _: &PlatformSpecificHeadlessBuilderAttributes)
               -> Result<HeadlessContext, CreationError> {
        let opengl = opengl.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl,
                                           pf_reqs,
                                           &opengl,
                                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl GlContext for HeadlessContext {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<commit_msg>WIP - Begin updating android api to Context redesign. Untested.<commit_after>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;

use CreationError::{self, OsError};

use winit;

use Api;
use ContextError;
use GlAttributes;
use GlContext;
use PixelFormat;
use PixelFormatRequirements;
use WindowAttributes;

use api::egl;
use api::egl::Context as EglContext;

mod ffi;

pub struct Window {
    context: EglContext,
    winit_window: winit::Window,
}

pub struct Context {
    egl_context: EglContext,
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

impl Context {
    pub fn new(
        _window: &winit::Window,
        pf_reqs: &PixelFormatRequirements,
        gl_attr: &GlAttributes<&Context>,
    ) -> Result<Self, CreationError>
    {
        let gl_attr = gl_attr.clone().map_sharing(|w| &w.context);
        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }
        let egl = egl::ffi::egl::Egl;
        let native_display = egl::NativeDisplay::Android;
        let context = try!(EglContext::new(egl, pf_reqs, &gl_attr, native_display)
            .and_then(|p| p.finish(native_window as *const _)));
        Ok(Context { egl_context: context })
    }

    #[inline]
    pub unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.egl_context.make_current()
    }

    #[inline]
    pub fn is_current(&self) -> bool {
        self.egl_context.is_current()
    }

    #[inline]
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        self.egl_context.get_proc_address(addr)
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        self.egl_context.swap_buffers()
    }

    #[inline]
    pub fn get_api(&self) -> Api {
        self.egl_context.get_api()
    }

    #[inline]
    pub fn get_pixel_format(&self) -> PixelFormat {
        self.egl_context.get_pixel_format()
    }
}

pub struct HeadlessContext(EglContext);

impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(dimensions: (u32, u32),
               pf_reqs: &PixelFormatRequirements,
               opengl: &GlAttributes<&HeadlessContext>,
               _: &PlatformSpecificHeadlessBuilderAttributes)
               -> Result<HeadlessContext, CreationError> {
        let opengl = opengl.clone().map_sharing(|c| &c.0);
        let context = try!(EglContext::new(egl::ffi::egl::Egl,
                                           pf_reqs,
                                           &opengl,
                                           egl::NativeDisplay::Android));
        let context = try!(context.finish_pbuffer(dimensions));     // TODO:
        Ok(HeadlessContext(context))
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl GlContext for HeadlessContext {
    #[inline]
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        self.0.make_current()
    }

    #[inline]
    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    #[inline]
    fn get_proc_address(&self, addr: &str) -> *const () {
        self.0.get_proc_address(addr)
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        self.0.swap_buffers()
    }

    #[inline]
    fn get_api(&self) -> Api {
        self.0.get_api()
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        self.0.get_pixel_format()
    }
}
<|endoftext|>


<commit_before>use nix::{
    Error,
    errno::Errno,
    poll::{PollFlags, poll, PollFd},
    unistd::{write, pipe}
};

macro_rules! loop_while_eintr {
    ($poll_expr: expr) => {
        loop {
            match $poll_expr {
                Ok(nfds) => break nfds,
                Err(Error::Sys(Errno::EINTR)) => (),
                Err(e) => panic!(e)
            }
        }
    }
}

#[test]
fn test_poll() {
    let (r, w) = pipe().unwrap();
    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];

    // Poll an idle pipe.  Should timeout
    let nfds = loop_while_eintr!(poll(&mut fds, 100));
    assert_eq!(nfds, 0);
    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));

    write(w, b".").unwrap();

    // Poll a readable pipe.  Should return an event.
    let nfds = poll(&mut fds, 100).unwrap();
    assert_eq!(nfds, 1);
    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
}

// ppoll(2) is the same as poll except for how it handles timeouts and signals.
// Repeating the test for poll(2) should be sufficient to check that our
// bindings are correct.
#[cfg(any(target_os = "android",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "linux"))]
#[test]
fn test_ppoll() {
    use nix::poll::ppoll;
    use nix::sys::signal::SigSet;
    use nix::sys::time::{TimeSpec, TimeValLike};

    let timeout = TimeSpec::milliseconds(1);
    let (r, w) = pipe().unwrap();
    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];

    // Poll an idle pipe.  Should timeout
    let sigset = SigSet::empty();
    let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset));
    assert_eq!(nfds, 0);
    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));

    write(w, b".").unwrap();

    // Poll a readable pipe.  Should return an event.
    let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
    assert_eq!(nfds, 1);
    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
}
<commit_msg>Fix a non_fmt_panic warning with Rustc 1.52.0<commit_after>use nix::{
    Error,
    errno::Errno,
    poll::{PollFlags, poll, PollFd},
    unistd::{write, pipe}
};

macro_rules! loop_while_eintr {
    ($poll_expr: expr) => {
        loop {
            match $poll_expr {
                Ok(nfds) => break nfds,
                Err(Error::Sys(Errno::EINTR)) => (),
                Err(e) => panic!("{}", e)
            }
        }
    }
}

#[test]
fn test_poll() {
    let (r, w) = pipe().unwrap();
    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];

    // Poll an idle pipe.  Should timeout
    let nfds = loop_while_eintr!(poll(&mut fds, 100));
    assert_eq!(nfds, 0);
    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));

    write(w, b".").unwrap();

    // Poll a readable pipe.  Should return an event.
    let nfds = poll(&mut fds, 100).unwrap();
    assert_eq!(nfds, 1);
    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
}

// ppoll(2) is the same as poll except for how it handles timeouts and signals.
// Repeating the test for poll(2) should be sufficient to check that our
// bindings are correct.
#[cfg(any(target_os = "android",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "linux"))]
#[test]
fn test_ppoll() {
    use nix::poll::ppoll;
    use nix::sys::signal::SigSet;
    use nix::sys::time::{TimeSpec, TimeValLike};

    let timeout = TimeSpec::milliseconds(1);
    let (r, w) = pipe().unwrap();
    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];

    // Poll an idle pipe.  Should timeout
    let sigset = SigSet::empty();
    let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset));
    assert_eq!(nfds, 0);
    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));

    write(w, b".").unwrap();

    // Poll a readable pipe.  Should return an event.
    let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
    assert_eq!(nfds, 1);
    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
}
<|endoftext|>


<commit_before>
use std::fmt;

/// A value.
pub trait Value : Sized + fmt::Display
{
    /// Gets the set of values.
    /// TODO: make this an iterator once supported.
    fn subvalues(&self) -> Vec<Self>;

    /// Maps values to other values.
    fn map_subvalues<F>(self, f: F) -> Self
        where F: FnMut(Self) -> Self;

    fn map<F,T>(self, f: F) -> T
        where F: Fn(Self) -> T {
        f(self)
    }

    /// Checks if a single value is critical.
    ///
    /// If a value contains another critical value, it is also a
    /// critical value. Critical values are not removed when dead
    /// code elimination is run.
    fn is_single_critical(&self) -> bool {
        true // conservately mark all values critical by default
    }

    /// Checks if a value is critical.
    ///
    /// Recursively checks whether this value is critical.
    fn is_critical(&self) -> bool {
        self::is_critical_recursive(self)
    }
}

fn is_critical_recursive<V: Value>(value: &V) -> bool {

    let subvalues_critical = value.subvalues().iter().any(|a| is_critical_recursive(a));

    value.is_single_critical() || subvalues_critical
}
<commit_msg>Refactored value criticality checking code<commit_after>
use std::fmt;

/// A value.
pub trait Value : Sized + fmt::Display
{
    /// Gets the set of values.
    /// TODO: make this an iterator once supported.
    fn subvalues(&self) -> Vec<Self>;

    /// Maps values to other values.
    fn map_subvalues<F>(self, f: F) -> Self
        where F: FnMut(Self) -> Self;

    fn map<F,T>(self, f: F) -> T
        where F: Fn(Self) -> T {
        f(self)
    }

    /// Checks if a single value is critical.
    ///
    /// If a value contains another critical value, it is also a
    /// critical value. Critical values are not removed when dead
    /// code elimination is run.
    ///
    /// This does not check if subvalues are critical.
    // TODO: Find a better name.
    fn is_single_critical(&self) -> bool {
        true // conservately mark all values critical by default
    }

    /// Checks if a value is critical.
    ///
    /// Recursively checks whether this value is critical.
    fn is_critical(&self) -> bool {
        let subvalues_critical = self.subvalues().iter().any(|a| a.is_critical());

        self.is_single_critical() || subvalues_critical
    }
}

<|endoftext|>