<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod function_wrapper_cpp;
pub(crate) mod type_to_cpp;

use crate::{types::QualifiedName, CppFilePair};
use indoc::indoc;
use itertools::Itertools;
use std::collections::HashSet;
use syn::Type;
use type_to_cpp::type_to_cpp;

use super::{
    analysis::fun::{
        function_wrapper::{FunctionWrapper, FunctionWrapperPayload},
        FnAnalysis,
    },
    api::Api,
    ConvertError,
};

/// Instructions for new C++ which we need to generate.
#[derive(Clone)]
pub(crate) enum AdditionalNeed {
    MakeStringConstructor,
    FunctionWrapper(Box<FunctionWrapper>),
    CTypeTypedef(QualifiedName),
    ConcreteTemplatedTypeTypedef(QualifiedName, Box<Type>),
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
struct Header {
    name: &'static str,
    system: bool,
}

impl Header {
    fn system(name: &'static str) -> Self {
        Header { name, system: true }
    }

    fn user(name: &'static str) -> Self {
        Header {
            name,
            system: false,
        }
    }

    fn include_stmt(&self) -> String {
        if self.system {
            format!("#include <{}>", self.name)
        } else {
            format!("#include \"{}\"", self.name)
        }
    }
}

struct AdditionalFunction {
    type_definition: String, // are output before main declarations
    declaration: String,
    headers: Vec<Header>,
}

/// Generates additional C++ glue functions needed by autocxx.
/// In some ways it would be preferable to be able to pass snippets
/// of C++ through to `cxx` for inclusion in the C++ file which it
/// generates, and perhaps we'll explore that in future. But for now,
/// autocxx generates its own _additional_ C++ files which therefore
/// need to be built and included in linking procedures.
pub(crate) struct CppCodeGenerator {
    additional_functions: Vec<AdditionalFunction>,
    inclusions: String,
}

impl CppCodeGenerator {
    pub(crate) fn generate_cpp_code(
        inclusions: String,
        apis: &[Api<FnAnalysis>],
    ) -> Result<Option<CppFilePair>, ConvertError> {
        let mut gen = CppCodeGenerator::new(inclusions);
        gen.add_needs(apis.iter().filter_map(|api| api.additional_cpp()))?;
        Ok(gen.generate())
    }

    fn new(inclusions: String) -> Self {
        CppCodeGenerator {
            additional_functions: Vec::new(),
            inclusions,
        }
    }

    fn add_needs(
        &mut self,
        additions: impl Iterator<Item = AdditionalNeed>,
    ) -> Result<(), ConvertError> {
        for need in additions {
            match need {
                AdditionalNeed::MakeStringConstructor => self.generate_string_constructor(),
                AdditionalNeed::FunctionWrapper(by_value_wrapper) => {
                    self.generate_by_value_wrapper(&by_value_wrapper)?
                }
                AdditionalNeed::CTypeTypedef(tn) => self.generate_ctype_typedef(&tn),
                AdditionalNeed::ConcreteTemplatedTypeTypedef(tn, def) => {
                    self.generate_typedef(&tn, type_to_cpp(&def)?)
                }
            }
        }
        Ok(())
    }

    fn generate(&self) -> Option<CppFilePair> {
        if self.additional_functions.is_empty() {
            None
        } else {
            let headers: HashSet<Header> = self
                .additional_functions
                .iter()
                .map(|x| x.headers.iter().cloned())
                .flatten()
                .collect();
            let headers = headers.iter().map(|x| x.include_stmt()).join("\n");
            let type_definitions = self.concat_additional_items(|x| &x.type_definition);
            let declarations = self.concat_additional_items(|x| &x.declaration);
            let declarations = format!(
                "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
                headers, self.inclusions, type_definitions, declarations
            );
            log::info!("Additional C++ decls:\n{}", declarations);
            Some(CppFilePair {
                header: declarations.into_bytes(),
                implementation: None,
                header_name: "autocxxgen.h".into(),
            })
        }
    }

    fn concat_additional_items<F>(&self, field_access: F) -> String
    where
        F: FnMut(&AdditionalFunction) -> &str,
    {
        let mut s = self
            .additional_functions
            .iter()
            .map(field_access)
            .collect::<Vec<&str>>()
            .join("\n");
        s.push('\n');
        s
    }

    fn generate_string_constructor(&mut self) {
        let declaration = indoc! {"
        inline std::unique_ptr<std::string> make_string(::rust::Str str)
        { return std::make_unique<std::string>(std::string(str)); }
        "};
        let declaration = format!("{};", declaration);
        self.additional_functions.push(AdditionalFunction {
            type_definition: "".into(),
            declaration,
            headers: vec![
                Header::system("memory"),
                Header::system("string"),
                Header::user("cxx.h"),
            ],
        })
    }

    fn generate_by_value_wrapper(&mut self, details: &FunctionWrapper) -> Result<(), ConvertError> {
        // Even if the original function call is in a namespace,
        // we generate this wrapper in the global namespace.
        // We could easily do this the other way round, and when
        // cxx::bridge comes to support nested namespace mods then
        // we wil wish to do that to avoid name conflicts. However,
        // at the moment this is simpler because it avoids us having
        // to generate namespace blocks in the generated C++.
        let is_a_method = details.is_a_method;
        let name = &details.wrapper_function_name;
        let get_arg_name = |counter: usize| -> String {
            if is_a_method && counter == 0 {
                // For method calls that we generate, the first
                // argument name needs to be such that we recognize
                // it as a method in the second invocation of
                // bridge_converter after it's flowed again through
                // bindgen.
                // TODO this may not be the case any longer. We
                // may be able to remove this.
                "autocxx_gen_this".to_string()
            } else {
                format!("arg{}", counter)
            }
        };
        let args: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, ty)| {
                Ok(format!(
                    "{} {}",
                    ty.unconverted_type()?,
                    get_arg_name(counter)
                ))
            })
            .collect();
        let args = args?.join(", ");
        let ret_type = details
            .return_conversion
            .as_ref()
            .map_or(Ok("void".to_string()), |x| x.converted_type())?;
        let declaration = format!("{} {}({})", ret_type, name, args);
        let arg_list: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, conv)| conv.cpp_conversion(&get_arg_name(counter)))
            .collect();
        let mut arg_list = arg_list?.into_iter();
        let receiver = if is_a_method { arg_list.next() } else { None };
        let arg_list = arg_list.join(", ");
        let mut underlying_function_call = match &details.payload {
            FunctionWrapperPayload::Constructor => arg_list,
            FunctionWrapperPayload::FunctionCall(ns, id) => match receiver {
                Some(receiver) => format!("{}.{}({})", receiver, id.to_string(), arg_list),
                None => {
                    let underlying_function_call = ns
                        .into_iter()
                        .cloned()
                        .chain(std::iter::once(id.to_string()))
                        .join("::");
                    format!("{}({})", underlying_function_call, arg_list)
                }
            },
            FunctionWrapperPayload::StaticMethodCall(ns, ty_id, fn_id) => {
                let underlying_function_call = ns
                    .into_iter()
                    .cloned()
                    .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
                    .join("::");
                format!("{}({})", underlying_function_call, arg_list)
            }
        };
        if let Some(ret) = &details.return_conversion {
            underlying_function_call =
                format!("return {}", ret.cpp_conversion(&underlying_function_call)?);
        };
        let declaration = format!("{} {{ {}; }}", declaration, underlying_function_call,);
        self.additional_functions.push(AdditionalFunction {
            type_definition: "".into(),
            declaration,
            headers: vec![Header::system("memory")],
        });
        Ok(())
    }

    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
        let cpp_name = tn.to_cpp_name();
        self.generate_typedef(tn, cpp_name)
    }

    fn generate_typedef(&mut self, tn: &QualifiedName, definition: String) {
        let our_name = tn.get_final_item();
        self.additional_functions.push(AdditionalFunction {
            type_definition: format!("typedef {} {};", definition, our_name),
            declaration: "".into(),
            headers: Vec::new(),
        })
    }
}
<commit_msg>Make declarations and definitions optional<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod function_wrapper_cpp;
pub(crate) mod type_to_cpp;

use crate::{types::QualifiedName, CppFilePair};
use indoc::indoc;
use itertools::Itertools;
use std::collections::HashSet;
use syn::Type;
use type_to_cpp::type_to_cpp;

use super::{
    analysis::fun::{
        function_wrapper::{FunctionWrapper, FunctionWrapperPayload},
        FnAnalysis,
    },
    api::Api,
    ConvertError,
};

/// Instructions for new C++ which we need to generate.
#[derive(Clone)]
pub(crate) enum AdditionalNeed {
    MakeStringConstructor,
    FunctionWrapper(Box<FunctionWrapper>),
    CTypeTypedef(QualifiedName),
    ConcreteTemplatedTypeTypedef(QualifiedName, Box<Type>),
}

#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
struct Header {
    name: &'static str,
    system: bool,
}

impl Header {
    fn system(name: &'static str) -> Self {
        Header { name, system: true }
    }

    fn user(name: &'static str) -> Self {
        Header {
            name,
            system: false,
        }
    }

    fn include_stmt(&self) -> String {
        if self.system {
            format!("#include <{}>", self.name)
        } else {
            format!("#include \"{}\"", self.name)
        }
    }
}

struct AdditionalFunction {
    type_definition: Option<String>, // are output before main declarations
    declaration: Option<String>,
    headers: Vec<Header>,
}

/// Generates additional C++ glue functions needed by autocxx.
/// In some ways it would be preferable to be able to pass snippets
/// of C++ through to `cxx` for inclusion in the C++ file which it
/// generates, and perhaps we'll explore that in future. But for now,
/// autocxx generates its own _additional_ C++ files which therefore
/// need to be built and included in linking procedures.
pub(crate) struct CppCodeGenerator {
    additional_functions: Vec<AdditionalFunction>,
    inclusions: String,
}

impl CppCodeGenerator {
    pub(crate) fn generate_cpp_code(
        inclusions: String,
        apis: &[Api<FnAnalysis>],
    ) -> Result<Option<CppFilePair>, ConvertError> {
        let mut gen = CppCodeGenerator::new(inclusions);
        gen.add_needs(apis.iter().filter_map(|api| api.additional_cpp()))?;
        Ok(gen.generate())
    }

    fn new(inclusions: String) -> Self {
        CppCodeGenerator {
            additional_functions: Vec::new(),
            inclusions,
        }
    }

