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

trait Graph {
	type R: PartialOrd<u32>;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a Self::R>> ;
}
trait GraphMut: Graph {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=&'a mut Self::R>>;
}
trait GraphMut2: Graph {
	fn graph_mut2(&mut self) -> &mut Self::R;
}

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

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

	fn constrain(g: Self::Base) -> Result<Self, ()>{
		println!("Default constrain()");
		Self::constrain_single(Self::Constrained::constrain(g)?)
	}
	fn unconstrain(self) -> Self::Base{
		self.unconstrain_single().unconstrain()
	}

}
trait ConstraintMut: Constraint<Base=<Self as ConstraintMut>::BaseMut, Constrained=<Self as ConstraintMut>::ConstrainedMut> + ImplGraphMut {
	type BaseMut:  BaseConstraintMut;
	type ConstrainedMut: ConstraintMut<BaseMut=Self::BaseMut>;
}

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

	fn unconstrain_single(self) -> Self::Constrained { self }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> { println!("Constraint for BaseConstraint constrain_single()");Ok(g)}

	fn unconstrain(self) -> Self::Base { self }
	fn constrain(g: Self::Base) -> Result<Self, ()>{ println!("Constraint for BaseConstraint constrain()");Ok(g) }
}
impl<B: BaseConstraintMut> ConstraintMut for B {
	type BaseMut = Self;
	type ConstrainedMut = Self;
}

struct BaseGraph(u32);
impl BaseGraph {
	fn base_graph_fn(&self) -> u32
	{
		self.0
	}
}
impl Graph for BaseGraph{
	type R = u32;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a u32>> {
		Box::new(vec![&self.0].into_iter())
	}
}
impl GraphMut for BaseGraph {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=&'a mut u32>> {
		Box::new(vec![&mut self.0].into_iter())
	}
}
impl GraphMut2 for BaseGraph {
	fn graph_mut2(&mut self) -> &mut u32 { &mut self.0 }
}
impl ImplGraph for BaseGraph {
	type Graph = Self;

	fn get_graph(&self) -> &Self::Graph {
		self
	}
}
impl ImplGraphMut for BaseGraph {
	fn get_graph_mut(&mut self) -> &mut Self::Graph {
		self
	}
}
impl BaseConstraint for BaseGraph {}
impl BaseConstraintMut for BaseGraph{}

struct Connected<C: Constraint>(C);
impl<C: Constraint> ImplGraph for Connected<C> {
	type Graph = Self;

	fn get_graph(&self) -> &Self::Graph {
		println!("ImplGraph for Connected get_graph()");
		self
	}
}
impl<C: Constraint> ImplGraphMut for Connected<C>  {
	fn get_graph_mut(&mut self) -> &mut Self::Graph {
		self
	}
}
impl<C: Constraint> Constraint for Connected<C> {
	type Base = C::Base;
	type Constrained = C;

	fn unconstrain_single(self) -> Self::Constrained { self.0 }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> {
		println!("Constraint for Connected constrain_single()");
		if g.get_graph().graph_fn().next().unwrap() < &32 {
			Ok(Self(g))
		} else {
			Err(())
		}

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

impl<C: Constraint> Connected<C> {
	fn connected_fn(&self) -> &<C::Graph as Graph>::R
	{
		self.get_graph().graph_fn().next().unwrap()
	}
}
impl<C: Constraint> Graph for Connected<C>{
	type R = <C::Graph as Graph>::R;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a Self::R>> {
		println!("Graph for Connected graph_fn()");
		self.0.get_graph().graph_fn()
	}
}
impl<C: ConstraintMut> GraphMut for Connected<C>
	where C::Graph: GraphMut {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=
		&'a mut <C::Graph as Graph>::R>>
	{
		self.0.get_graph_mut().graph_mut()
	}
}
impl<C: ConstraintMut> GraphMut2 for Connected<C>
	where C::Graph: GraphMut2 {
	fn graph_mut2(&mut self) -> &mut <C::Graph as Graph>::R {
		self.0.get_graph_mut().graph_mut2()
	}
}

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

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

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

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

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

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

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

}

#[test]
fn inline_constrainer_constraining_base(){

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

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

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

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

}

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

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

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

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

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

#[test]
fn base_constrains_self_by_inline_constraint_inference(){

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

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

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

	let c_owned: Connected<Connected<Connected<BaseGraph>>> = g.constrain().unwrap();
	assert_eq!(c_owned.connected_fn(), &31);
	let c_owned_unc = c_owned.unconstrain_single();
	assert_eq!(c_owned_unc.connected_fn(), &31);
	let g2 = c_owned_unc.unconstrain();
	assert_eq!(g2.base_graph_fn(), 31);
}<commit_msg>Simplified constraint system to remove BaseConstraintMut and ConstraintMut<commit_after>use std::ops::{Deref, DerefMut};
use std::borrow::Borrow;

trait Graph {
	type R: PartialOrd<u32>;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a Self::R>> ;
}
trait GraphMut: Graph {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=&'a mut Self::R>>;
}
trait GraphMut2: Graph {
	fn graph_mut2(&mut self) -> &mut Self::R;
}

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

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

