<commit_before>use cairo::{self, ImageSurface};
use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::number_list::{NumberList, NumberListError, NumberListLength};
use crate::parsers::{self, Parse, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// The `feConvolveMatrix` filter primitive.
pub struct FeConvolveMatrix {
    base: PrimitiveWithInput,
    order: (u32, u32),
    kernel_matrix: Option<DMatrix<f64>>,
    divisor: Option<f64>,
    bias: f64,
    target_x: Option<u32>,
    target_y: Option<u32>,
    edge_mode: EdgeMode,
    kernel_unit_length: Option<(f64, f64)>,
    preserve_alpha: bool,
}

impl Default for FeConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    fn default() -> FeConvolveMatrix {
        FeConvolveMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            order: (3, 3),
            kernel_matrix: None,
            divisor: None,
            bias: 0.0,
            target_x: None,
            target_y: None,
            edge_mode: EdgeMode::Duplicate,
            kernel_unit_length: None,
            preserve_alpha: false,
        }
    }
}

impl NodeTrait for FeConvolveMatrix {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "order") => {
                    self.order = parsers::integer_optional_integer(value)
                        .and_then(|(x, y)| {
                            if x > 0 && y > 0 {
                                Ok((x as u32, y as u32))
                            } else {
                                Err(ValueErrorKind::value_error("values must be greater than 0"))
                            }
                        })
                        .attribute(attr)?
                }
                expanded_name!(svg "divisor") => {
                    self.divisor = Some(
                        parsers::number(value)
                            .and_then(|x| {
                                if x != 0.0 {
                                    Ok(x)
                                } else {
                                    Err(ValueErrorKind::value_error("divisor cannot be equal to 0"))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "bias") => self.bias = parsers::number(value).attribute(attr)?,
                expanded_name!(svg "edgeMode") => self.edge_mode = EdgeMode::parse(attr, value)?,
                expanded_name!(svg "kernelUnitLength") => {
                    self.kernel_unit_length = Some(
                        parsers::number_optional_number(value)
                            .and_then(|(x, y)| {
                                if x > 0.0 && y > 0.0 {
                                    Ok((x, y))
                                } else {
                                    Err(ValueErrorKind::value_error(
                                        "kernelUnitLength can't be less or equal to zero",
                                    ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "preserveAlpha") => self.preserve_alpha = attr.parse(value)?,

                _ => (),
            }
        }

        // target_x and target_y depend on order.
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "targetX") => {
                    self.target_x = Some(
                        parsers::integer(value)
                            .and_then(|x| {
                                if x >= 0 && x < self.order.0 as i32 {
                                    Ok(x as u32)
                                } else {
                                    Err(ValueErrorKind::value_error(
                                    "targetX must be greater or equal to zero and less than orderX",
                                ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "targetY") => {
                    self.target_y = Some(
                        parsers::integer(value)
                            .and_then(|x| {
                                if x >= 0 && x < self.order.1 as i32 {
                                    Ok(x as u32)
                                } else {
                                    Err(ValueErrorKind::value_error(
                                    "targetY must be greater or equal to zero and less than orderY",
                                ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                _ => (),
            }
        }

        // Default values for target_x and target_y.
        if self.target_x.is_none() {
            self.target_x = Some(self.order.0 / 2);
        }
        if self.target_y.is_none() {
            self.target_y = Some(self.order.1 / 2);
        }

        // Finally, parse the kernel matrix.
        for (attr, value) in pbag
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!(svg "kernelMatrix"))
        {
            self.kernel_matrix = Some({
                let number_of_elements = self.order.0 as usize * self.order.1 as usize;

                // #352: Parse as an unbounded list rather than exact length to prevent aborts due
                //       to huge allocation attempts by underlying Vec::with_capacity().
                let NumberList(v) = NumberList::parse_str(value, NumberListLength::Unbounded)
                    .map_err(|err| match err {
                        NumberListError::IncorrectNumberOfElements => unreachable!(),
                        NumberListError::Parse(ref err) => ValueErrorKind::parse_error(&err),
                    })
                    .attribute(attr.clone())?;

                if v.len() != number_of_elements {
                    return Err(ValueErrorKind::value_error(&format!(
                        "incorrect number of elements: expected {}",
                        number_of_elements
                    )))
                    .attribute(attr);
                }

                DMatrix::from_data(VecStorage::new(
                    Dynamic::new(self.order.1 as usize),
                    Dynamic::new(self.order.0 as usize),
                    v,
                ))
            });
        }

        // kernel_matrix must have been specified.
        if self.kernel_matrix.is_none() {
            return Err(ValueErrorKind::value_error("the value must be set"))
                .attribute(QualName::new(None, ns!(svg), local_name!("kernelMatrix")));
        }

        // Default value for the divisor.
        if self.divisor.is_none() {
            self.divisor = Some(self.kernel_matrix.as_ref().unwrap().iter().sum());

            if self.divisor.unwrap() == 0.0 {
                self.divisor = Some(1.0);
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeConvolveMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let mut bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);
        let original_bounds = bounds;

        let mut input_surface = if self.preserve_alpha {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            input.surface().unpremultiply(bounds)?
        } else {
            input.surface().clone()
        };

        let scale = self
            .kernel_unit_length
            .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.as_ref().unwrap();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            input_surface.width(),
            input_surface.height(),
        )?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::new(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect::new(
                    x as i32 - self.target_x.unwrap() as i32,
                    y as i32 - self.target_y.unwrap() as i32,
                    x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
                    y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
                );

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::new(&input_surface, bounds, kernel_bounds, self.edge_mode)
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
                    g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
                    b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];

                    if !self.preserve_alpha {
                        a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / self.divisor.unwrap() + self.bias;
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / self.divisor.unwrap() + self.bias * a;

                    let x = if self.preserve_alpha {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    ((x * 255.0) + 0.5) as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: ((clamped_a * 255.0) + 0.5) as u8,
                };

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        let mut output_surface =
            SharedImageSurface::new(output_surface, input.surface().surface_type())?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            output_surface = output_surface.scale_to(
                ctx.source_graphic().width(),
                ctx.source_graphic().height(),
                original_bounds,
                ox,
                oy,
            )?;

            bounds = original_bounds;
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl EdgeMode {
    fn parse(attr: QualName, s: &str) -> Result<Self, NodeError> {
        match s {
            "duplicate" => Ok(EdgeMode::Duplicate),
            "wrap" => Ok(EdgeMode::Wrap),
            "none" => Ok(EdgeMode::None),
            _ => Err(ValueErrorKind::parse_error("invalid value")).attribute(attr),
        }
    }
}

// Used for the preserveAlpha attribute
impl Parse for bool {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<Self, ValueErrorKind> {
        parse_identifiers!(
            parser,
            "false" => false,
            "true" => true,
        )
        .map_err(|_: ParseError| ValueErrorKind::parse_error("parse error"))
    }
}
<commit_msg>convolve_matrix.rs: impl Parse for EdgeMode instead of using a custom method<commit_after>use cairo::{self, ImageSurface};
use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns, QualName};
use nalgebra::{DMatrix, Dynamic, VecStorage};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::number_list::{NumberList, NumberListError, NumberListLength};
use crate::parsers::{self, Parse, ParseValue};
use crate::property_bag::PropertyBag;
use crate::rect::IRect;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::SharedImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// The `feConvolveMatrix` filter primitive.
pub struct FeConvolveMatrix {
    base: PrimitiveWithInput,
    order: (u32, u32),
    kernel_matrix: Option<DMatrix<f64>>,
    divisor: Option<f64>,
    bias: f64,
    target_x: Option<u32>,
    target_y: Option<u32>,
    edge_mode: EdgeMode,
    kernel_unit_length: Option<(f64, f64)>,
    preserve_alpha: bool,
}

impl Default for FeConvolveMatrix {
    /// Constructs a new `ConvolveMatrix` with empty properties.
    #[inline]
    fn default() -> FeConvolveMatrix {
        FeConvolveMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            order: (3, 3),
            kernel_matrix: None,
            divisor: None,
            bias: 0.0,
            target_x: None,
            target_y: None,
            edge_mode: EdgeMode::Duplicate,
            kernel_unit_length: None,
            preserve_alpha: false,
        }
    }
}

impl NodeTrait for FeConvolveMatrix {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "order") => {
                    self.order = parsers::integer_optional_integer(value)
                        .and_then(|(x, y)| {
                            if x > 0 && y > 0 {
                                Ok((x as u32, y as u32))
                            } else {
                                Err(ValueErrorKind::value_error("values must be greater than 0"))
                            }
                        })
                        .attribute(attr)?
                }
                expanded_name!(svg "divisor") => {
                    self.divisor = Some(
                        parsers::number(value)
                            .and_then(|x| {
                                if x != 0.0 {
                                    Ok(x)
                                } else {
                                    Err(ValueErrorKind::value_error("divisor cannot be equal to 0"))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "bias") => self.bias = parsers::number(value).attribute(attr)?,
                expanded_name!(svg "edgeMode") => self.edge_mode = attr.parse(value)?,
                expanded_name!(svg "kernelUnitLength") => {
                    self.kernel_unit_length = Some(
                        parsers::number_optional_number(value)
                            .and_then(|(x, y)| {
                                if x > 0.0 && y > 0.0 {
                                    Ok((x, y))
                                } else {
                                    Err(ValueErrorKind::value_error(
                                        "kernelUnitLength can't be less or equal to zero",
                                    ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "preserveAlpha") => self.preserve_alpha = attr.parse(value)?,

                _ => (),
            }
        }

        // target_x and target_y depend on order.
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!(svg "targetX") => {
                    self.target_x = Some(
                        parsers::integer(value)
                            .and_then(|x| {
                                if x >= 0 && x < self.order.0 as i32 {
                                    Ok(x as u32)
                                } else {
                                    Err(ValueErrorKind::value_error(
                                    "targetX must be greater or equal to zero and less than orderX",
                                ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                expanded_name!(svg "targetY") => {
                    self.target_y = Some(
                        parsers::integer(value)
                            .and_then(|x| {
                                if x >= 0 && x < self.order.1 as i32 {
                                    Ok(x as u32)
                                } else {
                                    Err(ValueErrorKind::value_error(
                                    "targetY must be greater or equal to zero and less than orderY",
                                ))
                                }
                            })
                            .attribute(attr)?,
                    )
                }
                _ => (),
            }
        }

        // Default values for target_x and target_y.
        if self.target_x.is_none() {
            self.target_x = Some(self.order.0 / 2);
        }
        if self.target_y.is_none() {
            self.target_y = Some(self.order.1 / 2);
        }

        // Finally, parse the kernel matrix.
        for (attr, value) in pbag
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!(svg "kernelMatrix"))
        {
            self.kernel_matrix = Some({
                let number_of_elements = self.order.0 as usize * self.order.1 as usize;

                // #352: Parse as an unbounded list rather than exact length to prevent aborts due
                //       to huge allocation attempts by underlying Vec::with_capacity().
                let NumberList(v) = NumberList::parse_str(value, NumberListLength::Unbounded)
                    .map_err(|err| match err {
                        NumberListError::IncorrectNumberOfElements => unreachable!(),
                        NumberListError::Parse(ref err) => ValueErrorKind::parse_error(&err),
                    })
                    .attribute(attr.clone())?;

                if v.len() != number_of_elements {
                    return Err(ValueErrorKind::value_error(&format!(
                        "incorrect number of elements: expected {}",
                        number_of_elements
                    )))
                    .attribute(attr);
                }

                DMatrix::from_data(VecStorage::new(
                    Dynamic::new(self.order.1 as usize),
                    Dynamic::new(self.order.0 as usize),
                    v,
                ))
            });
        }

        // kernel_matrix must have been specified.
        if self.kernel_matrix.is_none() {
            return Err(ValueErrorKind::value_error("the value must be set"))
                .attribute(QualName::new(None, ns!(svg), local_name!("kernelMatrix")));
        }

        // Default value for the divisor.
        if self.divisor.is_none() {
            self.divisor = Some(self.kernel_matrix.as_ref().unwrap().iter().sum());

            if self.divisor.unwrap() == 0.0 {
                self.divisor = Some(1.0);
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeConvolveMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let mut bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);
        let original_bounds = bounds;

        let mut input_surface = if self.preserve_alpha {
            // preserve_alpha means we need to premultiply and unpremultiply the values.
            input.surface().unpremultiply(bounds)?
        } else {
            input.surface().clone()
        };

        let scale = self
            .kernel_unit_length
            .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));

        if let Some((ox, oy)) = scale {
            // Scale the input surface to match kernel_unit_length.
            let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;

            input_surface = new_surface;
            bounds = new_bounds;
        }

        let matrix = self.kernel_matrix.as_ref().unwrap();

        let mut output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            input_surface.width(),
            input_surface.height(),
        )?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::new(&input_surface, bounds) {
                // Compute the convolution rectangle bounds.
                let kernel_bounds = IRect::new(
                    x as i32 - self.target_x.unwrap() as i32,
                    y as i32 - self.target_y.unwrap() as i32,
                    x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
                    y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
                );

                // Do the convolution.
                let mut r = 0.0;
                let mut g = 0.0;
                let mut b = 0.0;
                let mut a = 0.0;

                for (x, y, pixel) in
                    PixelRectangle::new(&input_surface, bounds, kernel_bounds, self.edge_mode)
                {
                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;

                    r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
                    g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
                    b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];

                    if !self.preserve_alpha {
                        a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
                    }
                }

                // If preserve_alpha is true, set a to the source alpha value.
                if self.preserve_alpha {
                    a = f64::from(pixel.a) / 255.0;
                } else {
                    a = a / self.divisor.unwrap() + self.bias;
                }

                let clamped_a = clamp(a, 0.0, 1.0);

                let compute = |x| {
                    let x = x / self.divisor.unwrap() + self.bias * a;

                    let x = if self.preserve_alpha {
                        // Premultiply the output value.
                        clamp(x, 0.0, 1.0) * clamped_a
                    } else {
                        clamp(x, 0.0, clamped_a)
                    };

                    ((x * 255.0) + 0.5) as u8
                };

                let output_pixel = Pixel {
                    r: compute(r),
                    g: compute(g),
                    b: compute(b),
                    a: ((clamped_a * 255.0) + 0.5) as u8,
                };

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        let mut output_surface =
            SharedImageSurface::new(output_surface, input.surface().surface_type())?;

        if let Some((ox, oy)) = scale {
            // Scale the output surface back.
            output_surface = output_surface.scale_to(
                ctx.source_graphic().width(),
                ctx.source_graphic().height(),
                original_bounds,
                ox,
                oy,
            )?;

            bounds = original_bounds;
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: output_surface,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl Parse for EdgeMode {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<Self, ValueErrorKind> {
        parse_identifiers!(
            parser,
            "duplicate" => EdgeMode::Duplicate,
            "wrap" => EdgeMode::Wrap,
            "none" => EdgeMode::None,
        )
        .map_err(|_: ParseError| ValueErrorKind::parse_error("parse error"))
    }
}

// Used for the preserveAlpha attribute
impl Parse for bool {
    fn parse(parser: &mut Parser<'_, '_>) -> Result<Self, ValueErrorKind> {
        parse_identifiers!(
            parser,
            "false" => false,
            "true" => true,
        )
        .map_err(|_: ParseError| ValueErrorKind::parse_error("parse error"))
    }
}
<|endoftext|>


<commit_before>//
//
//
use arch::memory::{VAddr};
use core::ptr::RawPtr;

pub use self::memorymap::{MAP_PAD, MemoryMapEnt, MemoryMapBuilder};
pub use self::memorymap::{StateReserved,StateUsed,StateFree};

pub mod phys;
pub mod virt;
pub mod heap;

pub mod memorymap;

pub fn c_string_valid(c_str: *const i8) -> bool
{
	// 1. Check first page
	if ! ::arch::memory::virt::is_reserved(c_str as VAddr) {
		return false;
	}

	unsafe
	{
		let mut ptr = c_str;
		while *ptr != 0
		{
			ptr = ptr.offset(1);
			if ptr as uint % ::PAGE_SIZE == 0
			{
				if ! ::arch::memory::virt::is_reserved(ptr as VAddr) {
					return false;
				}
			}
		}
	}

	true
}

// vim: ft=rust

<commit_msg>Core/Memory - Add a buffer validate function<commit_after>//
//
//
use arch::memory::{VAddr};
use core::ptr::RawPtr;

pub use self::memorymap::{MAP_PAD, MemoryMapEnt, MemoryMapBuilder};
pub use self::memorymap::{StateReserved,StateUsed,StateFree};

pub mod phys;
pub mod virt;
pub mod heap;

pub mod memorymap;

pub fn c_string_valid(c_str: *const i8) -> bool
{
	// 1. Check first page
	if ! ::arch::memory::virt::is_reserved(c_str as VAddr) {
		return false;
	}

	unsafe
	{
		let mut ptr = c_str;
		while *ptr != 0
		{
			ptr = ptr.offset(1);
			if ptr as uint % ::PAGE_SIZE == 0
			{
				if ! ::arch::memory::virt::is_reserved(ptr as VAddr) {
					return false;
				}
			}
		}
	}

	true
}

pub fn buf_valid(ptr: *const (), mut size: uint) -> bool
{
	let mut addr = ptr as VAddr;
	if ! ::arch::memory::virt::is_reserved(addr) {
		return false;
	}
	let rem_ofs = ::PAGE_SIZE - addr % ::PAGE_SIZE;

	if size > rem_ofs
	{
		addr += rem_ofs;
		size -= rem_ofs;
		while size != 0
		{
			if ! ::arch::memory::virt::is_reserved(addr) {
				return false;
			}
			if size > ::PAGE_SIZE {
				size -= ::PAGE_SIZE;
				addr += ::PAGE_SIZE;
			}
			else {
				break;
			}
		}
	}

	true
}

// vim: ft=rust

<|endoftext|>


<commit_before>// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

// CHECK-LABEL: @already_sliced_no_bounds_check
#[no_mangle]
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// make sure we're checking for the right thing: there can be a panic if the slice is too small
// CHECK-LABEL: @already_sliced_bounds_check
#[no_mangle]
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK: panic_bounds_check
    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}
<commit_msg>elaborate, add check for exact bounds<commit_after>// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

// Make sure no bounds checks are emitted in the loop when upfront slicing
// ensures that the slices are big enough.
// In particular, bounds checks were not always optimized out if the upfront
// check was for a greater len than the loop requires.
// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
// `already_sliced_no_bounds_check_exact` was)
// CHECK-LABEL: @already_sliced_no_bounds_check
#[no_mangle]
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// CHECK-LABEL: @already_sliced_no_bounds_check_exact
#[no_mangle]
pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK-NOT: panic_bounds_check
    let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}

// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
// CHECK-LABEL: @already_sliced_bounds_check
#[no_mangle]
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
    // CHECK: slice_index_len_fail
    // CHECK: panic_bounds_check
    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
    for i in 0..1024 {
        c[i] = a[i] ^ b[i];
    }
}
<|endoftext|>


<commit_before>/// Implementation must match exactly
/// `ToJsonName()` function in C++ `descriptor.cc`.
pub fn json_name(input: &str) -> String {
    let mut capitalize_next = false;
    let mut result = String::with_capacity(input.len());

    for c in input.chars() {
        if c == '_' {
            capitalize_next = true;
        } else if capitalize_next {
            result.extend(c.to_uppercase());
            capitalize_next = false;
        } else {
            result.push(c);
        }
    }

    result
}
<commit_msg>Add doc(hidden) to json_name function<commit_after>/// Implementation must match exactly
/// `ToJsonName()` function in C++ `descriptor.cc`.
#[doc(hidden)]
pub fn json_name(input: &str) -> String {
    let mut capitalize_next = false;
    let mut result = String::with_capacity(input.len());

    for c in input.chars() {
        if c == '_' {
            capitalize_next = true;
        } else if capitalize_next {
            result.extend(c.to_uppercase());
            capitalize_next = false;
        } else {
            result.push(c);
        }
    }

    result
}
<|endoftext|>


<commit_before>use std::io::File;
use serialize::hex::ToHex;
use rust_crypto::md5::Md5;
use rust_crypto::digest::Digest;

pub trait DataStore {
  fn write(&self, data: &[u8]) -> ();
}

pub struct FileStore{
  path: String,
}

impl FileStore{
  pub fn new(path: String) -> FileStore {
    FileStore {
      path: path,
    }
  }
}

impl DataStore for FileStore{
  fn write(&self, data: &[u8]){
    let mut hash = Md5::new();
    hash.input(data);
    let mut hashbits: [u8, ..16] = [0u8, ..16];
    hash.result(&mut hashbits);
    let root: Path = Path::new(self.path.as_slice());
    let path = root.join(hashbits.as_slice().to_hex());

    let mut file = File::create(&path);
    file.write(data);
  }
}

<commit_msg>Fix FileStore write method, includes : - Create root folders if don't exist - Handles errors and make them verbose<commit_after>use std::io::fs;
use std::io::{File, USER_RWX};
use serialize::hex::ToHex;
use rust_crypto::md5::Md5;
use rust_crypto::digest::Digest;

pub trait DataStore {
    fn write(&self, data: &[u8]) -> ();
}

pub struct FileStore{
    root: Path,
}

impl FileStore{
    pub fn new(path: &str) -> FileStore {
        let root = Path::new(path);

        match fs::mkdir_recursive(&root, USER_RWX) {
            Ok(_) => {},
            Err(e) => println!("Folder error: {}", e.kind),
        }

        FileStore {
            root: root,
        }
    }
}

impl DataStore for FileStore{
    fn write(&self, content: &[u8]){
        let mut hash = Md5::new();
        hash.input(data);

        let mut hashbits = [0u8, ..16];
        hash.result(&mut hashbits);

        let path = self.root.join(hashbits.as_slice().to_hex());

        let mut file = match File::create(&path) {
            Ok(f) => f,
            Err(e) => panic!("File error: {}", e),
        };

        match file.write(data) {
            Ok(_) => {},
            Err(e) => panic!("File error: {}", e),
        };
    }
}
<|endoftext|>


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

use capnp::capability::{FromServer};
use capnp_rpc::ez_rpc::EzRpcClient;
use capnp_rpc::capability::{InitRequest, LocalClient, WaitForContent};
use calculator_capnp::calculator;

#[derive(Copy)]
pub struct PowerFunction;

impl calculator::function::Server for PowerFunction {
    fn call(&mut self, mut context : calculator::function::CallContext) {
        use std::num::Float;

        let (params, mut results) = context.get();
        let params = params.get_params().unwrap();
        if params.len() != 2 {
            return context.fail("Wrong number of parameters".to_string());
        };
        results.set_value(params.get(0).powf(params.get(1)));
        context.done();
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    let mut rpc_client = EzRpcClient::new(&args[2][..]).unwrap();

    let calculator : calculator::Client = rpc_client.get_main();

    {
        //# Make a request that just evaluates the literal value 123.
        //#
        //# What's interesting here is that evaluate() returns a "Value", which is
        //# another interface and therefore points back to an object living on the
        //# server.  We then have to call read() on that object to read it.
        //# However, even though we are making two RPC's, this block executes in
        //# *one* network round trip because of promise pipelining:  we do not wait
        //# for the first call to complete before we send the second call to the
        //# server.

        println!("Evaluating a literal... ");

        let mut request = calculator.evaluate_request();
        request.init().init_expression().set_literal(123.0);

        let eval_promise = request.send();

        let mut read_promise = eval_promise.pipeline.get_value().read_request().send();

        let response = read_promise.wait().unwrap();
        assert_eq!(response.get_value(), 123.0);

        println!("PASS")
    }

    {
        //# Make a request to evaluate 123 + 45 - 67.
        //#
        //# The Calculator interface requires that we first call getOperator() to
        //# get the addition and subtraction functions, then call evaluate() to use
        //# them.  But, once again, we can get both functions, call evaluate(), and
        //# then read() the result -- four RPCs -- in the time of *one* network
        //# round trip, because of promise pipelining.

        println!("Using add and subtract... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let subtract = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Subtract);
            request.send().pipeline.get_func()
        };

        let mut request = calculator.evaluate_request();

        let mut subtract_call = request.init().init_expression().init_call();
        subtract_call.set_function(subtract);
        let mut subtract_params = subtract_call.init_params(2);
        subtract_params.borrow().get(1).set_literal(67.0);

        let mut add_call = subtract_params.get(0).init_call();
        add_call.set_function(add);
        let mut add_params = add_call.init_params(2);
        add_params.borrow().get(0).set_literal(123.0);
        add_params.get(1).set_literal(45.0);

        let eval_promise = request.send();
        let mut read_promise = eval_promise.pipeline.get_value().read_request().send();
        let response = read_promise.wait().unwrap();
        assert_eq!(response.get_value(), 101.0);

        println!("PASS");
    }

    {
        //# Make a request to evaluate 4 * 6, then use the result in two more
        //# requests that add 3 and 5.
        //#
        //# Since evaluate() returns its result wrapped in a `Value`, we can pass
        //# that `Value` back to the server in subsequent requests before the first
        //# `evaluate()` has actually returned.  Thus, this example again does only
        //# one network round trip.

        println!("Pipelining eval() calls... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let multiply = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Multiply);
            request.send().pipeline.get_func()
        };

        //# Build the request to evaluate 4 * 6
        let mut request = calculator.evaluate_request();

        let mut multiply_call = request.init().init_expression().init_call();
        multiply_call.set_function(multiply);
        let mut multiply_params = multiply_call.init_params(2);
        multiply_params.borrow().get(0).set_literal(4.0);
        multiply_params.get(1).set_literal(6.0);

        let multiply_result = request.send().pipeline.get_value();

        //# Use the result in two calls that add 3 and 5.

        let mut add3_request = calculator.evaluate_request();
        let mut add3_call = add3_request.init().init_expression().init_call();
        add3_call.set_function(add.clone());
        let mut add3_params = add3_call.init_params(2);
        add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
        add3_params.get(1).set_literal(3.0);
        let mut add3_promise = add3_request.send().pipeline.get_value().read_request().send();

        let mut add5_request = calculator.evaluate_request();
        let mut add5_call = add5_request.init().init_expression().init_call();
        add5_call.set_function(add);
        let mut add5_params = add5_call.init_params(2);
        add5_params.borrow().get(0).set_previous_result(multiply_result);
        add5_params.get(1).set_literal(5.0);
        let mut add5_promise = add5_request.send().pipeline.get_value().read_request().send();

        assert!(add3_promise.wait().unwrap().get_value() == 27.0);
        assert!(add5_promise.wait().unwrap().get_value() == 29.0);

        println!("PASS");
    }

    {
        //# Our calculator interface supports defining functions.  Here we use it
        //# to define two functions and then make calls to them as follows:
        //#
        //#   f(x, y) = x * 100 + y
        //#   g(x) = f(x, x + 1) * 2;
        //#   f(12, 34)
        //#   g(21)
        //#
        //# Once again, the whole thing takes only one network round trip.

        println!("Defining functions... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let multiply = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Multiply);
            request.send().pipeline.get_func()
        };

        let f = {
            let mut request = calculator.def_function_request();
            let mut def_function_params = request.init();
            def_function_params.set_param_count(2);
            {
                let mut add_call = def_function_params.init_body().init_call();
                add_call.set_function(add.clone());
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(1).set_parameter(1);

                let mut multiply_call = add_params.get(0).init_call();
                multiply_call.set_function(multiply.clone());
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_parameter(0);
                multiply_params.get(1).set_literal(100.0);
            }
            request.send().pipeline.get_func()
        };

        let g = {
            let mut request = calculator.def_function_request();
            let mut def_function_params = request.init();
            def_function_params.set_param_count(1);
            {
                let mut multiply_call = def_function_params.init_body().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(1).set_literal(2.0);

                let mut f_call = multiply_params.get(0).init_call();
                f_call.set_function(f.clone());
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_parameter(0);

                let mut add_call = f_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_parameter(0);
                add_params.get(1).set_literal(1.0);
            }
            request.send().pipeline.get_func()
        };

        let mut f_eval_request = calculator.evaluate_request();
        let mut f_call = f_eval_request.init().init_expression().init_call();
        f_call.set_function(f);
        let mut f_params = f_call.init_params(2);
        f_params.borrow().get(0).set_literal(12.0);
        f_params.get(1).set_literal(34.0);
        let mut f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

        let mut g_eval_request = calculator.evaluate_request();
        let mut g_call = g_eval_request.init().init_expression().init_call();
        g_call.set_function(g);
        g_call.init_params(1).get(0).set_literal(21.0);
        let mut g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

        assert!(f_eval_promise.wait().unwrap().get_value() == 1234.0);
        assert!(g_eval_promise.wait().unwrap().get_value() == 4244.0);

        println!("PASS")
    }

    {
        //# Make a request that will call back to a function defined locally.
        //#
        //# Specifically, we will compute 2^(4 + 5).  However, exponent is not
        //# defined by the Calculator server.  So, we'll implement the Function
        //# interface locally and pass it to the server for it to use when
        //# evaluating the expression.
        //#
        //# This example requires two network round trips to complete, because the
        //# server calls back to the client once before finishing.  In this
        //# particular case, this could potentially be optimized by using a tail
        //# call on the server side -- see CallContext::tailCall().  However, to
        //# keep the example simpler, we haven't implemented this optimization in
        //# the sample server.

        println!("Using a callback... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let mut request = calculator.evaluate_request();
        {
            let mut pow_call = request.init().init_expression().init_call();
            pow_call.set_function(
                calculator::function::ToClient(PowerFunction).from_server(None::<LocalClient>));
            let mut pow_params = pow_call.init_params(2);
            pow_params.borrow().get(0).set_literal(2.0);

            let mut add_call = pow_params.get(1).init_call();
            add_call.set_function(add);
            let mut add_params = add_call.init_params(2);
            add_params.borrow().get(0).set_literal(4.0);
            add_params.get(1).set_literal(5.0);
        }

        let mut response_promise = request.send().pipeline.get_value().read_request().send();
        let response = response_promise.wait().unwrap();

        assert!(response.get_value() == 512.0);

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

use capnp::capability::{FromServer};
use capnp_rpc::ez_rpc::EzRpcClient;
use capnp_rpc::capability::{InitRequest, LocalClient, WaitForContent};
use calculator_capnp::calculator;

#[derive(Copy)]
pub struct PowerFunction;

impl calculator::function::Server for PowerFunction {
    fn call(&mut self, mut context : calculator::function::CallContext) {
        let (params, mut results) = context.get();
        let params = params.get_params().unwrap();
        if params.len() != 2 {
            return context.fail("Wrong number of parameters".to_string());
        };
        results.set_value(params.get(0).powf(params.get(1)));
        context.done();
    }
}

pub fn main() {
    let args : Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    let mut rpc_client = EzRpcClient::new(&args[2][..]).unwrap();

    let calculator : calculator::Client = rpc_client.get_main();

    {
        //# Make a request that just evaluates the literal value 123.
        //#
        //# What's interesting here is that evaluate() returns a "Value", which is
        //# another interface and therefore points back to an object living on the
        //# server.  We then have to call read() on that object to read it.
        //# However, even though we are making two RPC's, this block executes in
        //# *one* network round trip because of promise pipelining:  we do not wait
        //# for the first call to complete before we send the second call to the
        //# server.

        println!("Evaluating a literal... ");

        let mut request = calculator.evaluate_request();
        request.init().init_expression().set_literal(123.0);

        let eval_promise = request.send();

        let mut read_promise = eval_promise.pipeline.get_value().read_request().send();

        let response = read_promise.wait().unwrap();
        assert_eq!(response.get_value(), 123.0);

        println!("PASS")
    }

    {
        //# Make a request to evaluate 123 + 45 - 67.
        //#
        //# The Calculator interface requires that we first call getOperator() to
        //# get the addition and subtraction functions, then call evaluate() to use
        //# them.  But, once again, we can get both functions, call evaluate(), and
        //# then read() the result -- four RPCs -- in the time of *one* network
        //# round trip, because of promise pipelining.

        println!("Using add and subtract... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let subtract = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Subtract);
            request.send().pipeline.get_func()
        };

        let mut request = calculator.evaluate_request();

        let mut subtract_call = request.init().init_expression().init_call();
        subtract_call.set_function(subtract);
        let mut subtract_params = subtract_call.init_params(2);
        subtract_params.borrow().get(1).set_literal(67.0);

        let mut add_call = subtract_params.get(0).init_call();
        add_call.set_function(add);
        let mut add_params = add_call.init_params(2);
        add_params.borrow().get(0).set_literal(123.0);
        add_params.get(1).set_literal(45.0);

        let eval_promise = request.send();
        let mut read_promise = eval_promise.pipeline.get_value().read_request().send();
        let response = read_promise.wait().unwrap();
        assert_eq!(response.get_value(), 101.0);

        println!("PASS");
    }

    {
        //# Make a request to evaluate 4 * 6, then use the result in two more
        //# requests that add 3 and 5.
        //#
        //# Since evaluate() returns its result wrapped in a `Value`, we can pass
        //# that `Value` back to the server in subsequent requests before the first
        //# `evaluate()` has actually returned.  Thus, this example again does only
        //# one network round trip.

        println!("Pipelining eval() calls... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let multiply = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Multiply);
            request.send().pipeline.get_func()
        };

        //# Build the request to evaluate 4 * 6
        let mut request = calculator.evaluate_request();

        let mut multiply_call = request.init().init_expression().init_call();
        multiply_call.set_function(multiply);
        let mut multiply_params = multiply_call.init_params(2);
        multiply_params.borrow().get(0).set_literal(4.0);
        multiply_params.get(1).set_literal(6.0);

        let multiply_result = request.send().pipeline.get_value();

        //# Use the result in two calls that add 3 and 5.

        let mut add3_request = calculator.evaluate_request();
        let mut add3_call = add3_request.init().init_expression().init_call();
        add3_call.set_function(add.clone());
        let mut add3_params = add3_call.init_params(2);
        add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
        add3_params.get(1).set_literal(3.0);
        let mut add3_promise = add3_request.send().pipeline.get_value().read_request().send();

        let mut add5_request = calculator.evaluate_request();
        let mut add5_call = add5_request.init().init_expression().init_call();
        add5_call.set_function(add);
        let mut add5_params = add5_call.init_params(2);
        add5_params.borrow().get(0).set_previous_result(multiply_result);
        add5_params.get(1).set_literal(5.0);
        let mut add5_promise = add5_request.send().pipeline.get_value().read_request().send();

        assert!(add3_promise.wait().unwrap().get_value() == 27.0);
        assert!(add5_promise.wait().unwrap().get_value() == 29.0);

        println!("PASS");
    }

    {
        //# Our calculator interface supports defining functions.  Here we use it
        //# to define two functions and then make calls to them as follows:
        //#
        //#   f(x, y) = x * 100 + y
        //#   g(x) = f(x, x + 1) * 2;
        //#   f(12, 34)
        //#   g(21)
        //#
        //# Once again, the whole thing takes only one network round trip.

        println!("Defining functions... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let multiply = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Multiply);
            request.send().pipeline.get_func()
        };

        let f = {
            let mut request = calculator.def_function_request();
            let mut def_function_params = request.init();
            def_function_params.set_param_count(2);
            {
                let mut add_call = def_function_params.init_body().init_call();
                add_call.set_function(add.clone());
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(1).set_parameter(1);

                let mut multiply_call = add_params.get(0).init_call();
                multiply_call.set_function(multiply.clone());
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_parameter(0);
                multiply_params.get(1).set_literal(100.0);
            }
            request.send().pipeline.get_func()
        };

        let g = {
            let mut request = calculator.def_function_request();
            let mut def_function_params = request.init();
            def_function_params.set_param_count(1);
            {
                let mut multiply_call = def_function_params.init_body().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(1).set_literal(2.0);

                let mut f_call = multiply_params.get(0).init_call();
                f_call.set_function(f.clone());
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_parameter(0);

                let mut add_call = f_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_parameter(0);
                add_params.get(1).set_literal(1.0);
            }
            request.send().pipeline.get_func()
        };

        let mut f_eval_request = calculator.evaluate_request();
        let mut f_call = f_eval_request.init().init_expression().init_call();
        f_call.set_function(f);
        let mut f_params = f_call.init_params(2);
        f_params.borrow().get(0).set_literal(12.0);
        f_params.get(1).set_literal(34.0);
        let mut f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

        let mut g_eval_request = calculator.evaluate_request();
        let mut g_call = g_eval_request.init().init_expression().init_call();
        g_call.set_function(g);
        g_call.init_params(1).get(0).set_literal(21.0);
        let mut g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

        assert!(f_eval_promise.wait().unwrap().get_value() == 1234.0);
        assert!(g_eval_promise.wait().unwrap().get_value() == 4244.0);

        println!("PASS")
    }

    {
        //# Make a request that will call back to a function defined locally.
        //#
        //# Specifically, we will compute 2^(4 + 5).  However, exponent is not
        //# defined by the Calculator server.  So, we'll implement the Function
        //# interface locally and pass it to the server for it to use when
        //# evaluating the expression.
        //#
        //# This example requires two network round trips to complete, because the
        //# server calls back to the client once before finishing.  In this
        //# particular case, this could potentially be optimized by using a tail
        //# call on the server side -- see CallContext::tailCall().  However, to
        //# keep the example simpler, we haven't implemented this optimization in
        //# the sample server.

        println!("Using a callback... ");

        let add = {
            let mut request = calculator.get_operator_request();
            request.init().set_op(calculator::Operator::Add);
            request.send().pipeline.get_func()
        };

        let mut request = calculator.evaluate_request();
        {
            let mut pow_call = request.init().init_expression().init_call();
            pow_call.set_function(
                calculator::function::ToClient(PowerFunction).from_server(None::<LocalClient>));
            let mut pow_params = pow_call.init_params(2);
            pow_params.borrow().get(0).set_literal(2.0);

            let mut add_call = pow_params.get(1).init_call();
            add_call.set_function(add);
            let mut add_params = add_call.init_params(2);
            add_params.borrow().get(0).set_literal(4.0);
            add_params.get(1).set_literal(5.0);
        }

        let mut response_promise = request.send().pipeline.get_value().read_request().send();
        let response = response_promise.wait().unwrap();

        assert!(response.get_value() == 512.0);

        println!("PASS");
    }
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format, BITS_PER_PIXEL};
use cairo::{self, Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::draw::BaseDraw;

/// The borders of a container.
///
/// This type just deals with rendering,
#[derive(Clone)]
pub struct Borders {
    /// The surface that contains the bytes we give to wlc to draw.
    surface: ImageSurface,
    /// How thick the borders should be. This affects how big the geometry is.
    pub thickness: u32,
    /// The geometry where the buffer is written.
    ///
    /// Should correspond with the geometry of the container.
    pub geometry: Geometry
}

impl Borders {
    pub fn new(mut geometry: Geometry, thickness: u32) -> Self {
        // Add the thickness to the geometry.
        geometry.origin.x -= thickness as i32;
        geometry.origin.y -= thickness as i32;
        geometry.size.w += thickness;
        geometry.size.h += thickness;
        error!("Initial geometry: {:?}", geometry);
        let Size { w, h } = geometry.size;
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        Borders {
            surface: surface,
            thickness: thickness,
            geometry: geometry
        }
    }

    pub fn render(&mut self) {
        warn!("Rendering {:#?}", self);
        let mut buffer = self.surface.get_data()
            .expect("Could not get border surface buffer");
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        let mut geometry = self.geometry;

        // If the buffer would clip the side, keep it within the bounds
        // This is done because wlc wraps if it goes beyond, which we don't
        // want for the borders.
        if geometry.origin.x < 0 {
            geometry.origin.x = 0;
        }
        if geometry.origin.x + geometry.size.w as i32 > output_res.w as i32 {
            let offset = (geometry.origin.x + geometry.size.w as i32) - output_res.w as i32;
            geometry.origin.x -= offset as i32;
        }
        if geometry.origin.y + geometry.size.h as i32 > output_res.h as i32 {
            let offset = (geometry.origin.y + geometry.size.h as i32) - output_res.h as i32;
            geometry.origin.y -= offset as i32;
        }
        if geometry.origin.y < 0 {
            geometry.origin.y = 0;
        }
        //error!("Rendering (abs) @ {:#?}", geometry);
        write_pixels(wlc_pixel_format::WLC_RGBA8888, geometry, &mut buffer);
    }

    /// Updates the position at which we render the buffer.
    ///
    /// Since this is a common operation, and does not resize the buffer,
    /// this is a method is here instead of in a draw struct
    /// for ergonomic and performance reasons.
    pub fn update_pos(&mut self, origin: Point) {
        self.geometry.origin = origin;
    }

    /// Updates/Creates the underlying geometry for the surface/buffer.
    ///
    /// This causes a reallocation of the buffer, do not call this
    /// in a tight loop unless you want memory fragmentation and
    /// bad performance.
    pub fn reallocate_buffer(&mut self, mut geometry: Geometry) {
        // Add the thickness to the geometry.
        error!("Reallocating buffer!");
        geometry.origin.x -= self.thickness as i32;
        geometry.origin.y -= self.thickness as i32;
        geometry.size.w += self.thickness;
        geometry.size.h += self.thickness;
        let Size { w, h } = geometry.size;
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        //let data = Vec::with_capacity(h as usize * stride as usize);
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        self.geometry = geometry;
        self.surface = surface;
    }

    /// Enables Cairo drawing capabilities on the borders.
    ///
    /// While drawing with Cairo, the underlying surface cannot be read.
    /// Borders is consumed in order for this to be checked at compile time.
    pub fn enable_cairo(self) -> Result<BaseDraw, cairo::Status> {
        let cairo = Context::new(&self.surface);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        cairo.set_operator(Operator::Source);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        Ok(BaseDraw::new(self, cairo))
    }
}

impl Debug for Borders {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Borders")
            .field("geometry", &self.geometry as &Debug)
            .field("thickness", &self.thickness as &Debug)
            .finish()
    }
}

impl PartialEq for Borders {
    fn eq(&self, other: &Borders) -> bool {
        self.geometry == other.geometry
    }
}

impl Eq for Borders {}

unsafe impl Send for Borders {}
unsafe impl Sync for Borders {}

/// Calculates the stride for ARgb32 encoded buffers
fn calculate_stride(width: u32) -> u32 {
    // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in cairoint.h
    // Can be found in the most recent version of the cairo source
    let stride_alignment = ::std::mem::size_of::<u32>() as u32;
    ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1))  & (stride_alignment.overflowing_neg().0)
}

#[allow(dead_code)]
fn drop_data(_: Box<[u8]>) { error!("Freeing data") }
<commit_msg>Don't reallocate if the buffer size doesn't change<commit_after>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format, BITS_PER_PIXEL};
use cairo::{self, Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::draw::BaseDraw;

/// The borders of a container.
///
/// This type just deals with rendering,
#[derive(Clone)]
pub struct Borders {
    /// The surface that contains the bytes we give to wlc to draw.
    surface: ImageSurface,
    /// How thick the borders should be. This affects how big the geometry is.
    pub thickness: u32,
    /// The geometry where the buffer is written.
    ///
    /// Should correspond with the geometry of the container.
    pub geometry: Geometry
}

impl Borders {
    pub fn new(mut geometry: Geometry, thickness: u32) -> Self {
        // Add the thickness to the geometry.
        geometry.origin.x -= thickness as i32;
        geometry.origin.y -= thickness as i32;
        geometry.size.w += thickness;
        geometry.size.h += thickness;
        error!("Initial geometry: {:?}", geometry);
        let Size { w, h } = geometry.size;
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        Borders {
            surface: surface,
            thickness: thickness,
            geometry: geometry
        }
    }

    pub fn render(&mut self) {
        warn!("Rendering {:#?}", self);
        let mut buffer = self.surface.get_data()
            .expect("Could not get border surface buffer");
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        let mut geometry = self.geometry;

        // If the buffer would clip the side, keep it within the bounds
        // This is done because wlc wraps if it goes beyond, which we don't
        // want for the borders.
        if geometry.origin.x < 0 {
            geometry.origin.x = 0;
        }
        if geometry.origin.x + geometry.size.w as i32 > output_res.w as i32 {
            let offset = (geometry.origin.x + geometry.size.w as i32) - output_res.w as i32;
            geometry.origin.x -= offset as i32;
        }
        if geometry.origin.y + geometry.size.h as i32 > output_res.h as i32 {
            let offset = (geometry.origin.y + geometry.size.h as i32) - output_res.h as i32;
            geometry.origin.y -= offset as i32;
        }
        if geometry.origin.y < 0 {
            geometry.origin.y = 0;
        }
        //error!("Rendering (abs) @ {:#?}", geometry);
        write_pixels(wlc_pixel_format::WLC_RGBA8888, geometry, &mut buffer);
    }

    /// Updates the position at which we render the buffer.
    ///
    /// Since this is a common operation, and does not resize the buffer,
    /// this is a method is here instead of in a draw struct
    /// for ergonomic and performance reasons.
    pub fn update_pos(&mut self, origin: Point) {
        self.geometry.origin = origin;
    }

    /// Updates/Creates the underlying geometry for the surface/buffer.
    ///
    /// This causes a reallocation of the buffer, do not call this
    /// in a tight loop unless you want memory fragmentation and
    /// bad performance.
    pub fn reallocate_buffer(&mut self, mut geometry: Geometry) {
        // Add the thickness to the geometry.
        error!("Reallocating buffer!");
        geometry.origin.x -= self.thickness as i32;
        geometry.origin.y -= self.thickness as i32;
        geometry.size.w += self.thickness;
        geometry.size.h += self.thickness;
        let Size { w, h } = geometry.size;
        if w == self.geometry.size.w && h == self.geometry.size.h {
            warn!("Geometry is same size, not reallocating");
            return;
        }
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        //let data = Vec::with_capacity(h as usize * stride as usize);
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        self.geometry = geometry;
        self.surface = surface;
    }

    /// Enables Cairo drawing capabilities on the borders.
    ///
    /// While drawing with Cairo, the underlying surface cannot be read.
    /// Borders is consumed in order for this to be checked at compile time.
    pub fn enable_cairo(self) -> Result<BaseDraw, cairo::Status> {
        let cairo = Context::new(&self.surface);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        cairo.set_operator(Operator::Source);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        Ok(BaseDraw::new(self, cairo))
    }
}

impl Debug for Borders {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Borders")
            .field("geometry", &self.geometry as &Debug)
            .field("thickness", &self.thickness as &Debug)
            .finish()
    }
}

impl PartialEq for Borders {
    fn eq(&self, other: &Borders) -> bool {
        self.geometry == other.geometry
    }
}

impl Eq for Borders {}

unsafe impl Send for Borders {}
unsafe impl Sync for Borders {}

/// Calculates the stride for ARgb32 encoded buffers
fn calculate_stride(width: u32) -> u32 {
    // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in cairoint.h
    // Can be found in the most recent version of the cairo source
    let stride_alignment = ::std::mem::size_of::<u32>() as u32;
    ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1))  & (stride_alignment.overflowing_neg().0)
}

#[allow(dead_code)]
fn drop_data(_: Box<[u8]>) { error!("Freeing data") }
<|endoftext|>


<commit_before>use super::raw;
use std::fmt;
use std::cell::RefCell;

pub struct Document<'d> {
    storage: &'d raw::Storage,
    connections: RefCell<&'d raw::Connections>,
}

impl<'d> Document<'d> {
    pub fn new(storage: &'d raw::Storage, connections: &'d raw::Connections) -> Document<'d> {
        Document {
            storage: storage,
            connections: RefCell::new(connections),
        }
    }

    fn wrap_element(&'d self, node: *mut raw::Element) -> Element<'d> {
        Element {
            document: self,
            node: node,
        }
    }

    fn wrap_attribute(&'d self, node: *mut raw::Attribute) -> Attribute<'d> {
        Attribute {
            document: self,
            node: node,
        }
    }

    pub fn create_element(&'d self, name: &str) -> Element<'d> {
        self.wrap_element(self.storage.create_element(name))
    }
}

impl<'d> PartialEq for Document<'d> {
    fn eq(&self, other: &Document<'d>) -> bool {
        self as *const Document == other as *const Document
    }
}

impl<'d> fmt::Show for Document<'d> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Document {{ {} }}", self as *const Document)
    }
}

pub struct Element<'d> {
    document: &'d Document<'d>,
    node: *mut raw::Element,
}

impl<'d> Element<'d> {
    fn node(&self) -> &raw::Element { unsafe { &*self.node } }

    pub fn document(&self) -> &'d Document<'d> { self.document }
    pub fn name(&self) -> &str { self.node().name() }

    pub fn set_name(&self, name: &str) {
        self.document.storage.element_set_name(self.node, name)
    }

    pub fn parent(&'d self) -> Option<ParentOfChild<'d>> {
        let connections = self.document.connections.borrow();

        connections.element_parent(self.node).map(|n| {
            match n {
                raw::ElementPOC(n) => ElementPOC(self.document.wrap_element(n)),
            }
        })
    }

    pub fn append_child(&self, child: Element) {
        let connections = self.document.connections.borrow_mut();
        connections.append_element_child(self.node, child.node)
    }

    pub fn children(&'d self) -> Vec<ChildOfElement<'d>> {
        let connections = self.document.connections.borrow();
        // This is safe because we copy of the children, and the
        // children are never deallocated.
        unsafe {
            let raw_children = connections.element_children(self.node);
            raw_children.iter().map(|n| match n {
                &raw::ElementCOE(n) => ElementCOE(self.document.wrap_element(n)),
            }).collect()
        }
    }

    pub fn attributes(&self) -> Vec<Attribute<'d>> {
        let connections = self.document.connections.borrow();
        // This is safe because we copy of the children, and the
        // children are never deallocated.
        unsafe {
            connections.attributes(self.node).iter().map(|n| {
                self.document.wrap_attribute(*n)
            }).collect()
        }
    }

    pub fn set_attribute_value(&self, name: &str, value: &str) -> Attribute<'d> {
        let attr = self.document.storage.create_attribute(name, value);
        let connections = self.document.connections.borrow_mut();
        connections.set_attribute(self.node, attr);
        self.document.wrap_attribute(attr)
    }

    pub fn attribute_value(&self, name: &str) -> Option<&'d str> {
        let connections = self.document.connections.borrow();
        connections.attribute(self.node, name).map(|a| {
            let a_r = unsafe { &*a };
            a_r.value()
        })
    }
}

impl<'d> PartialEq for Element<'d> {
    fn eq(&self, other: &Element<'d>) -> bool {
        self.node == other.node
    }
}

impl<'d> fmt::Show for Element<'d> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let node = unsafe { &* self.node };
        write!(f, "Element {{ name: {}  }}", node.name())
    }
}

pub struct Attribute<'d> {
    document: &'d Document<'d>,
    node: *mut raw::Attribute,
}

impl<'d> Attribute<'d> {
    fn node(&self) -> &raw::Attribute { unsafe { &*self.node } }

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

    pub fn parent(&self) -> Option<Element<'d>> {
        let connections = self.document.connections.borrow();
        connections.attribute_parent(self.node).map(|n| {
            self.document.wrap_element(n)
        })
    }
}

#[deriving(PartialEq,Show)]
pub enum ChildOfElement<'d> {
    ElementCOE(Element<'d>)
}

impl<'d> ChildOfElement<'d> {
    pub fn element(self) -> Option<Element<'d>> {
        match self {
            ElementCOE(n) => Some(n),
        }
    }
}

#[deriving(PartialEq,Show)]
pub enum ParentOfChild<'d> {
    ElementPOC(Element<'d>),
}

#[cfg(test)]
mod test {
    use super::super::Package;
    use super::{ElementCOE};
    use super::{ElementPOC};

    #[test]
    fn elements_belong_to_a_document() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("alpha");

        assert_eq!(&doc, element.document());
    }

    #[test]
    fn elements_can_have_element_children() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        let beta  = doc.create_element("beta");

        alpha.append_child(beta);

        let children = alpha.children();

        assert_eq!(children[0], ElementCOE(beta));
    }

    #[test]
    fn element_children_are_ordered() {
        let package = Package::new();
        let doc = package.as_document();

        let greek = doc.create_element("greek");
        let alpha = doc.create_element("alpha");
        let omega = doc.create_element("omega");

        greek.append_child(alpha);
        greek.append_child(omega);

        let children = greek.children();

        assert_eq!(children[0], ElementCOE(alpha));
        assert_eq!(children[1], ElementCOE(omega));
    }

    #[test]
    fn element_children_know_their_parent() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        let beta  = doc.create_element("beta");

        alpha.append_child(beta);

        assert_eq!(Some(ElementPOC(alpha)), beta.parent());
    }

    #[test]
    fn changing_parent_of_element_removes_element_from_original_parent() {
        let package = Package::new();
        let doc = package.as_document();

        let parent1 = doc.create_element("parent1");
        let parent2 = doc.create_element("parent2");
        let child = doc.create_element("child");

        parent1.append_child(child);
        parent2.append_child(child);

        assert!(parent1.children().is_empty());
        assert_eq!(1, parent2.children().len());
    }

    #[test]
    fn elements_can_be_renamed() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        alpha.set_name("beta");
        assert_eq!(alpha.name(), "beta");
    }

    #[test]
    fn elements_have_attributes() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("hello", "world");

        assert_eq!(Some("world"), element.attribute_value("hello"));
    }

    #[test]
    fn attributes_know_their_element() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");
        let attr = element.set_attribute_value("hello", "world");

        assert_eq!(Some(element), attr.parent());
    }

    #[test]
    fn attributes_can_be_reset() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("hello", "world");
        element.set_attribute_value("hello", "galaxy");

        assert_eq!(Some("galaxy"), element.attribute_value("hello"));
    }

    #[test]
    fn attributes_can_be_iterated() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("name1", "value1");
        element.set_attribute_value("name2", "value2");

        let mut attrs = element.attributes();
        attrs.sort_by(|a, b| a.name().cmp(b.name()));

        assert_eq!(2, attrs.len());
        assert_eq!("name1",  attrs[0].name());
        assert_eq!("value1", attrs[0].value());
        assert_eq!("name2",  attrs[1].name());
        assert_eq!("value2", attrs[1].value());
    }
}
<commit_msg>Fat DOM attributes belong to a document<commit_after>use super::raw;
use std::fmt;
use std::cell::RefCell;

pub struct Document<'d> {
    storage: &'d raw::Storage,
    connections: RefCell<&'d raw::Connections>,
}

impl<'d> Document<'d> {
    pub fn new(storage: &'d raw::Storage, connections: &'d raw::Connections) -> Document<'d> {
        Document {
            storage: storage,
            connections: RefCell::new(connections),
        }
    }

    fn wrap_element(&'d self, node: *mut raw::Element) -> Element<'d> {
        Element {
            document: self,
            node: node,
        }
    }

    fn wrap_attribute(&'d self, node: *mut raw::Attribute) -> Attribute<'d> {
        Attribute {
            document: self,
            node: node,
        }
    }

    pub fn create_element(&'d self, name: &str) -> Element<'d> {
        self.wrap_element(self.storage.create_element(name))
    }
}

impl<'d> PartialEq for Document<'d> {
    fn eq(&self, other: &Document<'d>) -> bool {
        self as *const Document == other as *const Document
    }
}

impl<'d> fmt::Show for Document<'d> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Document {{ {} }}", self as *const Document)
    }
}

macro_rules! node(
    ($name:ident, $raw:ty) => (
        pub struct $name<'d> {
            document: &'d Document<'d>,
            node: *mut $raw,
        }

        impl<'d> $name<'d> {
            fn node(&self) -> &$raw { unsafe { &*self.node } }

            pub fn document(&self) -> &'d Document<'d> { self.document }
        }

        impl<'d> PartialEq for $name<'d> {
            fn eq(&self, other: &$name<'d>) -> bool {
                self.node == other.node
            }
        }
    )
)

node!(Element, raw::Element)

impl<'d> Element<'d> {
    pub fn name(&self) -> &str { self.node().name() }

    pub fn set_name(&self, name: &str) {
        self.document.storage.element_set_name(self.node, name)
    }

    pub fn parent(&'d self) -> Option<ParentOfChild<'d>> {
        let connections = self.document.connections.borrow();

        connections.element_parent(self.node).map(|n| {
            match n {
                raw::ElementPOC(n) => ElementPOC(self.document.wrap_element(n)),
            }
        })
    }

    pub fn append_child(&self, child: Element) {
        let connections = self.document.connections.borrow_mut();
        connections.append_element_child(self.node, child.node)
    }

    pub fn children(&'d self) -> Vec<ChildOfElement<'d>> {
        let connections = self.document.connections.borrow();
        // This is safe because we copy of the children, and the
        // children are never deallocated.
        unsafe {
            let raw_children = connections.element_children(self.node);
            raw_children.iter().map(|n| match n {
                &raw::ElementCOE(n) => ElementCOE(self.document.wrap_element(n)),
            }).collect()
        }
    }

    pub fn attributes(&self) -> Vec<Attribute<'d>> {
        let connections = self.document.connections.borrow();
        // This is safe because we copy of the children, and the
        // children are never deallocated.
        unsafe {
            connections.attributes(self.node).iter().map(|n| {
                self.document.wrap_attribute(*n)
            }).collect()
        }
    }

    pub fn set_attribute_value(&self, name: &str, value: &str) -> Attribute<'d> {
        let attr = self.document.storage.create_attribute(name, value);
        let connections = self.document.connections.borrow_mut();
        connections.set_attribute(self.node, attr);
        self.document.wrap_attribute(attr)
    }

    pub fn attribute_value(&self, name: &str) -> Option<&'d str> {
        let connections = self.document.connections.borrow();
        connections.attribute(self.node, name).map(|a| {
            let a_r = unsafe { &*a };
            a_r.value()
        })
    }
}

impl<'d> fmt::Show for Element<'d> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let node = unsafe { &* self.node };
        write!(f, "Element {{ name: {}  }}", node.name())
    }
}

node!(Attribute, raw::Attribute)

impl<'d> Attribute<'d> {
    pub fn name(&self)  -> &str { self.node().name() }
    pub fn value(&self) -> &str { self.node().value() }

    pub fn parent(&self) -> Option<Element<'d>> {
        let connections = self.document.connections.borrow();
        connections.attribute_parent(self.node).map(|n| {
            self.document.wrap_element(n)
        })
    }
}

#[deriving(PartialEq,Show)]
pub enum ChildOfElement<'d> {
    ElementCOE(Element<'d>)
}

impl<'d> ChildOfElement<'d> {
    pub fn element(self) -> Option<Element<'d>> {
        match self {
            ElementCOE(n) => Some(n),
        }
    }
}