    fn add_needs(
        &mut self,
        additions: impl Iterator<Item = AdditionalNeed>,
    ) -> Result<(), ConvertError> {
        for need in additions {
            match need {
                AdditionalNeed::MakeStringConstructor => self.generate_string_constructor(),
                AdditionalNeed::FunctionWrapper(by_value_wrapper) => {
                    self.generate_by_value_wrapper(&by_value_wrapper)?
                }
                AdditionalNeed::CTypeTypedef(tn) => self.generate_ctype_typedef(&tn),
                AdditionalNeed::ConcreteTemplatedTypeTypedef(tn, def) => {
                    self.generate_typedef(&tn, type_to_cpp(&def)?)
                }
            }
        }
        Ok(())
    }

    fn generate(&self) -> Option<CppFilePair> {
        if self.additional_functions.is_empty() {
            None
        } else {
            let headers: HashSet<Header> = self
                .additional_functions
                .iter()
                .map(|x| x.headers.iter().cloned())
                .flatten()
                .collect();
            let headers = headers.iter().map(|x| x.include_stmt()).join("\n");
            let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
            let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
            let declarations = format!(
                "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
                headers, self.inclusions, type_definitions, declarations
            );
            log::info!("Additional C++ decls:\n{}", declarations);
            Some(CppFilePair {
                header: declarations.into_bytes(),
                implementation: None,
                header_name: "autocxxgen.h".into(),
            })
        }
    }

    fn concat_additional_items<F>(&self, field_access: F) -> String
    where
        F: FnMut(&AdditionalFunction) -> Option<&String>,
    {
        let mut s = self
            .additional_functions
            .iter()
            .map(field_access)
            .flatten()
            .join("\n");
        s.push('\n');
        s
    }

    fn generate_string_constructor(&mut self) {
        let declaration = indoc! {"
        inline std::unique_ptr<std::string> make_string(::rust::Str str)
        { return std::make_unique<std::string>(std::string(str)); }
        "};
        let declaration = Some(declaration.into());
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            headers: vec![
                Header::system("memory"),
                Header::system("string"),
                Header::user("cxx.h"),
            ],
        })
    }

    fn generate_by_value_wrapper(&mut self, details: &FunctionWrapper) -> Result<(), ConvertError> {
        // Even if the original function call is in a namespace,
        // we generate this wrapper in the global namespace.
        // We could easily do this the other way round, and when
        // cxx::bridge comes to support nested namespace mods then
        // we wil wish to do that to avoid name conflicts. However,
        // at the moment this is simpler because it avoids us having
        // to generate namespace blocks in the generated C++.
        let is_a_method = details.is_a_method;
        let name = &details.wrapper_function_name;
        let get_arg_name = |counter: usize| -> String {
            if is_a_method && counter == 0 {
                // For method calls that we generate, the first
                // argument name needs to be such that we recognize
                // it as a method in the second invocation of
                // bridge_converter after it's flowed again through
                // bindgen.
                // TODO this may not be the case any longer. We
                // may be able to remove this.
                "autocxx_gen_this".to_string()
            } else {
                format!("arg{}", counter)
            }
        };
        let args: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, ty)| {
                Ok(format!(
                    "{} {}",
                    ty.unconverted_type()?,
                    get_arg_name(counter)
                ))
            })
            .collect();
        let args = args?.join(", ");
        let ret_type = details
            .return_conversion
            .as_ref()
            .map_or(Ok("void".to_string()), |x| x.converted_type())?;
        let declaration = format!("{} {}({})", ret_type, name, args);
        let arg_list: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, conv)| conv.cpp_conversion(&get_arg_name(counter)))
            .collect();
        let mut arg_list = arg_list?.into_iter();
        let receiver = if is_a_method { arg_list.next() } else { None };
        let arg_list = arg_list.join(", ");
        let mut underlying_function_call = match &details.payload {
            FunctionWrapperPayload::Constructor => arg_list,
            FunctionWrapperPayload::FunctionCall(ns, id) => match receiver {
                Some(receiver) => format!("{}.{}({})", receiver, id.to_string(), arg_list),
                None => {
                    let underlying_function_call = ns
                        .into_iter()
                        .cloned()
                        .chain(std::iter::once(id.to_string()))
                        .join("::");
                    format!("{}({})", underlying_function_call, arg_list)
                }
            },
            FunctionWrapperPayload::StaticMethodCall(ns, ty_id, fn_id) => {
                let underlying_function_call = ns
                    .into_iter()
                    .cloned()
                    .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
                    .join("::");
                format!("{}({})", underlying_function_call, arg_list)
            }
        };
        if let Some(ret) = &details.return_conversion {
            underlying_function_call =
                format!("return {}", ret.cpp_conversion(&underlying_function_call)?);
        };
        let declaration = Some(format!(
            "{} {{ {}; }}",
            declaration, underlying_function_call,
        ));
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            headers: vec![Header::system("memory")],
        });
        Ok(())
    }

    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
        let cpp_name = tn.to_cpp_name();
        self.generate_typedef(tn, cpp_name)
    }

    fn generate_typedef(&mut self, tn: &QualifiedName, definition: String) {
        let our_name = tn.get_final_item();
        self.additional_functions.push(AdditionalFunction {
            type_definition: Some(format!("typedef {} {};", definition, our_name)),
            declaration: None,
            headers: Vec::new(),
        })
    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo::{MatrixTrait, PatternTrait};
use std::cell::{Cell, RefCell};

use allowed_url::AllowedUrl;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use handle::{self, RsvgHandle};
use length::*;
use node::*;
use parsers::{parse, parse_and_validate};
use property_bag::PropertyBag;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Length>,
    h: Cell<Length>,
    surface: RefCell<Option<cairo::ImageSurface>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(Length::default()),
            y: Cell::new(Length::default()),
            w: Cell::new(Length::default()),
            h: Cell::new(Length::default()),
            surface: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),
                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),
                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),

                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    // FIXME: use better errors here; these should be loading errors

                    let aurl = AllowedUrl::from_href(value, handle::get_base_url(handle).as_ref())
                        .map_err(|_| NodeError::value_error(attr, "invalid URL"))?;

                    *self.surface.borrow_mut() = Some(
                        // FIXME: translate the error better here
                        handle::load_image_to_surface(handle as *mut _, &aurl)
                            .map_err(|_| NodeError::value_error(attr, "could not load image"))?,
                    );
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx<'_>,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();

        if let Some(ref surface) = *self.surface.borrow() {
            let params = draw_ctx.get_view_params();

            let x = self.x.get().normalize(values, &params);
            let y = self.y.get().normalize(values, &params);
            let w = self.w.get().normalize(values, &params);
            let h = self.h.get().normalize(values, &params);

            if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
                return Ok(());
            }

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let aspect = self.aspect.get();

                if !values.is_overflow() && aspect.is_slice() {
                    dc.clip(x, y, w, h);
                }

                // The bounding box for <image> is decided by the values of x, y, w, h and not by
                // the final computed image bounds.
                let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                    cairo::Rectangle {
                        x,
                        y,
                        width: w,
                        height: h,
                    },
                ));

                let width = surface.get_width();
                let height = surface.get_height();
                if clipping || width == 0 || height == 0 {
                    return Ok(());
                }

                let width = f64::from(width);
                let height = f64::from(height);

                let (x, y, w, h) = aspect.compute(width, height, x, y, w, h);

                let cr = dc.get_cairo_context();

                cr.save();

                dc.set_affine_on_cr(&cr);
                cr.scale(w / width, h / height);
                let x = x * width / w;
                let y = y * height / h;

                cr.set_operator(cairo::Operator::from(values.comp_op));

                // We need to set extend appropriately, so can't use cr.set_source_surface().
                //
                // If extend is left at its default value (None), then bilinear scaling uses
                // transparency outside of the image producing incorrect results.
                // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                // transparent almost everywhere without this fix (which it shouldn't).
                let ptn = cairo::SurfacePattern::create(&surface);
                let mut matrix = cairo::Matrix::identity();
                matrix.translate(-x, -y);
                ptn.set_matrix(matrix);
                ptn.set_extend(cairo::Extend::Pad);
                cr.set_source(&cairo::Pattern::SurfacePattern(ptn));

                // Clip is needed due to extend being set to pad.
                cr.rectangle(x, y, width, height);
                cr.clip();

                cr.paint();

                cr.restore();

                dc.insert_bbox(&bbox);
                Ok(())
            })
        } else {
            Ok(())
        }
    }
}
<commit_msg>image.rs: use Href::without_fragment()<commit_after>use cairo;
use cairo::{MatrixTrait, PatternTrait};
use std::cell::{Cell, RefCell};

use allowed_url::AllowedUrl;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use bbox::BoundingBox;
use defs::Href;
use drawing_ctx::DrawingCtx;
use error::{NodeError, RenderingError};
use float_eq_cairo::ApproxEqCairo;
use handle::{self, RsvgHandle};
use length::*;
use node::*;
use parsers::{parse, parse_and_validate};
use property_bag::PropertyBag;

pub struct NodeImage {
    aspect: Cell<AspectRatio>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Length>,
    h: Cell<Length>,
    surface: RefCell<Option<cairo::ImageSurface>>,
}

impl NodeImage {
    pub fn new() -> NodeImage {
        NodeImage {
            aspect: Cell::new(AspectRatio::default()),
            x: Cell::new(Length::default()),
            y: Cell::new(Length::default()),
            w: Cell::new(Length::default()),
            h: Cell::new(Length::default()),
            surface: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeImage {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        // SVG element has overflow:hidden
        // https://www.w3.org/TR/SVG/styling.html#UAStyleSheet
        node.set_overflow_hidden();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),
                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),
                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),

                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    // FIXME: use better errors here; these should be loading errors

                    let href = Href::without_fragment(value)
                        .map_err(|_| NodeError::value_error(attr, "fragment not allowed here"))?;

                    let url = match href {
                        Href::PlainUri(u) => u,
                        _ => unreachable!(),
                    };

                    let aurl = AllowedUrl::from_href(&url, handle::get_base_url(handle).as_ref())
                        .map_err(|_| NodeError::value_error(attr, "invalid URL"))?;