	fn constrain(g: Self::Base) -> Result<Self, ()>{
		println!("Default constrain()");
		Self::constrain_single(Self::Constrained::constrain(g)?)
	}
	fn unconstrain(self) -> Self::Base{
		self.unconstrain_single().unconstrain()
	}

}

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

	fn unconstrain_single(self) -> Self::Constrained { self }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> { println!("Constraint for BaseConstraint constrain_single()");Ok(g)}

	fn unconstrain(self) -> Self::Base { self }
	fn constrain(g: Self::Base) -> Result<Self, ()>{ println!("Constraint for BaseConstraint constrain()");Ok(g) }
}

struct BaseGraph(u32);
impl BaseGraph {
	fn base_graph_fn(&self) -> u32
	{
		self.0
	}
}
impl Graph for BaseGraph{
	type R = u32;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a u32>> {
		Box::new(vec![&self.0].into_iter())
	}
}
impl GraphMut for BaseGraph {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=&'a mut u32>> {
		Box::new(vec![&mut self.0].into_iter())
	}
}
impl GraphMut2 for BaseGraph {
	fn graph_mut2(&mut self) -> &mut u32 { &mut self.0 }
}
impl ImplGraph for BaseGraph {
	type Graph = Self;
	fn get_graph(&self) -> &Self::Graph {
		self
	}
}
impl ImplGraphMut for BaseGraph {
	fn get_graph_mut(&mut self) -> &mut Self::Graph {
		self
	}
}
impl BaseConstraint for BaseGraph {}

struct Connected<C: Constraint>(C);
impl<C: Constraint> ImplGraph for Connected<C> {
	type Graph = Self;

	fn get_graph(&self) -> &Self::Graph {
		println!("ImplGraph for Connected get_graph()");
		self
	}
}
impl<C: Constraint> ImplGraphMut for Connected<C>  {
	fn get_graph_mut(&mut self) -> &mut Self::Graph {
		self
	}
}
impl<C: Constraint> Constraint for Connected<C> {
	type Base = C::Base;
	type Constrained = C;

	fn unconstrain_single(self) -> Self::Constrained { self.0 }
	fn constrain_single(g: Self::Constrained) -> Result<Self, ()> {
		println!("Constraint for Connected constrain_single()");
		if g.get_graph().graph_fn().next().unwrap() < &32 {
			Ok(Self(g))
		} else {
			Err(())
		}

	}
}

impl<C: Constraint> Connected<C> {
	fn connected_fn(&self) -> &<C::Graph as Graph>::R
	{
		self.get_graph().graph_fn().next().unwrap()
	}
}
impl<C: Constraint> Graph for Connected<C>{
	type R = <C::Graph as Graph>::R;
	fn graph_fn<'a>(&'a self) -> Box<dyn 'a + Iterator<Item=&'a Self::R>> {
		println!("Graph for Connected graph_fn()");
		self.0.get_graph().graph_fn()
	}
}
impl<C: Constraint + ImplGraphMut> GraphMut for Connected<C>
	where C::Graph: GraphMut {
	fn graph_mut<'a>(&'a mut self) -> Box<dyn 'a + Iterator<Item=
		&'a mut <C::Graph as Graph>::R>>
	{
		self.0.get_graph_mut().graph_mut()
	}
}
impl<C: Constraint + ImplGraphMut> GraphMut2 for Connected<C>
	where C::Graph: GraphMut2 {
	fn graph_mut2(&mut self) -> &mut <C::Graph as Graph>::R {
		self.0.get_graph_mut().graph_mut2()
	}
}

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

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

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

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

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

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

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

}

#[test]
fn inline_constrainer_constraining_base(){

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

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

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

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

}

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

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

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

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

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