#[deriving(PartialEq,Show)]
pub enum ParentOfChild<'d> {
    ElementPOC(Element<'d>),
}

#[cfg(test)]
mod test {
    use super::super::Package;
    use super::{ElementCOE};
    use super::{ElementPOC};

    #[test]
    fn elements_belong_to_a_document() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("alpha");

        assert_eq!(&doc, element.document());
    }

    #[test]
    fn elements_can_have_element_children() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        let beta  = doc.create_element("beta");

        alpha.append_child(beta);

        let children = alpha.children();

        assert_eq!(children[0], ElementCOE(beta));
    }

    #[test]
    fn element_children_are_ordered() {
        let package = Package::new();
        let doc = package.as_document();

        let greek = doc.create_element("greek");
        let alpha = doc.create_element("alpha");
        let omega = doc.create_element("omega");

        greek.append_child(alpha);
        greek.append_child(omega);

        let children = greek.children();

        assert_eq!(children[0], ElementCOE(alpha));
        assert_eq!(children[1], ElementCOE(omega));
    }

    #[test]
    fn element_children_know_their_parent() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        let beta  = doc.create_element("beta");

        alpha.append_child(beta);

        assert_eq!(Some(ElementPOC(alpha)), beta.parent());
    }

    #[test]
    fn changing_parent_of_element_removes_element_from_original_parent() {
        let package = Package::new();
        let doc = package.as_document();

        let parent1 = doc.create_element("parent1");
        let parent2 = doc.create_element("parent2");
        let child = doc.create_element("child");

        parent1.append_child(child);
        parent2.append_child(child);

        assert!(parent1.children().is_empty());
        assert_eq!(1, parent2.children().len());
    }

    #[test]
    fn elements_can_be_renamed() {
        let package = Package::new();
        let doc = package.as_document();

        let alpha = doc.create_element("alpha");
        alpha.set_name("beta");
        assert_eq!(alpha.name(), "beta");
    }

    #[test]
    fn attributes_belong_to_a_document() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("alpha");
        let attr = element.set_attribute_value("hello", "world");

        assert_eq!(&doc, attr.document());
    }

    #[test]
    fn elements_have_attributes() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("hello", "world");

        assert_eq!(Some("world"), element.attribute_value("hello"));
    }

    #[test]
    fn attributes_know_their_element() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");
        let attr = element.set_attribute_value("hello", "world");

        assert_eq!(Some(element), attr.parent());
    }

    #[test]
    fn attributes_can_be_reset() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("hello", "world");
        element.set_attribute_value("hello", "galaxy");

        assert_eq!(Some("galaxy"), element.attribute_value("hello"));
    }

    #[test]
    fn attributes_can_be_iterated() {
        let package = Package::new();
        let doc = package.as_document();

        let element = doc.create_element("element");

        element.set_attribute_value("name1", "value1");
        element.set_attribute_value("name2", "value2");

        let mut attrs = element.attributes();
        attrs.sort_by(|a, b| a.name().cmp(b.name()));

        assert_eq!(2, attrs.len());
        assert_eq!("name1",  attrs[0].name());
        assert_eq!("value1", attrs[0].value());
        assert_eq!("name2",  attrs[1].name());
        assert_eq!("value2", attrs[1].value());
    }
}
<|endoftext|>