                    *self.surface.borrow_mut() = Some(
                        // FIXME: translate the error better here
                        handle::load_image_to_surface(handle as *mut _, &aurl)
                            .map_err(|_| NodeError::value_error(attr, "could not load image"))?,
                    );
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx<'_>,
        clipping: bool,
    ) -> Result<(), RenderingError> {
        let values = cascaded.get();

        if let Some(ref surface) = *self.surface.borrow() {
            let params = draw_ctx.get_view_params();

            let x = self.x.get().normalize(values, &params);
            let y = self.y.get().normalize(values, &params);
            let w = self.w.get().normalize(values, &params);
            let h = self.h.get().normalize(values, &params);

            if w.approx_eq_cairo(&0.0) || h.approx_eq_cairo(&0.0) {
                return Ok(());
            }

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                let aspect = self.aspect.get();

                if !values.is_overflow() && aspect.is_slice() {
                    dc.clip(x, y, w, h);
                }

                // The bounding box for <image> is decided by the values of x, y, w, h and not by
                // the final computed image bounds.
                let bbox = BoundingBox::new(&dc.get_cairo_context().get_matrix()).with_rect(Some(
                    cairo::Rectangle {
                        x,
                        y,
                        width: w,
                        height: h,
                    },
                ));

                let width = surface.get_width();
                let height = surface.get_height();
                if clipping || width == 0 || height == 0 {
                    return Ok(());
                }

                let width = f64::from(width);
                let height = f64::from(height);

                let (x, y, w, h) = aspect.compute(width, height, x, y, w, h);

                let cr = dc.get_cairo_context();

                cr.save();

                dc.set_affine_on_cr(&cr);
                cr.scale(w / width, h / height);
                let x = x * width / w;
                let y = y * height / h;

                cr.set_operator(cairo::Operator::from(values.comp_op));

                // We need to set extend appropriately, so can't use cr.set_source_surface().
                //
                // If extend is left at its default value (None), then bilinear scaling uses
                // transparency outside of the image producing incorrect results.
                // For example, in svg1.1/filters-blend-01-b.svgthere's a completely
                // opaque 100×1 image of a gradient scaled to 100×98 which ends up
                // transparent almost everywhere without this fix (which it shouldn't).
                let ptn = cairo::SurfacePattern::create(&surface);
                let mut matrix = cairo::Matrix::identity();
                matrix.translate(-x, -y);
                ptn.set_matrix(matrix);
                ptn.set_extend(cairo::Extend::Pad);
                cr.set_source(&cairo::Pattern::SurfacePattern(ptn));

                // Clip is needed due to extend being set to pad.
                cr.rectangle(x, y, width, height);
                cr.clip();

                cr.paint();

                cr.restore();

                dc.insert_bbox(&bbox);
                Ok(())
            })
        } else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//! "Stripped-down" versions of the core state events.
//!
//! Each "stripped" event includes only the `content`, `type`, and `state_key` fields of its full
//! version. These stripped types are useful for APIs where the user is providing the content of a
//! state event to be created, when the other fields can be inferred from a larger context, or where
//! the other fields are otherwise inapplicable.

use ruma_identifiers::UserId;
use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize};
use serde_json::Value as JsonValue;

use crate::{
    room::{
        aliases::AliasesEventContent, avatar::AvatarEventContent,
        canonical_alias::CanonicalAliasEventContent, create::CreateEventContent,
        guest_access::GuestAccessEventContent, history_visibility::HistoryVisibilityEventContent,
        join_rules::JoinRulesEventContent, member::MemberEventContent, name::NameEventContent,
        power_levels::PowerLevelsEventContent, third_party_invite::ThirdPartyInviteEventContent,
        topic::TopicEventContent,
    },
    util::get_field,
    EventType, TryFromRaw,
};

/// A stripped-down version of a state event that is included along with some other events.
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum AnyStrippedStateEvent {
    /// A stripped-down version of the *m.room.aliases* event.
    RoomAliases(StrippedRoomAliases),

    /// A stripped-down version of the *m.room.avatar* event.
    RoomAvatar(StrippedRoomAvatar),

    /// A stripped-down version of the *m.room.canonical_alias* event.
    RoomCanonicalAlias(StrippedRoomCanonicalAlias),

    /// A striped-down version of the *m.room.create* event.
    RoomCreate(StrippedRoomCreate),

    /// A stripped-down version of the *m.room.guest_access* event.
    RoomGuestAccess(StrippedRoomGuestAccess),

    /// A stripped-down version of the *m.room.history_visibility* event.
    RoomHistoryVisibility(StrippedRoomHistoryVisibility),

    /// A stripped-down version of the *m.room.join_rules* event.
    RoomJoinRules(StrippedRoomJoinRules),

    /// A stripped-down version of the *m.room.member* event.
    RoomMember(StrippedRoomMember),

    /// A stripped-down version of the *m.room.name* event.
    RoomName(StrippedRoomName),

    /// A stripped-down version of the *m.room.power_levels* event.
    RoomPowerLevels(StrippedRoomPowerLevels),

    /// A stripped-down version of the *m.room.third_party_invite* event.
    RoomThirdPartyInvite(StrippedRoomThirdPartyInvite),

    /// A stripped-down version of the *m.room.topic* event.
    RoomTopic(StrippedRoomTopic),
}

/// A "stripped-down" version of a core state event.
#[derive(Clone, Debug, Serialize)]
pub struct StrippedStateEvent<C> {
    /// Data specific to the event type.
    pub content: C,

    // FIXME(jplatte): It's unclear to me why this is stored
    /// The type of the event.
    #[serde(rename = "type")]
    pub event_type: EventType,

    /// A key that determines which piece of room state the event represents.
    pub state_key: String,

    /// The unique identifier for the user who sent this event.
    pub sender: UserId,
}

/// A stripped-down version of the *m.room.aliases* event.
pub type StrippedRoomAliases = StrippedStateEvent<AliasesEventContent>;

/// A stripped-down version of the *m.room.avatar* event.
pub type StrippedRoomAvatar = StrippedStateEvent<AvatarEventContent>;

/// A stripped-down version of the *m.room.canonical_alias* event.
pub type StrippedRoomCanonicalAlias = StrippedStateEvent<CanonicalAliasEventContent>;

/// A stripped-down version of the *m.room.create* event.
pub type StrippedRoomCreate = StrippedStateEvent<CreateEventContent>;

/// A stripped-down version of the *m.room.guest_access* event.
pub type StrippedRoomGuestAccess = StrippedStateEvent<GuestAccessEventContent>;

/// A stripped-down version of the *m.room.history_visibility* event.
pub type StrippedRoomHistoryVisibility = StrippedStateEvent<HistoryVisibilityEventContent>;

/// A stripped-down version of the *m.room.join_rules* event.
pub type StrippedRoomJoinRules = StrippedStateEvent<JoinRulesEventContent>;

/// A stripped-down version of the *m.room.member* event.
pub type StrippedRoomMember = StrippedStateEvent<MemberEventContent>;

/// A stripped-down version of the *m.room.name* event.
pub type StrippedRoomName = StrippedStateEvent<NameEventContent>;

/// A stripped-down version of the *m.room.power_levels* event.
pub type StrippedRoomPowerLevels = StrippedStateEvent<PowerLevelsEventContent>;

/// A stripped-down version of the *m.room.third_party_invite* event.
pub type StrippedRoomThirdPartyInvite = StrippedStateEvent<ThirdPartyInviteEventContent>;

/// A stripped-down version of the *m.room.topic* event.
pub type StrippedRoomTopic = StrippedStateEvent<TopicEventContent>;

impl TryFromRaw for AnyStrippedStateEvent {
    type Raw = raw::StrippedState;
    type Err = String;

    fn try_from_raw(raw: raw::StrippedState) -> Result<Self, Self::Err> {
        use crate::util::try_convert_variant as conv;
        use raw::StrippedState::*;

        match raw {
            RoomAliases(c) => conv(AnyStrippedStateEvent::RoomAliases, c),
            RoomAvatar(c) => conv(AnyStrippedStateEvent::RoomAvatar, c),
            RoomCanonicalAlias(c) => conv(AnyStrippedStateEvent::RoomCanonicalAlias, c),
            RoomCreate(c) => conv(AnyStrippedStateEvent::RoomCreate, c),
            RoomGuestAccess(c) => conv(AnyStrippedStateEvent::RoomGuestAccess, c),
            RoomHistoryVisibility(c) => conv(AnyStrippedStateEvent::RoomHistoryVisibility, c),
            RoomJoinRules(c) => conv(AnyStrippedStateEvent::RoomJoinRules, c),
            RoomMember(c) => conv(AnyStrippedStateEvent::RoomMember, c),
            RoomName(c) => conv(AnyStrippedStateEvent::RoomName, c),
            RoomPowerLevels(c) => conv(AnyStrippedStateEvent::RoomPowerLevels, c),
            RoomThirdPartyInvite(c) => conv(AnyStrippedStateEvent::RoomThirdPartyInvite, c),
            RoomTopic(c) => conv(AnyStrippedStateEvent::RoomTopic, c),
        }
    }
}

impl<C> TryFromRaw for StrippedStateEvent<C>
where
    C: TryFromRaw,
{
    type Raw = StrippedStateEvent<C::Raw>;
    type Err = C::Err;

    fn try_from_raw(raw: StrippedStateEvent<C::Raw>) -> Result<Self, Self::Err> {
        Ok(Self {
            content: C::try_from_raw(raw.content)?,
            event_type: raw.event_type,
            state_key: raw.state_key,
            sender: raw.sender,
        })
    }
}

impl<'de, C> Deserialize<'de> for StrippedStateEvent<C>
where
    C: DeserializeOwned,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // TODO: Optimize
        let value = JsonValue::deserialize(deserializer)?;

        Ok(Self {
            content: get_field(&value, "content")?,
            event_type: get_field(&value, "type")?,
            state_key: get_field(&value, "state_key")?,
            sender: get_field(&value, "sender")?,
        })
    }
}

mod raw {
    use serde::{Deserialize, Deserializer};
    use serde_json::Value as JsonValue;

    use super::StrippedStateEvent;
    use crate::{
        room::{
            aliases::raw::AliasesEventContent, avatar::raw::AvatarEventContent,
            canonical_alias::raw::CanonicalAliasEventContent, create::raw::CreateEventContent,
            guest_access::raw::GuestAccessEventContent,
            history_visibility::raw::HistoryVisibilityEventContent,
            join_rules::raw::JoinRulesEventContent, member::raw::MemberEventContent,
            name::raw::NameEventContent, power_levels::raw::PowerLevelsEventContent,
            third_party_invite::raw::ThirdPartyInviteEventContent, topic::raw::TopicEventContent,
        },
        util::get_field,
    };

    /// A stripped-down version of the *m.room.aliases* event.
    pub type StrippedRoomAliases = StrippedStateEvent<AliasesEventContent>;