#[test]
fn base_constrains_self_by_inline_constraint_inference(){

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

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

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

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


<commit_before>/* 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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               needs_context=False)}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: Some(${side}),
            % endfor
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = match self.border_${side}_width {
                    &DeclaredValue::Value(ref value) => DeclaredValue::Value(*value),
                    &DeclaredValue::WithVariables {
                        css: ref a, first_token_type: ref b, base_url: ref c, from_shorthand: ref d
                    } => DeclaredValue::WithVariables {
                        // WithVariables should not be reachable during serialization
                        css: a.clone(), first_token_type: b.clone(), base_url: c.clone(), from_shorthand: d.clone()
                    },
                    &DeclaredValue::Initial => DeclaredValue::Initial,
                    &DeclaredValue::Inherit => DeclaredValue::Inherit,
                    &DeclaredValue::Unset => DeclaredValue::Unset,
                };
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(Option<specified::CSSColor>,
                            Option<specified::BorderStyle>,
                            Option<specified::BorderWidth>), ()> {
    use values::specified;
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(specified::BorderStyle::parse) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| specified::BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any { Ok((color, style, width)) } else { Err(()) }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand name="border-${side}" sub_properties="${' '.join(
        'border-%s-%s' % (side, prop)
        for prop in ['color', 'style', 'width']
    )}" spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width,
            % endfor
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            super::serialize_directional_border(
                dest,
                self.border_${side}_width,
                self.border_${side}_style,
                self.border_${side}_color
            )
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: Some(radii.top_left),
            border_top_right_radius: Some(radii.top_right),
            border_bottom_right_radius: Some(radii.bottom_right),
            border_bottom_left_radius: Some(radii.bottom_left),
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" products="gecko" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            Ok((w, o))
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: Some(border_image_${name}),
            % endfor
         })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for name in "outset repeat slice source width".split():
                let ${name} = if let DeclaredValue::Value(ref value) = *self.border_image_${name} {
                    Some(value)
                } else {
                    None
                };
            % endfor

            if let Some(source) = source {
                try!(source.to_css(dest));
            } else {
                try!(write!(dest, "none"));
            }

            try!(write!(dest, " "));

            if let Some(slice) = slice {
                try!(slice.to_css(dest));
            } else {
                try!(write!(dest, "100%"));
            }

            try!(write!(dest, " / "));

            if let Some(width) = width {
                try!(width.to_css(dest));
            } else {
                try!(write!(dest, "1"));
            }

            try!(write!(dest, " / "));

            if let Some(outset) = outset {
                try!(outset.to_css(dest));
            } else {
                try!(write!(dest, "0"));
            }

            try!(write!(dest, " "));

            if let Some(repeat) = repeat {
                try!(repeat.to_css(dest));
            } else {
                try!(write!(dest, "stretch"));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<commit_msg>Add spec links for border shorthands<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-color")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               needs_context=False,
                               spec="https://drafts.csswg.org/css-backgrounds/#border-style")}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}"
    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: Some(${side}),
            % endfor
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = match self.border_${side}_width {
                    &DeclaredValue::Value(ref value) => DeclaredValue::Value(*value),
                    &DeclaredValue::WithVariables {
                        css: ref a, first_token_type: ref b, base_url: ref c, from_shorthand: ref d
                    } => DeclaredValue::WithVariables {
                        // WithVariables should not be reachable during serialization
                        css: a.clone(), first_token_type: b.clone(), base_url: c.clone(), from_shorthand: d.clone()
                    },
                    &DeclaredValue::Initial => DeclaredValue::Initial,
                    &DeclaredValue::Inherit => DeclaredValue::Inherit,
                    &DeclaredValue::Unset => DeclaredValue::Unset,
                };
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(Option<specified::CSSColor>,
                            Option<specified::BorderStyle>,
                            Option<specified::BorderWidth>), ()> {
    use values::specified;
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(specified::BorderStyle::parse) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| specified::BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any { Ok((color, style, width)) } else { Err(()) }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand name="border-${side}" sub_properties="${' '.join(
        'border-%s-%s' % (side, prop)
        for prop in ['color', 'style', 'width']
    )}" spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width,
            % endfor
        })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            super::serialize_directional_border(
                dest,
                self.border_${side}_width,
                self.border_${side}_style,
                self.border_${side}_color
            )
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: Some(radii.top_left),
            border_top_right_radius: Some(radii.top_right),
            border_bottom_right_radius: Some(radii.bottom_right),
            border_bottom_left_radius: Some(radii.bottom_left),
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" products="gecko" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            Ok((w, o))
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: Some(border_image_${name}),
            % endfor
         })
    }

    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for name in "outset repeat slice source width".split():
                let ${name} = if let DeclaredValue::Value(ref value) = *self.border_image_${name} {
                    Some(value)
                } else {
                    None
                };
            % endfor

            if let Some(source) = source {
                try!(source.to_css(dest));
            } else {
                try!(write!(dest, "none"));
            }

            try!(write!(dest, " "));

            if let Some(slice) = slice {
                try!(slice.to_css(dest));
            } else {
                try!(write!(dest, "100%"));
            }

            try!(write!(dest, " / "));

            if let Some(width) = width {
                try!(width.to_css(dest));
            } else {
                try!(write!(dest, "1"));
            }

            try!(write!(dest, " / "));

            if let Some(outset) = outset {
                try!(outset.to_css(dest));
            } else {
                try!(write!(dest, "0"));
            }

            try!(write!(dest, " "));

            if let Some(repeat) = repeat {
                try!(repeat.to_css(dest));
            } else {
                try!(write!(dest, "stretch"));
            }

            Ok(())
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                let x1 = last_x;
                let y1 = last_y;

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn line_or_curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (segments, expected_segments);
    }

    /* Single open path */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line_or_curve (10.0, 10.0, 20.0, 10.0, 10.0, 10.0, 20.0, 10.0),
            line_or_curve (20.0, 10.0, 20.0, 20.0, 20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line_or_curve (10.0, 10.0, 20.0, 10.0, 10.0, 10.0, 20.0, 10.0),
            line_or_curve (20.0, 10.0, 20.0, 20.0, 20.0, 10.0, 20.0, 20.0),

            line_or_curve (30.0, 30.0, 40.0, 30.0, 30.0, 30.0, 40.0, 30.0),
            line_or_curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line_or_curve (70.0, 70.0, 80.0, 90.0, 70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }
}
<commit_msg>marker.rs: Use helper functions to create Segments everywhere<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

fn make_degenerate (x: f64, y: f64) -> Segment {
    Segment::Degenerate { x: x, y: y}
}

fn make_curve (x1: f64, y1: f64,
               x2: f64, y2: f64,
               x3: f64, y3: f64,
               x4: f64, y4: f64) -> Segment {
    Segment::LineOrCurve {
        x1: x1, y1: y1,
        x2: x2, y2: y2,
        x3: x3, y3: y3,
        x4: x4, y4: y4
    }
}

fn make_line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
    make_curve (x1, y1, x2, y2, x1, y1, x2, y2)
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_degenerate (cur_x, cur_y);
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                let x1 = last_x;
                let y1 = last_y;

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = make_curve (x1, y1, x2, y2, x3, y3, x4, y4);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
        curve (x1, y1, x2, y2, x1, y1, x2, y2)
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (segments, expected_segments);
    }

    /* Single open path */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "tango"]
#![no_std]
#![no_main]
#![feature(lang_items)]

#[macro_use(static_init)]
extern crate common;
extern crate drivers;
extern crate hotel;
extern crate hil;
extern crate main;

#[macro_use]
pub mod io;

use main::{Chip, MPU, Platform};

unsafe fn load_processes() -> &'static mut [Option<main::process::Process<'static>>] {
    extern "C" {
        /// Beginning of the ROM region containing app images.
        static _sapps: u8;
    }

    const NUM_PROCS: usize = 2;

    #[link_section = ".app_memory"]
    static mut MEMORIES: [[u8; 8192]; NUM_PROCS] = [[0; 8192]; NUM_PROCS];

    static mut processes: [Option<main::process::Process<'static>>; NUM_PROCS] = [None, None];

    let mut addr = &_sapps as *const u8;
    for i in 0..NUM_PROCS {
        // The first member of the LoadInfo header contains the total size of each process image. A
        // sentinel value of 0 (invalid because it's smaller than the header itself) is used to
        // mark the end of the list of processes.
        let total_size = *(addr as *const usize);
        if total_size == 0 {
            break;
        }

        let process = &mut processes[i];
        let memory = &mut MEMORIES[i];
        *process = Some(main::process::Process::create(addr, total_size, memory));
        // TODO: panic if loading failed?

        addr = addr.offset(total_size as isize);
    }

    if *(addr as *const usize) != 0 {
        panic!("Exceeded maximum NUM_PROCS.");
    }

    &mut processes
}

pub struct Tango {
    console: &'static drivers::console::Console<'static, hotel::uart::UART>,
    gpio: &'static drivers::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
}

#[no_mangle]
pub unsafe fn reset_handler() {
    hotel::init();

    let timer = {
        use hotel::pmu::*;
        use hotel::timeus::Timeus;
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeUs0Timer)).enable();
        let timer = Timeus::new(0);
        timer
    };

    timer.start();
    let start = timer.now();

    hotel::usb::USB0.init(&mut hotel::usb::OUT_DESCRIPTORS,
                          &mut hotel::usb::OUT_BUFFERS,
                          &mut hotel::usb::IN_DESCRIPTORS,
                          &mut hotel::usb::IN_BUFFERS,
                          hotel::usb::PHY::A,
                          None, Some(0x0011), Some(0x7788));

    {
        use hotel::pmu::*;
        Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0)).enable();
        let pinmux = &mut *hotel::pinmux::PINMUX;
        pinmux.diob0.select.set(hotel::pinmux::Function::Gpio0Gpio0);

        pinmux.dioa0.select.set(hotel::pinmux::Function::Uart0Tx);
        pinmux.dioa11.control.set(1 << 2 | 1 << 4);
        pinmux.uart0_rx.select.set(hotel::pinmux::SelectablePin::Dioa11);
    }

    let console = static_init!(
        drivers::console::Console<'static, hotel::uart::UART>,
        drivers::console::Console::new(&hotel::uart::UART0,
                                       &mut drivers::console::WRITE_BUF,
                                       main::container::Container::create()),
        24);
    hotel::uart::UART0.set_client(console);
    console.initialize();

    let gpio_pins = static_init!(
        [&'static hotel::gpio::GPIOPin; 1],
        [&hotel::gpio::PORT0.pins[0]],
        4);

    let gpio = static_init!(
        drivers::gpio::GPIO<'static, hotel::gpio::GPIOPin>,
        drivers::gpio::GPIO::new(gpio_pins),
        20);

    let platform = static_init!(Tango, Tango {
        console: console,
        gpio: gpio
    }, 8);

    let end = timer.now();

    println!("Hello from Rust! Initialization took {} tics.",
             end.wrapping_sub(start));

    let mut chip = hotel::chip::Hotel::new();
    chip.mpu().enable_mpu();

    main::main(platform, &mut chip, load_processes());
}