    /// A stripped-down version of the *m.room.avatar* event.
    pub type StrippedRoomAvatar = StrippedStateEvent<AvatarEventContent>;

    /// A stripped-down version of the *m.room.canonical_alias* event.
    pub type StrippedRoomCanonicalAlias = StrippedStateEvent<CanonicalAliasEventContent>;

    /// A stripped-down version of the *m.room.create* event.
    pub type StrippedRoomCreate = StrippedStateEvent<CreateEventContent>;

    /// A stripped-down version of the *m.room.guest_access* event.
    pub type StrippedRoomGuestAccess = StrippedStateEvent<GuestAccessEventContent>;

    /// A stripped-down version of the *m.room.history_visibility* event.
    pub type StrippedRoomHistoryVisibility = StrippedStateEvent<HistoryVisibilityEventContent>;

    /// A stripped-down version of the *m.room.join_rules* event.
    pub type StrippedRoomJoinRules = StrippedStateEvent<JoinRulesEventContent>;

    /// A stripped-down version of the *m.room.member* event.
    pub type StrippedRoomMember = StrippedStateEvent<MemberEventContent>;

    /// A stripped-down version of the *m.room.name* event.
    pub type StrippedRoomName = StrippedStateEvent<NameEventContent>;

    /// A stripped-down version of the *m.room.power_levels* event.
    pub type StrippedRoomPowerLevels = StrippedStateEvent<PowerLevelsEventContent>;

    /// A stripped-down version of the *m.room.third_party_invite* event.
    pub type StrippedRoomThirdPartyInvite = StrippedStateEvent<ThirdPartyInviteEventContent>;

    /// A stripped-down version of the *m.room.topic* event.
    pub type StrippedRoomTopic = StrippedStateEvent<TopicEventContent>;

    /// A stripped-down version of a state event that is included along with some other events.
    #[derive(Clone, Debug)]
    #[allow(clippy::large_enum_variant)]
    pub enum StrippedState {
        /// A stripped-down version of the *m.room.aliases* event.
        RoomAliases(StrippedRoomAliases),

        /// A stripped-down version of the *m.room.avatar* event.
        RoomAvatar(StrippedRoomAvatar),

        /// A stripped-down version of the *m.room.canonical_alias* event.
        RoomCanonicalAlias(StrippedRoomCanonicalAlias),

        /// A striped-down version of the *m.room.create* event.
        RoomCreate(StrippedRoomCreate),

        /// A stripped-down version of the *m.room.guest_access* event.
        RoomGuestAccess(StrippedRoomGuestAccess),

        /// A stripped-down version of the *m.room.history_visibility* event.
        RoomHistoryVisibility(StrippedRoomHistoryVisibility),

        /// A stripped-down version of the *m.room.join_rules* event.
        RoomJoinRules(StrippedRoomJoinRules),

        /// A stripped-down version of the *m.room.member* event.
        RoomMember(StrippedRoomMember),

        /// A stripped-down version of the *m.room.name* event.
        RoomName(StrippedRoomName),

        /// A stripped-down version of the *m.room.power_levels* event.
        RoomPowerLevels(StrippedRoomPowerLevels),

        /// A stripped-down version of the *m.room.third_party_invite* event.
        RoomThirdPartyInvite(StrippedRoomThirdPartyInvite),

        /// A stripped-down version of the *m.room.topic* event.
        RoomTopic(StrippedRoomTopic),
    }

    impl<'de> Deserialize<'de> for StrippedState {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            use crate::{util::try_variant_from_value as from_value, EventType::*};
            use serde::de::Error as _;

            // TODO: Optimize
            let value = JsonValue::deserialize(deserializer)?;
            let event_type = get_field(&value, "type")?;

            match event_type {
                RoomAliases => from_value(value, StrippedState::RoomAliases),
                RoomAvatar => from_value(value, StrippedState::RoomAvatar),
                RoomCanonicalAlias => from_value(value, StrippedState::RoomCanonicalAlias),
                RoomCreate => from_value(value, StrippedState::RoomCreate),
                RoomGuestAccess => from_value(value, StrippedState::RoomGuestAccess),
                RoomHistoryVisibility => from_value(value, StrippedState::RoomHistoryVisibility),
                RoomJoinRules => from_value(value, StrippedState::RoomJoinRules),
                RoomMember => from_value(value, StrippedState::RoomMember),
                RoomName => from_value(value, StrippedState::RoomName),
                RoomPowerLevels => from_value(value, StrippedState::RoomPowerLevels),
                RoomThirdPartyInvite => from_value(value, StrippedState::RoomThirdPartyInvite),
                RoomTopic => from_value(value, StrippedState::RoomTopic),
                _ => Err(D::Error::custom("not a state event")),
            }
        }
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>events: Remove stripped.rs (whose mod declaration was already removed previously)<commit_after><|endoftext|>


<commit_before>use std::fmt;
use std::borrow::Cow;
use std::io::{Cursor, Read, Write, ErrorKind};
use std::default::Default;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt, NetworkEndian};
use bytes::BufMut;

use error::{Error, Result};
use super::coding::{OpCode, Control, Data, CloseCode};
use super::mask::{generate_mask, apply_mask};

/// A struct representing the close command.
#[derive(Debug, Clone)]
pub struct CloseFrame<'t> {
    /// The reason as a code.
    pub code: CloseCode,
    /// The reason as text string.
    pub reason: Cow<'t, str>,
}

impl<'t> CloseFrame<'t> {
    /// Convert into a owned string.
    pub fn into_owned(self) -> CloseFrame<'static> {
        CloseFrame {
            code: self.code,
            reason: self.reason.into_owned().into(),
        }
    }
}

impl<'t> fmt::Display for CloseFrame<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.reason, self.code)
    }
}

/// A struct representing a WebSocket frame.
#[derive(Debug, Clone)]
pub struct Frame {
    finished: bool,
    rsv1: bool,
    rsv2: bool,
    rsv3: bool,
    opcode: OpCode,

    mask: Option<[u8; 4]>,

    payload: Vec<u8>,
}

impl Frame {

    /// Get the length of the frame.
    /// This is the length of the header + the length of the payload.
    #[inline]
    pub fn len(&self) -> usize {
        let mut header_length = 2;
        let payload_len = self.payload().len();
        if payload_len > 125 {
            if payload_len <= u16::max_value() as usize {
                header_length += 2;
            } else {
                header_length += 8;
            }
        }

        if self.is_masked() {
            header_length += 4;
        }

        header_length + payload_len
    }

    /// Test whether the frame is a final frame.
    #[inline]
    pub fn is_final(&self) -> bool {
        self.finished
    }

    /// Test whether the first reserved bit is set.
    #[inline]
    pub fn has_rsv1(&self) -> bool {
        self.rsv1
    }

    /// Test whether the second reserved bit is set.
    #[inline]
    pub fn has_rsv2(&self) -> bool {
        self.rsv2
    }

    /// Test whether the third reserved bit is set.
    #[inline]
    pub fn has_rsv3(&self) -> bool {
        self.rsv3
    }

    /// Get the OpCode of the frame.
    #[inline]
    pub fn opcode(&self) -> OpCode {
        self.opcode
    }

    /// Get a reference to the frame's payload.
    #[inline]
    pub fn payload(&self) -> &Vec<u8> {
        &self.payload
    }

    // Test whether the frame is masked.
    #[doc(hidden)]
    #[inline]
    pub fn is_masked(&self) -> bool {
        self.mask.is_some()
    }

    // Get an optional reference to the frame's mask.
    #[doc(hidden)]
    #[allow(dead_code)]
    #[inline]
    pub fn mask(&self) -> Option<&[u8; 4]> {
        self.mask.as_ref()
    }

    /// Make this frame a final frame.
    #[allow(dead_code)]
    #[inline]
    pub fn set_final(&mut self, is_final: bool) -> &mut Frame {
        self.finished = is_final;
        self
    }

    /// Set the first reserved bit.
    #[inline]
    pub fn set_rsv1(&mut self, has_rsv1: bool) -> &mut Frame {
        self.rsv1 = has_rsv1;
        self
    }

    /// Set the second reserved bit.
    #[inline]
    pub fn set_rsv2(&mut self, has_rsv2: bool) -> &mut Frame {
        self.rsv2 = has_rsv2;
        self
    }

    /// Set the third reserved bit.
    #[inline]
    pub fn set_rsv3(&mut self, has_rsv3: bool) -> &mut Frame {
        self.rsv3 = has_rsv3;
        self
    }

    /// Set the OpCode.
    #[allow(dead_code)]
    #[inline]
    pub fn set_opcode(&mut self, opcode: OpCode) -> &mut Frame {
        self.opcode = opcode;
        self
    }

    /// Edit the frame's payload.
    #[allow(dead_code)]
    #[inline]
    pub fn payload_mut(&mut self) -> &mut Vec<u8> {
        &mut self.payload
    }