impl Platform for Tango {
    fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R
        where F: FnOnce(Option<&main::Driver>) -> R
    {
        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(self.gpio)),
            _ => f(None),
        }
    }
}
<commit_msg>Keep tango board up to date<commit_after>#![crate_name = "golf"]
#![no_std]
#![no_main]
#![feature(lang_items)]

#[macro_use(static_init)]
extern crate common;
extern crate drivers;
extern crate hotel;
extern crate hil;
extern crate main;

#[macro_use]
pub mod io;

use main::{Chip, MPU, Platform};

unsafe fn load_processes() -> &'static mut [Option<main::process::Process<'static>>] {
    extern "C" {
        /// Beginning of the ROM region containing app images.
        static _sapps: u8;
    }

    const NUM_PROCS: usize = 2;

    #[link_section = ".app_memory"]
    static mut MEMORIES: [[u8; 8192]; NUM_PROCS] = [[0; 8192]; NUM_PROCS];

    static mut processes: [Option<main::process::Process<'static>>; NUM_PROCS] = [None, None];

    let mut addr = &_sapps as *const u8;
    for i in 0..NUM_PROCS {
        // The first member of the LoadInfo header contains the total size of each process image. A
        // sentinel value of 0 (invalid because it's smaller than the header itself) is used to
        // mark the end of the list of processes.
        let total_size = *(addr as *const usize);
        if total_size == 0 {
            break;
        }

        let process = &mut processes[i];
        let memory = &mut MEMORIES[i];
        *process = Some(main::process::Process::create(addr, total_size, memory));
        // TODO: panic if loading failed?

        addr = addr.offset(total_size as isize);
    }

    if *(addr as *const usize) != 0 {
        panic!("Exceeded maximum NUM_PROCS.");
    }

    &mut processes
}

pub struct Golf {
    console: &'static drivers::console::Console<'static, hotel::uart::UART>,
    gpio: &'static drivers::gpio::GPIO<'static, hotel::gpio::Pin>,
    timer: &'static drivers::timer::TimerDriver<'static, hotel::timels::Timels>
}

#[no_mangle]
pub unsafe fn reset_handler() {
    hotel::init();

    let timerhs = {
        use hotel::pmu::*;
        use hotel::timeus::Timeus;
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeUs0Timer)).enable();
        Clock::new(PeripheralClock::Bank1(PeripheralClock1::TimeLs0)).enable();
        let timer = Timeus::new(0);
        timer
    };

    timerhs.start();
    let start = timerhs.now();

    {
        use hotel::pmu::*;
        Clock::new(PeripheralClock::Bank0(PeripheralClock0::Gpio0)).enable();
        let pinmux = &mut *hotel::pinmux::PINMUX;
        pinmux.diob0.select.set(hotel::pinmux::Function::Gpio0Gpio0);

        pinmux.gpio0_gpio1.select.set(hotel::pinmux::SelectablePin::Dioa8);
        pinmux.dioa8.select.set(hotel::pinmux::Function::Gpio0Gpio1);
        pinmux.dioa8.control.set(1 << 2 | 1 << 4);

        pinmux.dioa0.select.set(hotel::pinmux::Function::Uart0Tx);
        pinmux.dioa11.control.set(1 << 2 | 1 << 4);
        pinmux.uart0_rx.select.set(hotel::pinmux::SelectablePin::Dioa11);
    }

    let console = static_init!(
        drivers::console::Console<'static, hotel::uart::UART>,
        drivers::console::Console::new(&hotel::uart::UART0,
                                       &mut drivers::console::WRITE_BUF,
                                       main::container::Container::create()),
        24);
    hotel::uart::UART0.set_client(console);
    console.initialize();

    let gpio_pins = static_init!(
        [&'static hotel::gpio::Pin; 2],
        [&hotel::gpio::PORT0.pins[0], &hotel::gpio::PORT0.pins[1]],
        8);

    let gpio = static_init!(
        drivers::gpio::GPIO<'static, hotel::gpio::Pin>,
        drivers::gpio::GPIO::new(gpio_pins),
        20);
    for pin in gpio_pins.iter() {
        pin.set_client(gpio)
    }

    let timer = static_init!(
        drivers::timer::TimerDriver<'static, hotel::timels::Timels>,
        drivers::timer::TimerDriver::new(
            &hotel::timels::Timels0, main::container::Container::create()),
        12);
    hotel::timels::Timels0.set_client(timer);

    let platform = static_init!(Golf, Golf {
        console: console,
        gpio: gpio,
        timer: timer,
    }, 12);

    hotel::usb::USB0.init(&mut hotel::usb::OUT_DESCRIPTORS,
                          &mut hotel::usb::OUT_BUFFERS,
                          &mut hotel::usb::IN_DESCRIPTORS,
                          &mut hotel::usb::IN_BUFFERS,
                          hotel::usb::PHY::A,
                          None, Some(0x0011), Some(0x7788));

    let end = timerhs.now();

    println!("Hello from Rust! Initialization took {} tics.",
             end.wrapping_sub(start));

    let mut chip = hotel::chip::Hotel::new();
    chip.mpu().enable_mpu();

    main::main(platform, &mut chip, load_processes());
}

impl Platform for Golf {
    fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R
        where F: FnOnce(Option<&main::Driver>) -> R
    {
        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(self.gpio)),
            3 => f(Some(self.timer)),
            _ => f(None),
        }
    }
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::result::Result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String,
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY (fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        println!("table_create_variable_pair Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let me = VariablePair {
        id: 0,
        variable_value: name.to_string(),
        fk_variable: *fk_variable,
    };
    println!("me.fk_variable:{:?}", me.fk_variable);
    let variable_pair_instance = conn.execute(
        "INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                 VALUES (?1, ?2)",
        &[&me.fk_variable, &me.variable_value],
    );
    if variable_pair_instance.is_err() {
        println!("Failed to insert:{:?}", me);
        return Err("INSERT INTO VARIABLE_PAIR failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection) -> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare(
        "SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value
        FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2",
    ).unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable, &bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Select failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<commit_msg>Fixup<commit_after>use rusqlite::Connection;
use std::result::Result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String,
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY (fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        println!("table_create_variable_pair Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let me = VariablePair {
        id: 0,
        variable_value: name.to_string(),
        fk_variable: *fk_variable,
    };
    let variable_pair_instance = conn.execute(
        "INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                 VALUES (?1, ?2)",
        &[&me.fk_variable, &me.variable_value],
    );
    if variable_pair_instance.is_err() {
        println!("Failed to insert:{:?}", me);
        return Err("INSERT INTO VARIABLE_PAIR failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection) -> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare(
        "SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value
        FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2",
    ).unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable, &bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Select failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate term;

use std::io::prelude::*;
use std::io;
use std::sync::{Arc, Mutex};

use cargo::core::shell::ColorConfig::{Auto,Always, Never};
use cargo::core::shell::{Shell, ShellConfig};
use cargo::util::CargoResult;
use cargotest::support::{Tap, execs, shell_writes};
use hamcrest::{assert_that};
use term::{Terminal, TerminfoTerminal, color};

struct Sink(Arc<Mutex<Vec<u8>>>);

impl Write for Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[test]
fn non_tty() {
    let config = ShellConfig { color_config: Auto, tty: false };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..], shell_writes("Hey Alex\n"));
}

#[test]
fn color_explicitly_disabled() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }

    let config = ShellConfig { color_config: Never, tty: true };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..], shell_writes("Hey Alex\n"));
}

#[test]
fn colored_shell() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }

    let config = ShellConfig { color_config: Auto, tty: true };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..],
                shell_writes(colored_output("Hey Alex\n",
                                            color::RED).unwrap()));
}

#[test]
fn color_explicitly_enabled() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }

    let config = ShellConfig { color_config: Always, tty: false };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..],
                shell_writes(colored_output("Hey Alex\n",
                                            color::RED).unwrap()));
}

#[test]
fn no_term() {
    // Verify that shell creation is successful when $TERM does not exist.
    assert_that(cargotest::cargo_process().env_remove("TERM"),
                execs().with_stderr(""));
}

fn colored_output(string: &str, color: color::Color) -> CargoResult<String> {
    let mut term = TerminfoTerminal::new(Vec::new()).unwrap();
    term.reset()?;
    term.fg(color)?;
    write!(&mut term, "{}", string)?;
    term.reset()?;
    term.flush()?;
    Ok(String::from_utf8_lossy(term.get_ref()).to_string())
}
<commit_msg>disable color shell tests for terminals that don't support color<commit_after>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate term;

use std::io::prelude::*;
use std::io;
use std::sync::{Arc, Mutex};

use cargo::core::shell::ColorConfig::{Auto,Always, Never};
use cargo::core::shell::{Shell, ShellConfig};
use cargo::util::CargoResult;
use cargotest::support::{Tap, execs, shell_writes};
use hamcrest::{assert_that};
use term::{Terminal, TerminfoTerminal, color};

struct Sink(Arc<Mutex<Vec<u8>>>);

impl Write for Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[test]
fn non_tty() {
    let config = ShellConfig { color_config: Auto, tty: false };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..], shell_writes("Hey Alex\n"));
}

#[test]
fn color_explicitly_disabled() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }

    let config = ShellConfig { color_config: Never, tty: true };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..], shell_writes("Hey Alex\n"));
}

#[test]
fn colored_shell() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }

    let config = ShellConfig { color_config: Auto, tty: true };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    let expected_output = if term.unwrap().supports_color() {
        shell_writes(colored_output("Hey Alex\n", color::RED).unwrap())
    } else {
        shell_writes("Hey Alex\n")
    };
    assert_that(&buf[..], expected_output);
}

#[test]
fn color_explicitly_enabled() {
    let term = TerminfoTerminal::new(Vec::new());
    if term.is_none() { return }
    if !term.unwrap().supports_color() { return }

    let config = ShellConfig { color_config: Always, tty: false };
    let a = Arc::new(Mutex::new(Vec::new()));

    Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| {
        shell.say("Hey Alex", color::RED).unwrap();
    });
    let buf = a.lock().unwrap().clone();
    assert_that(&buf[..],
                shell_writes(colored_output("Hey Alex\n",
                                            color::RED).unwrap()));
}