    // Generate a new mask for this frame.
    //
    // This method simply generates and stores the mask. It does not change the payload data.
    // Instead, the payload data will be masked with the generated mask when the frame is sent
    // to the other endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn set_mask(&mut self) -> &mut Frame {
        self.mask = Some(generate_mask());
        self
    }

    // This method unmasks the payload and should only be called on frames that are actually
    // masked. In other words, those frames that have just been received from a client endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn remove_mask(&mut self) {
        self.mask.and_then(|mask| {
            Some(apply_mask(&mut self.payload, &mask))
        });
        self.mask = None;
    }

    /// Consume the frame into its payload as binary.
    #[inline]
    pub fn into_data(self) -> Vec<u8> {
        self.payload
    }

    /// Consume the frame into its payload as string.
    #[inline]
    pub fn into_string(self) -> StdResult<String, FromUtf8Error> {
        String::from_utf8(self.payload)
    }

     /// Consume the frame into a closing frame.
    #[inline]
    pub fn into_close(self) -> Result<Option<CloseFrame<'static>>> {
        match self.payload.len() {
            0 => Ok(None),
            1 => Err(Error::Protocol("Invalid close sequence".into())),
            _ => {
                let mut data = self.payload;
                let code = NetworkEndian::read_u16(&data[0..2]).into();
                data.drain(0..2);
                let text = String::from_utf8(data)?;
                Ok(Some(CloseFrame { code: code, reason: text.into() }))
            }
        }
    }

    /// Create a new data frame.
    #[inline]
    pub fn message(data: Vec<u8>, code: OpCode, finished: bool) -> Frame {
        debug_assert!(match code {
            OpCode::Data(_) => true,
            _ => false,
        }, "Invalid opcode for data frame.");

        Frame {
            finished: finished,
            opcode: code,
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Pong control frame.
    #[inline]
    pub fn pong(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Pong),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Ping control frame.
    #[inline]
    pub fn ping(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Ping),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Close control frame.
    #[inline]
    pub fn close(msg: Option<CloseFrame>) -> Frame {
        let payload = if let Some(CloseFrame { code, reason }) = msg {
            let mut p = Vec::with_capacity(reason.as_bytes().len() + 2);
            p.write_u16::<NetworkEndian>(code.into()).unwrap(); // can't fail
            p.extend_from_slice(reason.as_bytes());
            p
        } else {
            Vec::new()
        };

        Frame {
            payload: payload,
            .. Frame::default()
        }
    }

    /// Parse the input stream into a frame.
    pub fn parse(cursor: &mut Cursor<Vec<u8>>) -> Result<Option<Frame>> {
        let size = cursor.get_ref().len() as u64 - cursor.position();
        let initial = cursor.position();
        trace!("Position in buffer {}", initial);

        let mut head = [0u8; 2];
        if try!(cursor.read(&mut head)) != 2 {
            cursor.set_position(initial);
            return Ok(None)
        }

        trace!("Parsed headers {:?}", head);

        let first = head[0];
        let second = head[1];
        trace!("First: {:b}", first);
        trace!("Second: {:b}", second);

        let finished = first & 0x80 != 0;

        let rsv1 = first & 0x40 != 0;
        let rsv2 = first & 0x20 != 0;
        let rsv3 = first & 0x10 != 0;

        let opcode = OpCode::from(first & 0x0F);
        trace!("Opcode: {:?}", opcode);

        let masked = second & 0x80 != 0;
        trace!("Masked: {:?}", masked);

        let mut header_length = 2;

        let mut length = (second & 0x7F) as u64;

        if let Some(length_nbytes) = match length {
            126 => Some(2),
            127 => Some(8),
            _ => None,
        } {
            match cursor.read_uint::<NetworkEndian>(length_nbytes) {
                Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
                    cursor.set_position(initial);
                    return Ok(None);
                }
                Err(err) => {
                    return Err(Error::from(err));
                }
                Ok(read) => {
                    length = read;
                }
            };
            header_length += length_nbytes as u64;
        }
        trace!("Payload length: {}", length);

        let mask = if masked {
            let mut mask_bytes = [0u8; 4];
            if try!(cursor.read(&mut mask_bytes)) != 4 {
                cursor.set_position(initial);
                return Ok(None)
            } else {
                header_length += 4;
                Some(mask_bytes)
            }
        } else {
            None
        };

        if size < header_length || size - header_length < length {
            cursor.set_position(initial);
            return Ok(None)
        }

        let mut data = Vec::with_capacity(length as usize);
        if length > 0 {
            unsafe {
                try!(cursor.read_exact(data.bytes_mut()));
                data.advance_mut(length as usize);
            }
        }

        // Disallow bad opcode
        match opcode {
            OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => {
                return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into()))
            }
            _ => ()
        }

        let frame = Frame {
            finished: finished,
            rsv1: rsv1,
            rsv2: rsv2,
            rsv3: rsv3,
            opcode: opcode,
            mask: mask,
            payload: data,
        };

        Ok(Some(frame))
    }

    /// Write a frame out to a buffer
    pub fn format<W>(mut self, w: &mut W) -> Result<()>
        where W: Write
    {
        let mut one = 0u8;
        let code: u8 = self.opcode.into();
        if self.is_final() {
            one |= 0x80;
        }
        if self.has_rsv1() {
            one |= 0x40;
        }
        if self.has_rsv2() {
            one |= 0x20;
        }
        if self.has_rsv3() {
            one |= 0x10;
        }
        one |= code;

        let mut two = 0u8;

        if self.is_masked() {
            two |= 0x80;
        }

        if self.payload.len() < 126 {
            two |= self.payload.len() as u8;
            let headers = [one, two];
            try!(w.write(&headers));
        } else if self.payload.len() <= 65535 {
            two |= 126;
            let mut length_bytes = [0u8; 2];
            NetworkEndian::write_u16(&mut length_bytes, self.payload.len() as u16);
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let mut length_bytes = [0u8; 8];
            NetworkEndian::write_u64(&mut length_bytes, self.payload.len() as u64);
            let headers = [
                one,
                two,
                length_bytes[0],
                length_bytes[1],
                length_bytes[2],
                length_bytes[3],
                length_bytes[4],
                length_bytes[5],
                length_bytes[6],
                length_bytes[7],
            ];
            try!(w.write(&headers));
        }

        if self.is_masked() {
            let mask = self.mask.take().unwrap();
            apply_mask(&mut self.payload, &mask);
            try!(w.write(&mask));
        }

        try!(w.write(&self.payload));
        Ok(())
    }
}

impl Default for Frame {
    fn default() -> Frame {
        Frame {
            finished: true,
            rsv1: false,
            rsv2: false,
            rsv3: false,
            opcode: OpCode::Control(Control::Close),
            mask: None,
            payload: Vec::new(),
        }
    }
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "
<FRAME>
final: {}
reserved: {} {} {}
opcode: {}
length: {}
payload length: {}
payload: 0x{}
            ",
            self.finished,
            self.rsv1,
            self.rsv2,
            self.rsv3,
            self.opcode,
            // self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
            self.len(),
            self.payload.len(),
            self.payload.iter().map(|byte| format!("{:x}", byte)).collect::<String>())
    }
}

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

    use super::super::coding::{OpCode, Data};
    use std::io::Cursor;

    #[test]
    fn parse() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ]);
        let frame = Frame::parse(&mut raw).unwrap().unwrap();
        assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]);
    }

    #[test]
    fn format() {
        let frame = Frame::ping(vec![0x01, 0x02]);
        let mut buf = Vec::with_capacity(frame.len());
        frame.format(&mut buf).unwrap();
        assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
    }

    #[test]
    fn display() {
        let f = Frame::message("hi there".into(), OpCode::Data(Data::Text), true);
        let view = format!("{}", f);
        assert!(view.contains("payload:"));
    }

    #[test]
    fn parse_overflow() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let frame_none = Frame::parse(&mut raw).unwrap();
        assert!(frame_none.is_none());
    }
}
<commit_msg>frame: reject frames that are too big for the RAM<commit_after>use std::fmt;
use std::borrow::Cow;
use std::io::{Cursor, Read, Write, ErrorKind};
use std::default::Default;
use std::string::{String, FromUtf8Error};
use std::result::Result as StdResult;
use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt, NetworkEndian};
use bytes::BufMut;

use error::{Error, Result};
use super::coding::{OpCode, Control, Data, CloseCode};
use super::mask::{generate_mask, apply_mask};

/// A struct representing the close command.
#[derive(Debug, Clone)]
pub struct CloseFrame<'t> {
    /// The reason as a code.
    pub code: CloseCode,
    /// The reason as text string.
    pub reason: Cow<'t, str>,
}

impl<'t> CloseFrame<'t> {
    /// Convert into a owned string.
    pub fn into_owned(self) -> CloseFrame<'static> {
        CloseFrame {
            code: self.code,
            reason: self.reason.into_owned().into(),
        }
    }
}

impl<'t> fmt::Display for CloseFrame<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} ({})", self.reason, self.code)
    }
}

/// A struct representing a WebSocket frame.
#[derive(Debug, Clone)]
pub struct Frame {
    finished: bool,
    rsv1: bool,
    rsv2: bool,
    rsv3: bool,
    opcode: OpCode,

    mask: Option<[u8; 4]>,

    payload: Vec<u8>,
}

impl Frame {

    /// Get the length of the frame.
    /// This is the length of the header + the length of the payload.
    #[inline]
    pub fn len(&self) -> usize {
        let mut header_length = 2;
        let payload_len = self.payload().len();
        if payload_len > 125 {
            if payload_len <= u16::max_value() as usize {
                header_length += 2;
            } else {
                header_length += 8;
            }
        }

        if self.is_masked() {
            header_length += 4;
        }

        header_length + payload_len
    }

    /// Test whether the frame is a final frame.
    #[inline]
    pub fn is_final(&self) -> bool {
        self.finished
    }

    /// Test whether the first reserved bit is set.
    #[inline]
    pub fn has_rsv1(&self) -> bool {
        self.rsv1
    }

    /// Test whether the second reserved bit is set.
    #[inline]
    pub fn has_rsv2(&self) -> bool {
        self.rsv2
    }

    /// Test whether the third reserved bit is set.
    #[inline]
    pub fn has_rsv3(&self) -> bool {
        self.rsv3
    }

    /// Get the OpCode of the frame.
    #[inline]
    pub fn opcode(&self) -> OpCode {
        self.opcode
    }

    /// Get a reference to the frame's payload.
    #[inline]
    pub fn payload(&self) -> &Vec<u8> {
        &self.payload
    }

    // Test whether the frame is masked.
    #[doc(hidden)]
    #[inline]
    pub fn is_masked(&self) -> bool {
        self.mask.is_some()
    }

    // Get an optional reference to the frame's mask.
    #[doc(hidden)]
    #[allow(dead_code)]
    #[inline]
    pub fn mask(&self) -> Option<&[u8; 4]> {
        self.mask.as_ref()
    }

    /// Make this frame a final frame.
    #[allow(dead_code)]
    #[inline]
    pub fn set_final(&mut self, is_final: bool) -> &mut Frame {
        self.finished = is_final;
        self
    }

    /// Set the first reserved bit.
    #[inline]
    pub fn set_rsv1(&mut self, has_rsv1: bool) -> &mut Frame {
        self.rsv1 = has_rsv1;
        self
    }

    /// Set the second reserved bit.
    #[inline]
    pub fn set_rsv2(&mut self, has_rsv2: bool) -> &mut Frame {
        self.rsv2 = has_rsv2;
        self
    }

    /// Set the third reserved bit.
    #[inline]
    pub fn set_rsv3(&mut self, has_rsv3: bool) -> &mut Frame {
        self.rsv3 = has_rsv3;
        self
    }

    /// Set the OpCode.
    #[allow(dead_code)]
    #[inline]
    pub fn set_opcode(&mut self, opcode: OpCode) -> &mut Frame {
        self.opcode = opcode;
        self
    }

    /// Edit the frame's payload.
    #[allow(dead_code)]
    #[inline]
    pub fn payload_mut(&mut self) -> &mut Vec<u8> {
        &mut self.payload
    }

    // Generate a new mask for this frame.
    //
    // This method simply generates and stores the mask. It does not change the payload data.
    // Instead, the payload data will be masked with the generated mask when the frame is sent
    // to the other endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn set_mask(&mut self) -> &mut Frame {
        self.mask = Some(generate_mask());
        self
    }

    // This method unmasks the payload and should only be called on frames that are actually
    // masked. In other words, those frames that have just been received from a client endpoint.
    #[doc(hidden)]
    #[inline]
    pub fn remove_mask(&mut self) {
        self.mask.and_then(|mask| {
            Some(apply_mask(&mut self.payload, &mask))
        });
        self.mask = None;
    }

    /// Consume the frame into its payload as binary.
    #[inline]
    pub fn into_data(self) -> Vec<u8> {
        self.payload
    }

    /// Consume the frame into its payload as string.
    #[inline]
    pub fn into_string(self) -> StdResult<String, FromUtf8Error> {
        String::from_utf8(self.payload)
    }

     /// Consume the frame into a closing frame.
    #[inline]
    pub fn into_close(self) -> Result<Option<CloseFrame<'static>>> {
        match self.payload.len() {
            0 => Ok(None),
            1 => Err(Error::Protocol("Invalid close sequence".into())),
            _ => {
                let mut data = self.payload;
                let code = NetworkEndian::read_u16(&data[0..2]).into();
                data.drain(0..2);
                let text = String::from_utf8(data)?;
                Ok(Some(CloseFrame { code: code, reason: text.into() }))
            }
        }
    }

    /// Create a new data frame.
    #[inline]
    pub fn message(data: Vec<u8>, code: OpCode, finished: bool) -> Frame {
        debug_assert!(match code {
            OpCode::Data(_) => true,
            _ => false,
        }, "Invalid opcode for data frame.");

        Frame {
            finished: finished,
            opcode: code,
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Pong control frame.
    #[inline]
    pub fn pong(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Pong),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Ping control frame.
    #[inline]
    pub fn ping(data: Vec<u8>) -> Frame {
        Frame {
            opcode: OpCode::Control(Control::Ping),
            payload: data,
            .. Frame::default()
        }
    }

    /// Create a new Close control frame.
    #[inline]
    pub fn close(msg: Option<CloseFrame>) -> Frame {
        let payload = if let Some(CloseFrame { code, reason }) = msg {
            let mut p = Vec::with_capacity(reason.as_bytes().len() + 2);
            p.write_u16::<NetworkEndian>(code.into()).unwrap(); // can't fail
            p.extend_from_slice(reason.as_bytes());
            p
        } else {
            Vec::new()
        };

        Frame {
            payload: payload,
            .. Frame::default()
        }
    }

    /// Parse the input stream into a frame.
    pub fn parse(cursor: &mut Cursor<Vec<u8>>) -> Result<Option<Frame>> {
        let size = cursor.get_ref().len() as u64 - cursor.position();
        let initial = cursor.position();
        trace!("Position in buffer {}", initial);

        let mut head = [0u8; 2];
        if try!(cursor.read(&mut head)) != 2 {
            cursor.set_position(initial);
            return Ok(None)
        }

        trace!("Parsed headers {:?}", head);

        let first = head[0];
        let second = head[1];
        trace!("First: {:b}", first);
        trace!("Second: {:b}", second);

        let finished = first & 0x80 != 0;

        let rsv1 = first & 0x40 != 0;
        let rsv2 = first & 0x20 != 0;
        let rsv3 = first & 0x10 != 0;

        let opcode = OpCode::from(first & 0x0F);
        trace!("Opcode: {:?}", opcode);

        let masked = second & 0x80 != 0;
        trace!("Masked: {:?}", masked);

        let mut header_length = 2;

        let mut length = (second & 0x7F) as u64;

        if let Some(length_nbytes) = match length {
            126 => Some(2),
            127 => Some(8),
            _ => None,
        } {
            match cursor.read_uint::<NetworkEndian>(length_nbytes) {
                Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => {
                    cursor.set_position(initial);
                    return Ok(None);
                }
                Err(err) => {
                    return Err(Error::from(err));
                }
                Ok(read) => {
                    length = read;
                }
            };
            header_length += length_nbytes as u64;
        }
        trace!("Payload length: {}", length);

        let mask = if masked {
            let mut mask_bytes = [0u8; 4];
            if try!(cursor.read(&mut mask_bytes)) != 4 {
                cursor.set_position(initial);
                return Ok(None)
            } else {
                header_length += 4;
                Some(mask_bytes)
            }
        } else {
            None
        };

        // Make sure `length` is not too big (fits into `usize`).
        if length > usize::max_value() as u64 {
            return Err(Error::Capacity(format!("Message length too big: {}", length).into()));
        }

        if size < header_length || size - header_length < length {
            cursor.set_position(initial);
            return Ok(None)
        }

        // Size is checked above, so it won't be truncated here.
        let mut data = Vec::with_capacity(length as usize);
        if length > 0 {
            unsafe {
                try!(cursor.read_exact(data.bytes_mut()));
                data.advance_mut(length as usize);
            }
        }

        // Disallow bad opcode
        match opcode {
            OpCode::Control(Control::Reserved(_)) | OpCode::Data(Data::Reserved(_)) => {
                return Err(Error::Protocol(format!("Encountered invalid opcode: {}", first & 0x0F).into()))
            }
            _ => ()
        }

        let frame = Frame {
            finished: finished,
            rsv1: rsv1,
            rsv2: rsv2,
            rsv3: rsv3,
            opcode: opcode,
            mask: mask,
            payload: data,
        };

        Ok(Some(frame))
    }

    /// Write a frame out to a buffer
    pub fn format<W>(mut self, w: &mut W) -> Result<()>
        where W: Write
    {
        let mut one = 0u8;
        let code: u8 = self.opcode.into();
        if self.is_final() {
            one |= 0x80;
        }
        if self.has_rsv1() {
            one |= 0x40;
        }
        if self.has_rsv2() {
            one |= 0x20;
        }
        if self.has_rsv3() {
            one |= 0x10;
        }
        one |= code;

        let mut two = 0u8;

        if self.is_masked() {
            two |= 0x80;
        }

        if self.payload.len() < 126 {
            two |= self.payload.len() as u8;
            let headers = [one, two];
            try!(w.write(&headers));
        } else if self.payload.len() <= 65535 {
            two |= 126;
            let mut length_bytes = [0u8; 2];
            NetworkEndian::write_u16(&mut length_bytes, self.payload.len() as u16);
            let headers = [one, two, length_bytes[0], length_bytes[1]];
            try!(w.write(&headers));
        } else {
            two |= 127;
            let mut length_bytes = [0u8; 8];
            NetworkEndian::write_u64(&mut length_bytes, self.payload.len() as u64);
            let headers = [
                one,
                two,
                length_bytes[0],
                length_bytes[1],
                length_bytes[2],
                length_bytes[3],
                length_bytes[4],
                length_bytes[5],
                length_bytes[6],
                length_bytes[7],
            ];
            try!(w.write(&headers));
        }

        if self.is_masked() {
            let mask = self.mask.take().unwrap();
            apply_mask(&mut self.payload, &mask);
            try!(w.write(&mask));
        }

        try!(w.write(&self.payload));
        Ok(())
    }
}

impl Default for Frame {
    fn default() -> Frame {
        Frame {
            finished: true,
            rsv1: false,
            rsv2: false,
            rsv3: false,
            opcode: OpCode::Control(Control::Close),
            mask: None,
            payload: Vec::new(),
        }
    }
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
            "
<FRAME>
final: {}
reserved: {} {} {}
opcode: {}
length: {}
payload length: {}
payload: 0x{}
            ",
            self.finished,
            self.rsv1,
            self.rsv2,
            self.rsv3,
            self.opcode,
            // self.mask.map(|mask| format!("{:?}", mask)).unwrap_or("NONE".into()),
            self.len(),
            self.payload.len(),
            self.payload.iter().map(|byte| format!("{:x}", byte)).collect::<String>())
    }
}

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

    use super::super::coding::{OpCode, Data};
    use std::io::Cursor;

    #[test]
    fn parse() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ]);
        let frame = Frame::parse(&mut raw).unwrap().unwrap();
        assert_eq!(frame.into_data(), vec![ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ]);
    }

    #[test]
    fn format() {
        let frame = Frame::ping(vec![0x01, 0x02]);
        let mut buf = Vec::with_capacity(frame.len());
        frame.format(&mut buf).unwrap();
        assert_eq!(buf, vec![0x89, 0x02, 0x01, 0x02]);
    }

    #[test]
    fn display() {
        let f = Frame::message("hi there".into(), OpCode::Data(Data::Text), true);
        let view = format!("{}", f);
        assert!(view.contains("payload:"));
    }

    #[test]
    fn parse_overflow() {
        let mut raw: Cursor<Vec<u8>> = Cursor::new(vec![
            0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
        ]);
        let _ = Frame::parse(&mut raw); // should not crash
    }
}
<|endoftext|>