#[test]
fn no_term() {
    // Verify that shell creation is successful when $TERM does not exist.
    assert_that(cargotest::cargo_process().env_remove("TERM"),
                execs().with_stderr(""));
}

fn colored_output(string: &str, color: color::Color) -> CargoResult<String> {
    let mut term = TerminfoTerminal::new(Vec::new()).unwrap();
    term.reset()?;
    term.fg(color)?;
    write!(&mut term, "{}", string)?;
    term.reset()?;
    term.flush()?;
    Ok(String::from_utf8_lossy(term.get_ref()).to_string())
}
<|endoftext|>


<commit_before>use std::iter;
use std::cmp::max;

/// Utility struct for generating code that indents and formats it.
/// Also implements `std::fmt::Write` to support the `write!` macro.
#[derive(Debug)]
pub struct CodeBuilder {
    code: String,
    indent_level: i32,
    indent_size: i32,
    indent_string: String,
}

impl CodeBuilder {
    /// Adds a single line of code to this code builder, formatting it based on previous code.
    pub fn add_line(&mut self, line: &str) {
        let line = line.trim();
        let indent_change = (line.matches("{").count() as i32) -
            (line.matches("}").count() as i32);
        let new_indent_level = max(0, self.indent_level + indent_change);
        // Lines starting with '}' should be de-indented even if they
        // contain '{' after; in addition, lines ending with ':' are
        // typically labels, e.g., in LLVM.
        let this_line_indent = if line.starts_with("}") || line.ends_with(":") {
            let spaces = (self.indent_size * (self.indent_level - 1)) as usize;
            iter::repeat(" ")
                .take(spaces)
                .collect::<String>()
        } else {
            // TODO(shoumik): How to avoid this clone...?
            self.indent_string.clone()
        };

        self.code.push_str(this_line_indent.as_ref());
        self.code.push_str(line);
        self.code.push_str("\n");

        self.indent_level = new_indent_level;
        let spaces = (self.indent_size * new_indent_level) as usize;
        self.indent_string = iter::repeat(" ")
            .take(spaces)
            .collect::<String>();
    }

    /// Adds one or more lines (split by "\n") to this code builder.
    pub fn add<S>(&mut self, code: S) where S: AsRef<str> {
        for l in code.as_ref().lines() {
            self.add_line(l);
        }
    }

    /// Adds the result of another CodeBuilder.
    pub fn add_code(&mut self, builder: &CodeBuilder) {
        self.code.push_str(builder.code.as_ref());
    }

    /// Returns the code in this code builder so far.
    pub fn result(&self) -> &str {
        self.code.as_str()
    }

    /// Returns a new CodeBuilder.
    pub fn new() -> CodeBuilder {
        CodeBuilder::with_indent_size(2)
    }

    /// Returns a new CodeBuilder with the given indent size.
    pub fn with_indent_size(indent_size: i32) -> CodeBuilder {
        CodeBuilder {
            code: String::new(),
            indent_level: 0,
            indent_size: indent_size,
            indent_string: String::new(),
        }
    }

    /// Returns a formatted string using the CodeBuilder.
    pub fn format<S>(indent_size: i32, code: S) -> String where S: AsRef<str> {
        let mut c = CodeBuilder::with_indent_size(indent_size);
        c.add(code);
        c.code
    }
}

#[test]
fn code_builder_basic() {
    let inp = "
class A {
blahblah;
}";
   let exp = "
class A {
  blahblah;
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) {
duh
     }
}";
   let exp = "
class A {
  if (c) {
    duh
  }
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) { duh }
}";
   let exp = "
class A {
  if (c) { duh }
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) { duh }
myLabel:
blah
}";
   let exp = "
class A {
  if (c) { duh }
myLabel:
  blah
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);
}
<commit_msg>Simplify code builder<commit_after>use std::cmp::max;

/// Utility struct for generating code that indents and formats it.
/// Also implements `std::fmt::Write` to support the `write!` macro.
#[derive(Debug)]
pub struct CodeBuilder {
    code: String,
    indent_level: i32,
    indent_size: i32,
}

impl CodeBuilder {
    /// Adds a single line of code to this code builder, formatting it based on previous code.
    pub fn add_line<S>(&mut self, line: S) where S: AsRef<str> {
        let line = line.as_ref().trim();
        let indent_change = (line.matches("{").count() as i32) -
            (line.matches("}").count() as i32);
        let new_indent_level = max(0, self.indent_level + indent_change);

        // Lines starting with '}' should be de-indented even if they contain '{' after; in
        // addition, lines ending with ':' are typically labels, e.g., in LLVM.
        let this_line_indent = if line.starts_with("}") || line.ends_with(":") {
            self.indent_level - 1
        } else {
            self.indent_level
        };

        //self.code.push_str(this_line_indent.as_ref());
        for _ in 0 .. this_line_indent * self.indent_size {
            self.code.push(' ');
        }
        self.code.push_str(line);
        self.code.push_str("\n");

        self.indent_level = new_indent_level;
    }