<commit_before>//! `GET /_matrix/client/*/rooms/{roomId}/messages`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomidmessages

    use js_int::{uint, UInt};
    use ruma_common::{
        api::ruma_api,
        events::{AnyRoomEvent, AnyStateEvent},
        serde::Raw,
        RoomId,
    };
    use serde::{Deserialize, Serialize};

    use crate::filter::{IncomingRoomEventFilter, RoomEventFilter};

    ruma_api! {
        metadata: {
            description: "Get message events for a room.",
            method: GET,
            name: "get_message_events",
            r0_path: "/_matrix/client/r0/rooms/:room_id/messages",
            stable_path: "/_matrix/client/v3/rooms/:room_id/messages",
            rate_limited: false,
            authentication: AccessToken,
            added: 1.0,
        }

        request: {
            /// The room to get events from.
            #[ruma_api(path)]
            pub room_id: &'a RoomId,

            /// The token to start returning events from.
            ///
            /// This token can be obtained from a `prev_batch` token returned for each room by the
            /// sync endpoint, or from a `start` or `end` token returned by a previous request to
            /// this endpoint.
            ///
            /// If this is `None`, the server will return messages from the start or end of the
            /// history visible to the user, depending on the value of [`dir`][Self::dir].
            #[ruma_api(query)]
            pub from: Option<&'a str>,

            /// The token to stop returning events at.
            ///
            /// This token can be obtained from a `prev_batch` token returned for each room by the
            /// sync endpoint, or from a `start` or `end` token returned by a previous request to
            /// this endpoint.
            #[serde(skip_serializing_if = "Option::is_none")]
            #[ruma_api(query)]
            pub to: Option<&'a str>,

            /// The direction to return events from.
            #[ruma_api(query)]
            pub dir: Direction,

            /// The maximum number of events to return.
            ///
            /// Default: `10`.
            #[ruma_api(query)]
            #[serde(default = "default_limit", skip_serializing_if = "is_default_limit")]
            pub limit: UInt,

            /// A [`RoomEventFilter`] to filter returned events with.
            #[ruma_api(query)]
            #[serde(
                with = "ruma_common::serde::json_string",
                default,
                skip_serializing_if = "RoomEventFilter::is_empty"
            )]
            pub filter: RoomEventFilter<'a>,
        }

        #[derive(Default)]
        response: {
            /// The token the pagination starts from.
            pub start: String,

            /// The token the pagination ends at.
            #[serde(skip_serializing_if = "Option::is_none")]
            pub end: Option<String>,

            /// A list of room events.
            #[serde(default)]
            pub chunk: Vec<Raw<AnyRoomEvent>>,

            /// A list of state events relevant to showing the `chunk`.
            #[serde(default, skip_serializing_if = "Vec::is_empty")]
            pub state: Vec<Raw<AnyStateEvent>>,
        }

        error: crate::Error
    }

    impl<'a> Request<'a> {
        /// Creates a new `Request` with the given room ID and direction.
        ///
        /// All other parameters will be defaulted.
        pub fn new(room_id: &'a RoomId, dir: Direction) -> Self {
            Self {
                room_id,
                from: None,
                to: None,
                dir,
                limit: default_limit(),
                filter: RoomEventFilter::default(),
            }
        }

        /// Creates a new `Request` with the given room ID and `dir` set to `Backward`.
        ///
        /// # Example
        ///
        /// ```rust
        /// # use ruma_client_api::message::get_message_events;
        /// # let room_id = ruma_common::room_id!("!a:example.org");
        /// # let token = "prev_batch token";
        /// let request = get_message_events::v3::Request::backward(room_id).from(token);
        /// ```
        pub fn backward(room_id: &'a RoomId) -> Self {
            Self::new(room_id, Direction::Backward)
        }

        /// Creates a new `Request` with the given room ID and `dir` set to `Forward`.
        ///
        /// # Example
        ///
        /// ```rust
        /// # use ruma_client_api::message::get_message_events;
        /// # let room_id = ruma_common::room_id!("!a:example.org");
        /// # let token = "end token";
        /// let request = get_message_events::v3::Request::forward(room_id).from(token);
        /// ```
        pub fn forward(room_id: &'a RoomId) -> Self {
            Self::new(room_id, Direction::Forward)
        }

        /// Creates a new `Request` from `self` with the `from` field set to the given value.
        ///
        /// Since the field is public, you can also assign to it directly. This method merely acts
        /// as a shorthand for that, because it is very common to set this field.
        pub fn from(self, from: impl Into<Option<&'a str>>) -> Self {
            Self { from: from.into(), ..self }
        }
    }

    impl Response {
        /// Creates an empty `Response`.
        pub fn new() -> Self {
            Default::default()
        }
    }

    fn default_limit() -> UInt {
        uint!(10)
    }

    #[allow(clippy::trivially_copy_pass_by_ref)]
    fn is_default_limit(val: &UInt) -> bool {
        *val == default_limit()
    }

    /// The direction to return events from.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[allow(clippy::exhaustive_enums)]
    pub enum Direction {
        /// Return events backwards in time from the requested `from` token.
        #[serde(rename = "b")]
        Backward,

        /// Return events forwards in time from the requested `from` token.
        #[serde(rename = "f")]
        Forward,
    }

    #[cfg(all(test, feature = "client"))]
    mod tests {
        use js_int::uint;
        use ruma_common::{
            api::{MatrixVersion, OutgoingRequest, SendAccessToken},
            room_id,
        };

        use super::{Direction, Request};
        use crate::filter::{LazyLoadOptions, RoomEventFilter};

        #[test]
        fn serialize_some_room_event_filter() {
            let room_id = room_id!("!roomid:example.org");
            let rooms = &[room_id.to_owned()];
            let filter = RoomEventFilter {
                lazy_load_options: LazyLoadOptions::Enabled { include_redundant_members: true },
                rooms: Some(rooms),
                not_rooms: &[
                    room_id!("!room:example.org").to_owned(),
                    room_id!("!room2:example.org").to_owned(),
                    room_id!("!room3:example.org").to_owned(),
                ],
                not_types: &["type".into()],
                ..Default::default()
            };
            let req = Request {
                room_id,
                from: Some("token"),
                to: Some("token2"),
                dir: Direction::Backward,
                limit: uint!(0),
                filter,
            };

            let request: http::Request<Vec<u8>> = req
                .try_into_http_request(
                    "https://homeserver.tld",
                    SendAccessToken::IfRequired("auth_tok"),
                    &[MatrixVersion::V1_1],
                )
                .unwrap();
            assert_eq!(
            "from=token\
             &to=token2\
             &dir=b\
             &limit=0\
             &filter=%7B%22not_types%22%3A%5B%22type%22%5D%2C%22not_rooms%22%3A%5B%22%21room%3Aexample.org%22%2C%22%21room2%3Aexample.org%22%2C%22%21room3%3Aexample.org%22%5D%2C%22rooms%22%3A%5B%22%21roomid%3Aexample.org%22%5D%2C%22lazy_load_members%22%3Atrue%2C%22include_redundant_members%22%3Atrue%7D",
            request.uri().query().unwrap()
        );
        }

        #[test]
        fn serialize_default_room_event_filter() {
            let room_id = room_id!("!roomid:example.org");
            let req = Request {
                room_id,
                from: Some("token"),
                to: Some("token2"),
                dir: Direction::Backward,
                limit: uint!(0),
                filter: RoomEventFilter::default(),
            };

            let request = req
                .try_into_http_request::<Vec<u8>>(
                    "https://homeserver.tld",
                    SendAccessToken::IfRequired("auth_tok"),
                    &[MatrixVersion::V1_1],
                )
                .unwrap();
            assert_eq!("from=token&to=token2&dir=b&limit=0", request.uri().query().unwrap(),);
        }
    }
}
<commit_msg>client-api: Add more docs to `get_message_events::Request`s constructors<commit_after>//! `GET /_matrix/client/*/rooms/{roomId}/messages`

pub mod v3 {
    //! `/v3/` ([spec])
    //!
    //! [spec]: https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomidmessages

    use js_int::{uint, UInt};
    use ruma_common::{
        api::ruma_api,
        events::{AnyRoomEvent, AnyStateEvent},
        serde::Raw,
        RoomId,
    };
    use serde::{Deserialize, Serialize};

    use crate::filter::{IncomingRoomEventFilter, RoomEventFilter};

    ruma_api! {
        metadata: {
            description: "Get message events for a room.",
            method: GET,
            name: "get_message_events",
            r0_path: "/_matrix/client/r0/rooms/:room_id/messages",
            stable_path: "/_matrix/client/v3/rooms/:room_id/messages",
            rate_limited: false,
            authentication: AccessToken,
            added: 1.0,
        }

        request: {
            /// The room to get events from.
            #[ruma_api(path)]
            pub room_id: &'a RoomId,

            /// The token to start returning events from.
            ///
            /// This token can be obtained from a `prev_batch` token returned for each room by the
            /// sync endpoint, or from a `start` or `end` token returned by a previous request to
            /// this endpoint.
            ///
            /// If this is `None`, the server will return messages from the start or end of the
            /// history visible to the user, depending on the value of [`dir`][Self::dir].
            #[ruma_api(query)]
            pub from: Option<&'a str>,

            /// The token to stop returning events at.
            ///
            /// This token can be obtained from a `prev_batch` token returned for each room by the
            /// sync endpoint, or from a `start` or `end` token returned by a previous request to
            /// this endpoint.
            #[serde(skip_serializing_if = "Option::is_none")]
            #[ruma_api(query)]
            pub to: Option<&'a str>,

            /// The direction to return events from.
            #[ruma_api(query)]
            pub dir: Direction,

            /// The maximum number of events to return.
            ///
            /// Default: `10`.
            #[ruma_api(query)]
            #[serde(default = "default_limit", skip_serializing_if = "is_default_limit")]
            pub limit: UInt,

            /// A [`RoomEventFilter`] to filter returned events with.
            #[ruma_api(query)]
            #[serde(
                with = "ruma_common::serde::json_string",
                default,
                skip_serializing_if = "RoomEventFilter::is_empty"
            )]
            pub filter: RoomEventFilter<'a>,
        }

        #[derive(Default)]
        response: {
            /// The token the pagination starts from.
            pub start: String,

            /// The token the pagination ends at.
            #[serde(skip_serializing_if = "Option::is_none")]
            pub end: Option<String>,

            /// A list of room events.
            #[serde(default)]
            pub chunk: Vec<Raw<AnyRoomEvent>>,

            /// A list of state events relevant to showing the `chunk`.
            #[serde(default, skip_serializing_if = "Vec::is_empty")]
            pub state: Vec<Raw<AnyStateEvent>>,
        }

        error: crate::Error
    }

    impl<'a> Request<'a> {
        /// Creates a new `Request` with the given room ID and direction.
        ///
        /// All other parameters will be defaulted.
        pub fn new(room_id: &'a RoomId, dir: Direction) -> Self {
            Self {
                room_id,
                from: None,
                to: None,
                dir,
                limit: default_limit(),
                filter: RoomEventFilter::default(),
            }
        }

        /// Creates a new `Request` with the given room ID and `dir` set to `Backward`.
        ///
        /// If the returned request is sent without `from` being set, pagination will start at the
        /// end of (the accessible part of) the room timeline.
        ///
        /// # Example
        ///
        /// ```rust
        /// # use ruma_client_api::message::get_message_events;
        /// # let room_id = ruma_common::room_id!("!a:example.org");
        /// # let token = "prev_batch token";
        /// let request = get_message_events::v3::Request::backward(room_id).from(token);
        /// ```
        pub fn backward(room_id: &'a RoomId) -> Self {
            Self::new(room_id, Direction::Backward)
        }

        /// Creates a new `Request` with the given room ID and `dir` set to `Forward`.
        ///
        /// If the returned request is sent without `from` being set, pagination will start at the
        /// beginning of (the accessible part of) the room timeline.
        ///
        /// # Example
        ///
        /// ```rust
        /// # use ruma_client_api::message::get_message_events;
        /// # let room_id = ruma_common::room_id!("!a:example.org");
        /// # let token = "end token";
        /// let request = get_message_events::v3::Request::forward(room_id).from(token);
        /// ```
        pub fn forward(room_id: &'a RoomId) -> Self {
            Self::new(room_id, Direction::Forward)
        }

        /// Creates a new `Request` from `self` with the `from` field set to the given value.
        ///
        /// Since the field is public, you can also assign to it directly. This method merely acts
        /// as a shorthand for that, because it is very common to set this field.
        pub fn from(self, from: impl Into<Option<&'a str>>) -> Self {
            Self { from: from.into(), ..self }
        }
    }

    impl Response {
        /// Creates an empty `Response`.
        pub fn new() -> Self {
            Default::default()
        }
    }

    fn default_limit() -> UInt {
        uint!(10)
    }

    #[allow(clippy::trivially_copy_pass_by_ref)]
    fn is_default_limit(val: &UInt) -> bool {
        *val == default_limit()
    }

    /// The direction to return events from.
    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[allow(clippy::exhaustive_enums)]
    pub enum Direction {
        /// Return events backwards in time from the requested `from` token.
        #[serde(rename = "b")]
        Backward,

        /// Return events forwards in time from the requested `from` token.
        #[serde(rename = "f")]
        Forward,
    }

    #[cfg(all(test, feature = "client"))]
    mod tests {
        use js_int::uint;
        use ruma_common::{
            api::{MatrixVersion, OutgoingRequest, SendAccessToken},
            room_id,
        };

        use super::{Direction, Request};
        use crate::filter::{LazyLoadOptions, RoomEventFilter};

        #[test]
        fn serialize_some_room_event_filter() {
            let room_id = room_id!("!roomid:example.org");
            let rooms = &[room_id.to_owned()];
            let filter = RoomEventFilter {
                lazy_load_options: LazyLoadOptions::Enabled { include_redundant_members: true },
                rooms: Some(rooms),
                not_rooms: &[
                    room_id!("!room:example.org").to_owned(),
                    room_id!("!room2:example.org").to_owned(),
                    room_id!("!room3:example.org").to_owned(),
                ],
                not_types: &["type".into()],
                ..Default::default()
            };
            let req = Request {
                room_id,
                from: Some("token"),
                to: Some("token2"),
                dir: Direction::Backward,
                limit: uint!(0),
                filter,
            };

            let request: http::Request<Vec<u8>> = req
                .try_into_http_request(
                    "https://homeserver.tld",
                    SendAccessToken::IfRequired("auth_tok"),
                    &[MatrixVersion::V1_1],
                )
                .unwrap();
            assert_eq!(
            "from=token\
             &to=token2\
             &dir=b\
             &limit=0\
             &filter=%7B%22not_types%22%3A%5B%22type%22%5D%2C%22not_rooms%22%3A%5B%22%21room%3Aexample.org%22%2C%22%21room2%3Aexample.org%22%2C%22%21room3%3Aexample.org%22%5D%2C%22rooms%22%3A%5B%22%21roomid%3Aexample.org%22%5D%2C%22lazy_load_members%22%3Atrue%2C%22include_redundant_members%22%3Atrue%7D",
            request.uri().query().unwrap()
        );
        }

        #[test]
        fn serialize_default_room_event_filter() {
            let room_id = room_id!("!roomid:example.org");
            let req = Request {
                room_id,
                from: Some("token"),
                to: Some("token2"),
                dir: Direction::Backward,
                limit: uint!(0),
                filter: RoomEventFilter::default(),
            };

            let request = req
                .try_into_http_request::<Vec<u8>>(
                    "https://homeserver.tld",
                    SendAccessToken::IfRequired("auth_tok"),
                    &[MatrixVersion::V1_1],
                )
                .unwrap();
            assert_eq!("from=token&to=token2&dir=b&limit=0", request.uri().query().unwrap(),);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Jorge Aparicio

use std::iter::count;
use std::util::replace;

fn main() {
    let mut primes = ~[2];
    let mut next = Factors(~[(2, 1)]);

    for n in count(3u, 1) {
        let curr = replace(&mut next, factorize(n, &mut primes));
        let triangle = next * curr * Factors(~[(2, -1)]);

        if triangle.number_of_divisors() > 500 {
            println!("{}", n * (n - 1) / 2);
            return;
        }
    }
}

// Factors(~[(a, x), (b, y)]) <-> a^x * b^y
struct Factors(~[(uint, int)]);

fn factorize(mut n: uint, primes: &mut ~[uint]) -> Factors {
    let mut factors = ~[];

    for &prime in primes.iter() {
        if n == 1 {
            break;
        }

        if prime * prime > n {
            factors.push((n, 1));
            break;
        }

        let mut i = 0;
        while n % prime == 0 {
            i += 1;
            n /= prime;
        }

        if i != 0 {
            factors.push((prime, i));
        }
    }

    if n != 1 && n > *primes.last().unwrap() {
        primes.push(n);
    }

    Factors(factors)
}

impl Factors {
    fn number_of_divisors(&self) -> int {
        let &Factors(ref s) = self;

        s.iter().fold(1, |n, &(_, e)| n * (e + 1))
    }
}

impl Mul<Factors, Factors> for Factors {
    fn mul(&self, rhs: &Factors) -> Factors {
        let (&Factors(ref s), &Factors(ref r)) = (self, rhs);

        let (m, n) = (s.len(), r.len());
        let (mut i, mut j) = (0 ,0);

        let mut o = ~[];
        while i != m || j != n {
            if i == m {
                o.push(r[j]);
                j += 1;
            } else if j == n {
                o.push(s[i]);
                i += 1;
            } else {
                let ((a, x), (b, y)) = (s[i], r[j]);

                if a > b {
                    o.push((b, y));
                    j += 1;
                } else if a < b {
                    o.push((a, x));
                    i += 1;
                } else {
                    if x + y > 0 {
                        o.push((a, x + y));
                    }

                    i += 1;
                    j += 1;
                }
            }
        }

        Factors(o)
    }
}

<commit_msg>012.rs: replace is in std::mem now<commit_after>// Copyright (C) 2014 Jorge Aparicio

use std::iter::count;
use std::mem::replace;

fn main() {
    let mut primes = ~[2];
    let mut next = Factors(~[(2, 1)]);

    for n in count(3u, 1) {
        let curr = replace(&mut next, factorize(n, &mut primes));
        let triangle = next * curr * Factors(~[(2, -1)]);

        if triangle.number_of_divisors() > 500 {
            println!("{}", n * (n - 1) / 2);
            return;
        }
    }
}

// Factors(~[(a, x), (b, y)]) <-> a^x * b^y
struct Factors(~[(uint, int)]);

fn factorize(mut n: uint, primes: &mut ~[uint]) -> Factors {
    let mut factors = ~[];

    for &prime in primes.iter() {
        if n == 1 {
            break;
        }

        if prime * prime > n {
            factors.push((n, 1));
            break;
        }

        let mut i = 0;
        while n % prime == 0 {
            i += 1;
            n /= prime;
        }

        if i != 0 {
            factors.push((prime, i));
        }
    }

    if n != 1 && n > *primes.last().unwrap() {
        primes.push(n);
    }

    Factors(factors)
}

impl Factors {
    fn number_of_divisors(&self) -> int {
        let &Factors(ref s) = self;

        s.iter().fold(1, |n, &(_, e)| n * (e + 1))
    }
}

impl Mul<Factors, Factors> for Factors {
    fn mul(&self, rhs: &Factors) -> Factors {
        let (&Factors(ref s), &Factors(ref r)) = (self, rhs);

        let (m, n) = (s.len(), r.len());
        let (mut i, mut j) = (0 ,0);

        let mut o = ~[];
        while i != m || j != n {
            if i == m {
                o.push(r[j]);
                j += 1;
            } else if j == n {
                o.push(s[i]);
                i += 1;
            } else {
                let ((a, x), (b, y)) = (s[i], r[j]);

                if a > b {
                    o.push((b, y));
                    j += 1;
                } else if a < b {
                    o.push((a, x));
                    i += 1;
                } else {
                    if x + y > 0 {
                        o.push((a, x + y));
                    }

                    i += 1;
                    j += 1;
                }
            }
        }

        Factors(o)
    }
}

<|endoftext|>


<commit_before>//! This iterator emits `BlockPositions` in cube-shaped layers outward around a point.

use cube_shell::cube_shell;
use std::collections::VecDeque;
use block_position::BlockPosition;

#[cfg(test)]
use std::iter::range_inclusive;
#[cfg(test)]
use cube_shell::cube_shell_area;
#[cfg(test)]
use surroundings_loader::radius_between;

/// This iterator emits `BlockPositions` in cube-shaped layers outward around a point.
pub struct SurroundingsIter {
  center: BlockPosition,
  next_distance: i32,
  max_distance: i32,
}

impl SurroundingsIter {
  #[allow(missing_docs)]
  pub fn new(center: BlockPosition, max_distance: i32) -> SurroundingsIter {
    let mut to_load_buffer = VecDeque::new();
    to_load_buffer.push_back(center);

    SurroundingsIter {
      center: center,
      next_distance: 0,
      max_distance: max_distance,
      to_load_buffer: to_load_buffer,
    }
  }
}

impl Iterator for SurroundingsIter {
  type Item = BlockPosition;

  #[inline]
  fn next(&mut self) -> Option<Self::Item> {
    self.to_load_buffer.pop_front().map(|x| {
      if self.to_load_buffer.is_empty() {
        info!("Done loading surroundings at distance {}", self.next_distance);
        if self.next_distance < self.max_distance {
          self.next_distance += 1;
          self.to_load_buffer.extend(
            cube_shell(&self.center, self.next_distance).into_iter()
          );
        } else {
          info!("Done loading surroundings");
        }
      }
      x
    })
  }
}

#[test]
fn shell_ordering() {
  let center = BlockPosition::new(-1, 2, 3);
  let max_distance = 4;
  let mut iter = SurroundingsIter::new(center, max_distance);

  for distance in range_inclusive(0, max_distance) {
    for _ in 0..cube_shell_area(distance) {
      let (block_posn, d) = iter.next().unwrap();
      assert_eq!(d, distance);
      assert_eq!(radius_between(&center, &block_posn), distance);
    }
  }

  assert!(iter.next().is_none());
}
<commit_msg>remove unused file<commit_after><|endoftext|>