    /// Adds one or more lines (split by "\n") to this code builder.
    pub fn add<S>(&mut self, code: S) where S: AsRef<str> {
        for l in code.as_ref().lines() {
            self.add_line(l);
        }
    }

    /// Adds the result of another CodeBuilder.
    pub fn add_code(&mut self, builder: &CodeBuilder) {
        self.code.push_str(builder.code.as_ref());
    }

    /// Returns the code in this code builder so far.
    pub fn result(&self) -> &str {
        self.code.as_str()
    }

    /// Returns a new CodeBuilder.
    pub fn new() -> CodeBuilder {
        CodeBuilder::with_indent_size(2)
    }

    /// Returns a new CodeBuilder with the given indent size.
    pub fn with_indent_size(indent_size: i32) -> CodeBuilder {
        CodeBuilder {
            code: String::new(),
            indent_level: 0,
            indent_size: indent_size,
        }
    }

    /// Returns a formatted string using the CodeBuilder.
    pub fn format<S>(indent_size: i32, code: S) -> String where S: AsRef<str> {
        let mut c = CodeBuilder::with_indent_size(indent_size);
        c.add(code);
        c.code
    }
}

#[test]
fn code_builder_basic() {
    let inp = "
class A {
blahblah;
}";
   let exp = "
class A {
  blahblah;
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) {
duh
     }
}";
   let exp = "
class A {
  if (c) {
    duh
  }
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) { duh }
}";
   let exp = "
class A {
  if (c) { duh }
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);

   let inp = "
class A {
if (c) { duh }
myLabel:
blah
}";
   let exp = "
class A {
  if (c) { duh }
myLabel:
  blah
}
";
   assert_eq!(CodeBuilder::format(2, inp), exp);
}
<|endoftext|>


<commit_before>use std::slice;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// Like floor, but map generation treats it differently.
    Corridor,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_irregular: bool,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_irregular: false },
    Gate:        TerrainData { name: "gate",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_irregular: false },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ".,_", is_irregular: false },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_irregular: false },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_irregular: false },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_irregular: false },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_irregular: false },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "#*",  is_irregular: false },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "*#",  is_irregular: false },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_irregular: false },
    // TODO: Get rid of corridor, it only makes sense for mapgen bookkeeping and that doesn't
    // belong in persistent map.
    Corridor:    TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: "_.,", is_irregular: true },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_irregular: true },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_irregular: true },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> { TERRAIN_ENUM.iter() }

    #[inline(always)]
    pub fn kind(self) -> Kind { TERRAIN_DATA[self as usize].kind }

    #[inline(always)]
    pub fn form(self) -> Form { TERRAIN_DATA[self as usize].form }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Corridor | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground || self.kind() == Kind::Corridor }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_irregular(self) -> bool { TERRAIN_DATA[self as usize].is_irregular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str { TERRAIN_DATA[self as usize].map_chars }

    /// Terrain is a narrow object that blocks movement.
    ///
    /// Prop obstacles might not be distinguishable from floors if you only see a corner of the
    /// terrain tile. Use this if there's need to highlight partially visible terrain as obstacles.
    pub fn is_narrow_obstacle(self) -> bool {
        self.blocks_walk() && (self.form() == Form::Prop || self.form() == Form::Blob)
    }
}

impl Default for Terrain {
    fn default() -> Self { Terrain::Empty }
}
<commit_msg>Don't highlight blob tiles, most are in sectors you're not supposed to enter<commit_after>use std::slice;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// Like floor, but map generation treats it differently.
    Corridor,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_irregular: bool,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_irregular: false },
    Gate:        TerrainData { name: "gate",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_irregular: false },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ".,_", is_irregular: false },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_irregular: false },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_irregular: false },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_irregular: false },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_irregular: false },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "#*",  is_irregular: false },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "*#",  is_irregular: false },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_irregular: false },
    // TODO: Get rid of corridor, it only makes sense for mapgen bookkeeping and that doesn't
    // belong in persistent map.
    Corridor:    TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: "_.,", is_irregular: true },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_irregular: true },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_irregular: true },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> { TERRAIN_ENUM.iter() }

    #[inline(always)]
    pub fn kind(self) -> Kind { TERRAIN_DATA[self as usize].kind }

    #[inline(always)]
    pub fn form(self) -> Form { TERRAIN_DATA[self as usize].form }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Corridor | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground || self.kind() == Kind::Corridor }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_irregular(self) -> bool { TERRAIN_DATA[self as usize].is_irregular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str { TERRAIN_DATA[self as usize].map_chars }

    /// Terrain is a narrow object that blocks movement.
    ///
    /// Prop obstacles might not be distinguishable from floors if you only see a corner of the
    /// terrain tile. Use this if there's need to highlight partially visible terrain as obstacles.
    pub fn is_narrow_obstacle(self) -> bool {
        self.blocks_walk() && self.form() == Form::Prop
    }
}

impl Default for Terrain {
    fn default() -> Self { Terrain::Empty }
}
<|endoftext|>