<commit_before>use hir::db::HirDatabase;
use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
use rustc_lexer;

use crate::{Assist, AssistCtx, AssistId};

pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    let usual_string_range = find_usual_string_range(text)?;
    ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
        edit.target(literal.syntax().text_range());
        let start_of_inside = usual_string_range.start().to_usize() + 1;
        let end_of_inside = usual_string_range.end().to_usize();
        let inside_str = &text[start_of_inside..end_of_inside];
        let mut unescaped = String::with_capacity(inside_str.len());
        let mut error = Ok(());
        rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| {
            match unescaped_char {
                Ok(c) => unescaped.push(c),
                Err(_) => error = Err(()),
            }
        });
        if error.is_err() {
            eprintln!("Error unescaping string");
        } else {
            let mut max_hash_streak = 0;
            unescaped.chars().fold(0, |acc, c| {
                if c == '#' {
                    acc + 1
                } else {
                    if acc > max_hash_streak {
                        max_hash_streak = acc;
                    }
                    0
                }
            });
            let mut hashes = String::with_capacity(max_hash_streak + 1);
            for _ in 0..hashes.capacity() {
                hashes.push('#');
            }
            edit.replace(
                literal.syntax().text_range(),
                format!("r{}\"{}\"{}", hashes, unescaped, hashes),
            );
        }
    });
    ctx.build()
}

fn find_usual_string_range(s: &str) -> Option<TextRange> {
    Some(TextRange::from_to(
        TextUnit::from(s.find('"')? as u32),
        TextUnit::from(s.rfind('"')? as u32),
    ))
}

pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    let usual_string_range = find_usual_string_range(text)?;
    ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| {
        edit.target(literal.syntax().text_range());
        // parse inside string to escape `"`
        let start_of_inside = usual_string_range.start().to_usize() + 1;
        let end_of_inside = usual_string_range.end().to_usize();
        let inside_str = &text[start_of_inside..end_of_inside];
        let escaped = inside_str.escape_default().to_string();
        edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped));
    });
    ctx.build()
}

pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| {
        edit.target(literal.syntax().text_range());
        edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#");
        edit.insert(literal.syntax().text_range().end(), "#");
    });
    ctx.build()
}

pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    if text.starts_with("r\"") {
        // no hash to remove
        return None;
    }
    ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| {
        edit.target(literal.syntax().text_range());
        let result = &text[2..text.len() - 1];
        let result = if result.starts_with("\"") {
            // no more hash, escape
            let internal_str = &result[1..result.len() - 1];
            format!("\"{}\"", internal_str.escape_default().to_string())
        } else {
            result.to_owned()
        };
        edit.replace(literal.syntax().text_range(), format!("r{}", result));
    });
    ctx.build()
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn make_raw_string_target() {
        check_assist_target(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r#""random\nstring""#,
        );
    }

    #[test]
    fn make_raw_string_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random
string"#;
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
            fn f() {
                let s = <|>"#random##\nstring";
            }
            "###,
            r####"
            fn f() {
                let s = <|>r###"#random##
string"###;
            }
            "####,
        )
    }
    #[test]
    fn make_raw_string_nothing_to_unescape_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_hash_target() {
        check_assist_target(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r#"r"random string""#,
        );
    }

    #[test]
    fn add_hash_works() {
        check_assist(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_more_hash_works() {
        check_assist(
            add_hash,
            r##"
            fn f() {
                let s = <|>r#"random"string"#;
            }
            "##,
            r###"
            fn f() {
                let s = <|>r##"random"string"##;
            }
            "###,
        )
    }

    #[test]
    fn add_hash_not_works() {
        check_assist_not_applicable(
            add_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_target() {
        check_assist_target(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn remove_hash_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
        )
    }

    #[test]
    fn remove_hash_with_quote_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>r"random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn remove_more_hash_works() {
        check_assist(
            remove_hash,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn remove_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_no_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
        );
    }

    #[test]
    fn make_usual_string_target() {
        check_assist_target(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn make_usual_string_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_with_quote_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>"random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_more_hash_works() {
        check_assist(
            make_usual_string,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = <|>"random string";
            }
            "##,
        )
    }

    #[test]
    fn make_usual_string_not_works() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }
}
<commit_msg>feat(assists): Even smarter with hashes<commit_after>use hir::db::HirDatabase;
use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
use rustc_lexer;

use crate::{Assist, AssistCtx, AssistId};

pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    let usual_string_range = find_usual_string_range(text)?;
    ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
        edit.target(literal.syntax().text_range());
        let start_of_inside = usual_string_range.start().to_usize() + 1;
        let end_of_inside = usual_string_range.end().to_usize();
        let inside_str = &text[start_of_inside..end_of_inside];
        let mut unescaped = String::with_capacity(inside_str.len());
        let mut error = Ok(());
        rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| {
            match unescaped_char {
                Ok(c) => unescaped.push(c),
                Err(_) => error = Err(()),
            }
        });
        if error.is_err() {
            eprintln!("Error unescaping string");
        } else {
            let max_hash_streak = count_hashes(&unescaped);
            let mut hashes = String::with_capacity(max_hash_streak + 1);
            for _ in 0..hashes.capacity() {
                hashes.push('#');
            }
            edit.replace(
                literal.syntax().text_range(),
                format!("r{}\"{}\"{}", hashes, unescaped, hashes),
            );
        }
    });
    ctx.build()
}

fn count_hashes(s: &str) -> usize {
    let indexes: Vec<_> = s.match_indices("\"#").map(|(i, _)| i).collect();
    let mut max_hash_streak = 0usize;
    for idx in indexes {
        let (_, sub) = s.split_at(idx + 1);
        let nb_hash = sub.chars().take_while(|c| *c == '#').count();
        if nb_hash > max_hash_streak {
            max_hash_streak = nb_hash;
        }
    }
    max_hash_streak
}

fn find_usual_string_range(s: &str) -> Option<TextRange> {
    Some(TextRange::from_to(
        TextUnit::from(s.find('"')? as u32),
        TextUnit::from(s.rfind('"')? as u32),
    ))
}

pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    let usual_string_range = find_usual_string_range(text)?;
    ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| {
        edit.target(literal.syntax().text_range());
        // parse inside string to escape `"`
        let start_of_inside = usual_string_range.start().to_usize() + 1;
        let end_of_inside = usual_string_range.end().to_usize();
        let inside_str = &text[start_of_inside..end_of_inside];
        let escaped = inside_str.escape_default().to_string();
        edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped));
    });
    ctx.build()
}

pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| {
        edit.target(literal.syntax().text_range());
        edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#");
        edit.insert(literal.syntax().text_range().end(), "#");
    });
    ctx.build()
}

pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let literal = ctx.node_at_offset::<Literal>()?;
    if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
        return None;
    }
    let token = literal.token();
    let text = token.text().as_str();
    if text.starts_with("r\"") {
        // no hash to remove
        return None;
    }
    ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| {
        edit.target(literal.syntax().text_range());
        let result = &text[2..text.len() - 1];
        let result = if result.starts_with("\"") {
            // no more hash, escape
            let internal_str = &result[1..result.len() - 1];
            format!("\"{}\"", internal_str.escape_default().to_string())
        } else {
            result.to_owned()
        };
        edit.replace(literal.syntax().text_range(), format!("r{}", result));
    });
    ctx.build()
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn make_raw_string_target() {
        check_assist_target(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r#""random\nstring""#,
        );
    }

    #[test]
    fn make_raw_string_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random\nstring";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random
string"#;
            }
            "##,
        )
    }

    #[test]
    fn make_raw_string_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
            fn f() {
                let s = <|>"#random##\nstring";
            }
            "###,
            r####"
            fn f() {
                let s = <|>r#"#random##
string"#;
            }
            "####,
        )
    }

    #[test]
    fn make_raw_string_closing_hashes_inside_works() {
        check_assist(
            make_raw_string,
            r###"
            fn f() {
                let s = <|>"#random\"##\nstring";
            }
            "###,
            r####"
            fn f() {
                let s = <|>r###"#random"##
string"###;
            }
            "####,
        )
    }

    #[test]
    fn make_raw_string_nothing_to_unescape_works() {
        check_assist(
            make_raw_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_hash_target() {
        check_assist_target(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r#"r"random string""#,
        );
    }

    #[test]
    fn add_hash_works() {
        check_assist(
            add_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn add_more_hash_works() {
        check_assist(
            add_hash,
            r##"
            fn f() {
                let s = <|>r#"random"string"#;
            }
            "##,
            r###"
            fn f() {
                let s = <|>r##"random"string"##;
            }
            "###,
        )
    }

    #[test]
    fn add_hash_not_works() {
        check_assist_not_applicable(
            add_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_target() {
        check_assist_target(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn remove_hash_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
        )
    }

    #[test]
    fn remove_hash_with_quote_works() {
        check_assist(
            remove_hash,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>r"random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn remove_more_hash_works() {
        check_assist(
            remove_hash,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
        )
    }

    #[test]
    fn remove_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn remove_hash_no_hash_not_works() {
        check_assist_not_applicable(
            remove_hash,
            r#"
            fn f() {
                let s = <|>r"random string";
            }
            "#,
        );
    }

    #[test]
    fn make_usual_string_target() {
        check_assist_target(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r##"r#"random string"#"##,
        );
    }

    #[test]
    fn make_usual_string_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random string"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_with_quote_works() {
        check_assist(
            make_usual_string,
            r##"
            fn f() {
                let s = <|>r#"random"str"ing"#;
            }
            "##,
            r#"
            fn f() {
                let s = <|>"random\"str\"ing";
            }
            "#,
        )
    }

    #[test]
    fn make_usual_string_more_hash_works() {
        check_assist(
            make_usual_string,
            r###"
            fn f() {
                let s = <|>r##"random string"##;
            }
            "###,
            r##"
            fn f() {
                let s = <|>"random string";
            }
            "##,
        )
    }

    #[test]
    fn make_usual_string_not_works() {
        check_assist_not_applicable(
            make_usual_string,
            r#"
            fn f() {
                let s = <|>"random string";
            }
            "#,
        );
    }

    #[test]
    fn count_hashes_test() {
        assert_eq!(0, count_hashes("abc"));
        assert_eq!(0, count_hashes("###"));
        assert_eq!(1, count_hashes("\"#abc"));
        assert_eq!(0, count_hashes("#abc"));
        assert_eq!(2, count_hashes("#ab\"##c"));
        assert_eq!(4, count_hashes("#ab\"##\"####c"));
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::ops::Deref;

use attributes::Attribute;
use drawing_ctx::RsvgDrawingCtx;
use filter_context::RsvgFilterContext;
use error::AttributeError;
use filter_context::{FilterContext, RsvgFilterContext};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::State;

mod ffi;
use self::ffi::*;

pub mod offset;

/// A filter primitive interface.
trait Filter: NodeTrait {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), return without drawing anything.
    fn render(&self, ctx: *mut RsvgFilterContext);
}

/// The base filter node containing common properties.
struct Primitive {
    // The only purpose of this field is to communicate the render callback back to C code.
    // TODO: get rid of this once all filters have been ported to Rust.
    c_struct: RsvgFilterPrimitive,

    x: Cell<Option<RsvgLength>>,
    y: Cell<Option<RsvgLength>>,
    width: Cell<Option<RsvgLength>>,
    height: Cell<Option<RsvgLength>>,
    result: Cell<Option<String>>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterResult(String),
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: RefCell<Option<Input>>,
}

// TODO: remove #[repr(C)] when it's not needed.
#[repr(C)]
pub struct IRect {
    x0: i32,
    y0: i32,
    x1: i32,
    y1: i32,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: Filter>() -> Primitive {
        Primitive {
            c_struct: RsvgFilterPrimitive::new::<T>(),

            x: Cell::new(None),
            y: Cell::new(None),
            width: Cell::new(None),
            height: Cell::new(None),
            result: Cell::new(None),
        }
    }
}

impl NodeTrait for Primitive {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(Some(parse("x", value, LengthDir::Horizontal, None)?)),
                Attribute::Y => self.y.set(Some(parse("y", value, LengthDir::Vertical, None)?)),
                Attribute::Width => self.width.set(Some(parse("width", value, LengthDir::Horizontal, None)?)),
                Attribute::Height => self.height.set(Some(parse("height", value, LengthDir::Vertical, None)?)),
                Attribute::Result => self.result.set(Some(value.to_string())),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        // At least for now we have to return a *const RsvgFilterPrimitive.
        &self.c_struct as *const RsvgFilterPrimitive as *const RsvgCNodeImpl
    }
}

impl Parse for Input {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        match s {
            "SourceGraphic" => Ok(Input::SourceGraphic),
            "SourceAlpha" => Ok(Input::SourceAlpha),
            "BackgroundImage" => Ok(Input::BackgroundImage),
            "BackgroundAlpha" => Ok(Input::BackgroundAlpha),
            "FillPaint" => Ok(Input::FillPaint),
            "StrokePaint" => Ok(Input::StrokePaint),
            s => Ok(Input::FilterResult(s.to_string())),
        }
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: Filter>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new(),
            in_: RefCell::new(None),
        }
    }
}

impl NodeTrait for PrimitiveWithInput {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In => drop(self.in_.replace(Some(parse("in", value, (), None)?))),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Deref for PrimitiveWithInput {
    type Target = Primitive;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.base
    }
}
<commit_msg>Add PrimitiveWithInput::get_input()<commit_after>use std::cell::{Cell, RefCell};
use std::ops::Deref;

use cairo;

use attributes::Attribute;
use drawing_ctx::RsvgDrawingCtx;
use filter_context::RsvgFilterContext;
use error::AttributeError;
use filter_context::{FilterContext, RsvgFilterContext};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::State;

mod ffi;
use self::ffi::*;

pub mod offset;

/// A filter primitive interface.
trait Filter: NodeTrait {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), return without drawing anything.
    fn render(&self, ctx: *mut RsvgFilterContext);
}

/// The base filter node containing common properties.
struct Primitive {
    // The only purpose of this field is to communicate the render callback back to C code.
    // TODO: get rid of this once all filters have been ported to Rust.
    c_struct: RsvgFilterPrimitive,

    x: Cell<Option<RsvgLength>>,
    y: Cell<Option<RsvgLength>>,
    width: Cell<Option<RsvgLength>>,
    height: Cell<Option<RsvgLength>>,
    result: Cell<Option<String>>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterResult(String),
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: RefCell<Option<Input>>,
}

// TODO: remove #[repr(C)] when it's not needed.
#[repr(C)]
pub struct IRect {
    x0: i32,
    y0: i32,
    x1: i32,
    y1: i32,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: Filter>() -> Primitive {
        Primitive {
            c_struct: RsvgFilterPrimitive::new::<T>(),

            x: Cell::new(None),
            y: Cell::new(None),
            width: Cell::new(None),
            height: Cell::new(None),
            result: Cell::new(None),
        }
    }
}

impl NodeTrait for Primitive {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(Some(parse("x", value, LengthDir::Horizontal, None)?)),
                Attribute::Y => self.y.set(Some(parse("y", value, LengthDir::Vertical, None)?)),
                Attribute::Width => self.width.set(Some(parse("width", value, LengthDir::Horizontal, None)?)),
                Attribute::Height => self.height.set(Some(parse("height", value, LengthDir::Vertical, None)?)),
                Attribute::Result => self.result.set(Some(value.to_string())),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        // At least for now we have to return a *const RsvgFilterPrimitive.
        &self.c_struct as *const RsvgFilterPrimitive as *const RsvgCNodeImpl
    }
}

impl Parse for Input {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        match s {
            "SourceGraphic" => Ok(Input::SourceGraphic),
            "SourceAlpha" => Ok(Input::SourceAlpha),
            "BackgroundImage" => Ok(Input::BackgroundImage),
            "BackgroundAlpha" => Ok(Input::BackgroundAlpha),
            "FillPaint" => Ok(Input::FillPaint),
            "StrokePaint" => Ok(Input::StrokePaint),
            s => Ok(Input::FilterResult(s.to_string())),
        }
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: Filter>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new(),
            in_: RefCell::new(None),
        }
    }

    /// Returns the input Cairo surface for this filter primitive.
    // TODO: abstract over cairo::ImageSurface, will also allow to handle FillPaint and StrokePaint.
    fn get_input(&self, ctx: &FilterContext) -> Option<cairo::ImageSurface> {
        let in_ = self.in_.borrow();
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            return Some(ctx.last_result().unwrap_or_else(|| ctx.source_graphic()));
        }

        match *in_.as_ref().unwrap() {
            Input::SourceGraphic => Some(ctx.source_graphic()),
            Input::SourceAlpha => unimplemented!(),
            Input::BackgroundImage => Some(ctx.background_image()),
            Input::BackgroundAlpha => unimplemented!(),

            Input::FillPaint => unimplemented!(),
            Input::StrokePaint => unimplemented!(),

            Input::FilterResult(ref name) => ctx.filter_result(name),
        }
    }
}

impl NodeTrait for PrimitiveWithInput {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In => drop(self.in_.replace(Some(parse("in", value, (), None)?))),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Deref for PrimitiveWithInput {
    type Target = Primitive;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.base
    }
}
<|endoftext|>


<commit_before>//! Time sources for the rate limiter.
//!
//! The time sources contained in this module allow the rate limiter
//! to be (optionally) independent of std, and should additionally
//! allow mocking the passage of time.

use crate::lib::*;

/// A measurement from a clock.
pub trait Reference:
    Sized
    + Sub<Duration, Output = Self>
    + Add<Duration, Output = Self>
    + PartialEq
    + Eq
    + Ord
    + Copy
    + Clone
    + Send
    + Sync
    + Debug
{
    /// Determines the time that separates two measurements of a clock.
    fn duration_since(&self, earlier: Self) -> Duration;
}

/// A time source used by rate limiters.
pub trait Clock: Default + Clone {
    /// A measurement of a monotonically increasing clock.
    type Instant: Reference;

    /// Returns a measurement of the clock.
    fn now(&self) -> Self::Instant;
}

impl Reference for Duration {
    fn duration_since(&self, earlier: Self) -> Duration {
        *self - earlier
    }
}

/// A mock implementation of a clock. All it does is keep track of
/// what "now" is (relative to some point meaningful to the program),
/// and returns that.
#[derive(Debug, PartialEq, Clone)]
pub struct FakeRelativeClock {
    now: Duration,
}

impl Default for FakeRelativeClock {
    fn default() -> Self {
        FakeRelativeClock {
            now: Duration::from_nanos(0),
        }
    }
}

impl FakeRelativeClock {
    /// Advances the fake clock by the given amount.
    pub fn advance(&mut self, by: Duration) {
        self.now += by
    }
}

impl Clock for FakeRelativeClock {
    type Instant = Duration;

    fn now(&self) -> Self::Instant {
        self.now
    }
}

#[cfg(not(feature = "std"))]
mod no_std;
#[cfg(not(feature = "std"))]
pub use no_std::*;

#[cfg(feature = "std")]
mod with_std;
#[cfg(feature = "std")]
pub use with_std::*;
<commit_msg>Derive default for the no_std fake clock too<commit_after>//! Time sources for the rate limiter.
//!
//! The time sources contained in this module allow the rate limiter
//! to be (optionally) independent of std, and should additionally
//! allow mocking the passage of time.

use crate::lib::*;

/// A measurement from a clock.
pub trait Reference:
    Sized
    + Sub<Duration, Output = Self>
    + Add<Duration, Output = Self>
    + PartialEq
    + Eq
    + Ord
    + Copy
    + Clone
    + Send
    + Sync
    + Debug
{
    /// Determines the time that separates two measurements of a clock.
    fn duration_since(&self, earlier: Self) -> Duration;
}

/// A time source used by rate limiters.
pub trait Clock: Default + Clone {
    /// A measurement of a monotonically increasing clock.
    type Instant: Reference;

    /// Returns a measurement of the clock.
    fn now(&self) -> Self::Instant;
}

impl Reference for Duration {
    fn duration_since(&self, earlier: Self) -> Duration {
        *self - earlier
    }
}

/// A mock implementation of a clock. All it does is keep track of
/// what "now" is (relative to some point meaningful to the program),
/// and returns that.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct FakeRelativeClock {
    now: Duration,
}

impl FakeRelativeClock {
    /// Advances the fake clock by the given amount.
    pub fn advance(&mut self, by: Duration) {
        self.now += by
    }
}

impl Clock for FakeRelativeClock {
    type Instant = Duration;

    fn now(&self) -> Self::Instant {
        self.now
    }
}

#[cfg(not(feature = "std"))]
mod no_std;
#[cfg(not(feature = "std"))]
pub use no_std::*;

#[cfg(feature = "std")]
mod with_std;
#[cfg(feature = "std")]
pub use with_std::*;
<|endoftext|>


<commit_before>//! Colors.

use std::fmt;

/// A terminal color.
pub trait Color {
    /// Write the foreground version of this color.
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Write the background version of this color.
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

macro_rules! derive_color {
    ($doc:expr, $name:ident, $value:expr) => {
        #[doc = $doc]
        #[derive(Copy, Clone)]
        pub struct $name;

        impl Color for $name {
            #[inline]
            fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("38;5;", $value, "m"))
            }

            #[inline]
            fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("48;5;", $value, "m"))
            }
        }
    };
}

derive_color!("Black.", Black, "0");
derive_color!("Red.", Red, "1");
derive_color!("Green.", Green, "2");
derive_color!("Yellow.", Yellow, "3");
derive_color!("Blue.", Blue, "4");
derive_color!("Magenta.", Magenta, "5");
derive_color!("Cyan.", Cyan, "6");
derive_color!("White.", White, "7");
derive_color!("High-intensity light black.", LightBlack, "8");
derive_color!("High-intensity light red.", LightRed, "9");
derive_color!("High-intensity light green.", LightGreen, "10");
derive_color!("High-intensity light yellow.", LightYellow, "11");
derive_color!("High-intensity light blue.", LightBlue, "12");
derive_color!("High-intensity light magenta.", LightMagenta, "13");
derive_color!("High-intensity light cyan.", LightCyan, "14");
derive_color!("High-intensity light white.", LightWhite, "15");

/// An arbitrary ANSI color value.
#[derive(Clone, Copy)]
pub struct AnsiValue(pub u8);

impl AnsiValue {
    /// 216-color (r, g, b ≤ 5) RGB.
    pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
        debug_assert!(r <= 5, "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", r);
        debug_assert!(g <= 5, "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", g);
        debug_assert!(b <= 5, "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", b);

        AnsiValue(16 + 36 * r + 6 * g + b)
    }

    /// Grayscale color.
    ///
    /// There are 24 shades of gray.
    pub fn grayscale(shade: u8) -> AnsiValue {
        // Unfortunately, there are a little less than fifty shades.
        debug_assert!(shade < 24, "Grayscale out of bound (shade = {}). There are only 24 shades of \
                      gray.", shade);

        AnsiValue(0xE8 + shade)
    }
}

impl Color for AnsiValue {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;5;{}m"), self.0)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;5;{}m"), self.0)
    }
}

/// A truecolor RGB.
pub struct Rgb(pub u8, pub u8, pub u8);

impl Color for Rgb {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2)
    }
}

/// Reset colors to defaults.
pub struct Reset;

impl Color for Reset {#[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("39m"))
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("49m"))
    }
}

/// A foreground color.
pub struct Fg<C: Color>(pub C);

impl<C: Color> fmt::Display for Fg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }
}

/// A background color.
pub struct Bg<C: Color>(pub C);

impl<C: Color> fmt::Display for Bg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}
<commit_msg>Fix formatting<commit_after>//! Colors.

use std::fmt;

/// A terminal color.
pub trait Color {
    /// Write the foreground version of this color.
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Write the background version of this color.
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

macro_rules! derive_color {
    ($doc:expr, $name:ident, $value:expr) => {
        #[doc = $doc]
        #[derive(Copy, Clone)]
        pub struct $name;

        impl Color for $name {
            #[inline]
            fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("38;5;", $value, "m"))
            }

            #[inline]
            fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, csi!("48;5;", $value, "m"))
            }
        }
    };
}

derive_color!("Black.", Black, "0");
derive_color!("Red.", Red, "1");
derive_color!("Green.", Green, "2");
derive_color!("Yellow.", Yellow, "3");
derive_color!("Blue.", Blue, "4");
derive_color!("Magenta.", Magenta, "5");
derive_color!("Cyan.", Cyan, "6");
derive_color!("White.", White, "7");
derive_color!("High-intensity light black.", LightBlack, "8");
derive_color!("High-intensity light red.", LightRed, "9");
derive_color!("High-intensity light green.", LightGreen, "10");
derive_color!("High-intensity light yellow.", LightYellow, "11");
derive_color!("High-intensity light blue.", LightBlue, "12");
derive_color!("High-intensity light magenta.", LightMagenta, "13");
derive_color!("High-intensity light cyan.", LightCyan, "14");
derive_color!("High-intensity light white.", LightWhite, "15");

/// An arbitrary ANSI color value.
#[derive(Clone, Copy)]
pub struct AnsiValue(pub u8);

impl AnsiValue {
    /// 216-color (r, g, b ≤ 5) RGB.
    pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
        debug_assert!(r <= 5, "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", r);
        debug_assert!(g <= 5, "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", g);
        debug_assert!(b <= 5, "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", b);

        AnsiValue(16 + 36 * r + 6 * g + b)
    }

    /// Grayscale color.
    ///
    /// There are 24 shades of gray.
    pub fn grayscale(shade: u8) -> AnsiValue {
        // Unfortunately, there are a little less than fifty shades.
        debug_assert!(shade < 24, "Grayscale out of bound (shade = {}). There are only 24 shades of \
                      gray.", shade);

        AnsiValue(0xE8 + shade)
    }
}

impl Color for AnsiValue {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;5;{}m"), self.0)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;5;{}m"), self.0)
    }
}

/// A truecolor RGB.
pub struct Rgb(pub u8, pub u8, pub u8);

impl Color for Rgb {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2)
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2)
    }
}

/// Reset colors to defaults.
pub struct Reset;

impl Color for Reset {
    #[inline]
    fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("39m"))
    }

    #[inline]
    fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, csi!("49m"))
    }
}

/// A foreground color.
pub struct Fg<C: Color>(pub C);

impl<C: Color> fmt::Display for Fg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_fg(f)
    }
}

/// A background color.
pub struct Bg<C: Color>(pub C);

impl<C: Color> fmt::Display for Bg<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.write_bg(f)
    }
}
<|endoftext|>


<commit_before>use rug::ops::{Pow};
use rug::Integer;
// use std::ops::{Add, Neg, Sub};

use euclid::*;

use defs::*;
use math;

// A "vector" in the world, possibly going up or down levels
// TODO: Do we need a `Dyadic`?

#[derive(Clone, Debug, PartialEq, Eq)] // MUST TODO: this Eq is dangerous!
pub struct Delta {
    pub zdelta: i16,
    pub scale: i16,
    pub coords: TypedVector2D<Integer, UniverseSpace>,
    // So a coord distance of 1 means a `real` distance of 2^(scale) at z value 0
}

impl Delta {
    pub fn zero() -> Delta {
        Delta {
            zdelta: 0,
            scale: 0,
            coords: TypedVector2D::new(Integer::new(), Integer::new()),
        }
    }

    pub fn append(&self, other: &Delta) -> Delta {
        let zdelta = self.zdelta + other.zdelta;
        let other_relative_scale = self.zdelta + other.scale;
        let newscale = self.scale.min(other_relative_scale);

        let newcoords: TypedVector2D<Integer, UniverseSpace>;
        if self.scale == other_relative_scale {
            newcoords = math::add_vec(self.coords.clone(), other.coords.clone());
        } else if self.scale >= other_relative_scale {
            let difference = (self.scale - other_relative_scale) as u32;
            newcoords = math::add_vec(
                math::scale_vec(&self.coords, &Integer::from(ZOOM_SCALE).pow(difference)),
                other.coords.clone(),
            );
        } else {
            let difference = (other_relative_scale - self.scale) as u32;
            newcoords = math::add_vec(
                math::scale_vec(&other.coords, &Integer::from(ZOOM_SCALE).pow(difference)),
                self.coords.clone(),
            );
        }

        Delta {
            zdelta: zdelta,
            scale: newscale,
            coords: newcoords,
        }
    }

    pub fn invert(&self) -> Delta {
        Delta {
            zdelta: -self.zdelta,
            scale: self.scale - self.zdelta,
            coords: TypedVector2D::new(-self.coords.x.clone(), -self.coords.y.clone()),
        }
    }

    pub fn revert(&self, other: &Delta) -> Delta {
        self.append(&other.invert())
    }

    // pub fn truncate(&self) -> Delta {
    //     if self.scale == self.zdelta {
    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: self.coords.clone(),
    //         }
    //     } else if self.scale > self.zdelta {
    //         let difference = (self.scale - self.zdelta) as u32;
    //         let newcoords =
    //             math::scale_vec(&self.coords, Integer::from(ZOOM_SCALE).pow(difference));

    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: newcoords,
    //         }
    //     } else {
    //         let difference = (self.zdelta - self.scale) as u32;
    //         let truncated_coords_x = self.coords.x.clone() >> difference;
    //         let truncated_coords_y = self.coords.y.clone() >> difference;
    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: TypedVector2D::new(truncated_coords_x, truncated_coords_y),
    //         }
    //     }
    // }

    pub fn to_scaled_fvec(&self) -> TypedVector2D<f32, UniverseSpace> {
        TypedVector2D::new(
            math::scaled_bigint_to_float(&self.coords.x, self.scale),
            math::scaled_bigint_to_float(&self.coords.y, self.scale),
        )
    }

    pub fn to_scale_transform(&self) -> TypedTransform2D<f32, UniverseSpace, UniverseSpace> {
        let scale = (ZOOM_SCALE as f32).powi(self.zdelta as i32);
        TypedTransform2D::identity()
            .post_scale(scale, scale)
            .post_translate(self.to_scaled_fvec())
    }

    pub fn to_uvec(&self) -> Option<UVec> {
        assert!(self.zdelta == 0);
        assert!(self.scale >= 0);
        Some( UVec::new(
            self.coords.x.to_i32().unwrap(),
            self.coords.y.to_i32().unwrap(),
        ) * ZOOM_SCALE.pow(self.scale as u32) as i32)
    }
}

impl<U> From<TypedVector2D<f32, U>> for Delta
where U: SpaceWithLevel
{
    fn from(c: TypedVector2D<f32, U>) -> Delta {
        let int_x = (c.x * (ZOOM_SCALE as f32).pow(FRACTIONAL_DELTA_SCALE as i32)) as u32;
        let int_y = (c.y * (ZOOM_SCALE as f32).pow(FRACTIONAL_DELTA_SCALE as i32)) as u32;

        Delta {
            zdelta: U::LEVEL,
            scale: U::LEVEL - FRACTIONAL_DELTA_SCALE as i16,
            coords: TypedVector2D::new(Integer::from(int_x), Integer::from(int_y)),
        }
    }
}

impl<U> From<TypedVector2D<i32, U>> for Delta
where U: SpaceWithLevel
{
    fn from(c: TypedVector2D<i32, U>) -> Delta {
        Delta {
            zdelta: U::LEVEL,
            scale: U::LEVEL,
            coords: TypedVector2D::new(Integer::from(c.x), Integer::from(c.y)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn fractional_append_1() {
        let a = Delta {
            zdelta: 2,
            scale: 1,
            coords: TypedVector2D::new(Integer::from(-1), Integer::from(0)),
        };
        let b = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(1), Integer::from(0)),
        };

        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: 1,
                scale: 1,
                coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
            }
        );
    }

    #[test]
    fn fractional_append_2() {
        let a = Delta {
            zdelta: 1,
            scale: 0,
            coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
        };

        let b = Delta {
            zdelta: 1,
            scale: 1,
            coords: TypedVector2D::new(Integer::from(-1), Integer::from(0)),
        };
        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: 2,
                scale: 0,
                coords: TypedVector2D::new(Integer::from(-4), Integer::from(0)),
            }
        );
    }

    #[test]
    fn fractional_append_3() {
        let a = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(1), Integer::from(0)),
        };

        let b = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
        };
        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: -2,
                scale: -2,
                coords: TypedVector2D::new(Integer::from(2), Integer::from(0)),
            }
        );
    }

}
<commit_msg>Fix accidental unsigned conversion<commit_after>use rug::ops::{Pow};
use rug::Integer;
// use std::ops::{Add, Neg, Sub};

use euclid::*;

use defs::*;
use math;

// A "vector" in the world, possibly going up or down levels
// TODO: Do we need a `Dyadic`?

#[derive(Clone, Debug, PartialEq, Eq)] // MUST TODO: this Eq is dangerous!
pub struct Delta {
    pub zdelta: i16,
    pub scale: i16,
    pub coords: TypedVector2D<Integer, UniverseSpace>,
    // So a coord distance of 1 means a `real` distance of 2^(scale) at z value 0
}

impl Delta {
    pub fn zero() -> Delta {
        Delta {
            zdelta: 0,
            scale: 0,
            coords: TypedVector2D::new(Integer::new(), Integer::new()),
        }
    }

    pub fn append(&self, other: &Delta) -> Delta {
        let zdelta = self.zdelta + other.zdelta;
        let other_relative_scale = self.zdelta + other.scale;
        let newscale = self.scale.min(other_relative_scale);

        let newcoords: TypedVector2D<Integer, UniverseSpace>;
        if self.scale == other_relative_scale {
            newcoords = math::add_vec(self.coords.clone(), other.coords.clone());
        } else if self.scale >= other_relative_scale {
            let difference = (self.scale - other_relative_scale) as u32;
            newcoords = math::add_vec(
                math::scale_vec(&self.coords, &Integer::from(ZOOM_SCALE).pow(difference)),
                other.coords.clone(),
            );
        } else {
            let difference = (other_relative_scale - self.scale) as u32;
            newcoords = math::add_vec(
                math::scale_vec(&other.coords, &Integer::from(ZOOM_SCALE).pow(difference)),
                self.coords.clone(),
            );
        }

        Delta {
            zdelta: zdelta,
            scale: newscale,
            coords: newcoords,
        }
    }

    pub fn invert(&self) -> Delta {
        Delta {
            zdelta: -self.zdelta,
            scale: self.scale - self.zdelta,
            coords: TypedVector2D::new(-self.coords.x.clone(), -self.coords.y.clone()),
        }
    }

    pub fn revert(&self, other: &Delta) -> Delta {
        self.append(&other.invert())
    }

    // pub fn truncate(&self) -> Delta {
    //     if self.scale == self.zdelta {
    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: self.coords.clone(),
    //         }
    //     } else if self.scale > self.zdelta {
    //         let difference = (self.scale - self.zdelta) as u32;
    //         let newcoords =
    //             math::scale_vec(&self.coords, Integer::from(ZOOM_SCALE).pow(difference));

    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: newcoords,
    //         }
    //     } else {
    //         let difference = (self.zdelta - self.scale) as u32;
    //         let truncated_coords_x = self.coords.x.clone() >> difference;
    //         let truncated_coords_y = self.coords.y.clone() >> difference;
    //         Delta {
    //             zdelta: self.zdelta,
    //             coords: TypedVector2D::new(truncated_coords_x, truncated_coords_y),
    //         }
    //     }
    // }

    pub fn to_scaled_fvec(&self) -> TypedVector2D<f32, UniverseSpace> {
        TypedVector2D::new(
            math::scaled_bigint_to_float(&self.coords.x, self.scale),
            math::scaled_bigint_to_float(&self.coords.y, self.scale),
        )
    }

    pub fn to_scale_transform(&self) -> TypedTransform2D<f32, UniverseSpace, UniverseSpace> {
        let scale = (ZOOM_SCALE as f32).powi(self.zdelta as i32);
        TypedTransform2D::identity()
            .post_scale(scale, scale)
            .post_translate(self.to_scaled_fvec())
    }

    pub fn to_uvec(&self) -> Option<UVec> {
        assert!(self.zdelta == 0);
        assert!(self.scale >= 0);
        Some( UVec::new(
            self.coords.x.to_i32().unwrap(),
            self.coords.y.to_i32().unwrap(),
        ) * ZOOM_SCALE.pow(self.scale as u32) as i32)
    }
}

impl<U> From<TypedVector2D<f32, U>> for Delta
where U: SpaceWithLevel
{
    fn from(c: TypedVector2D<f32, U>) -> Delta {
        let int_x = (c.x * (ZOOM_SCALE as f32).pow(FRACTIONAL_DELTA_SCALE as i32)) as i32;
        let int_y = (c.y * (ZOOM_SCALE as f32).pow(FRACTIONAL_DELTA_SCALE as i32)) as i32;

        Delta {
            zdelta: U::LEVEL,
            scale: U::LEVEL - FRACTIONAL_DELTA_SCALE as i16,
            coords: TypedVector2D::new(Integer::from(int_x), Integer::from(int_y)),
        }
    }
}

impl<U> From<TypedVector2D<i32, U>> for Delta
where U: SpaceWithLevel
{
    fn from(c: TypedVector2D<i32, U>) -> Delta {
        Delta {
            zdelta: U::LEVEL,
            scale: U::LEVEL,
            coords: TypedVector2D::new(Integer::from(c.x), Integer::from(c.y)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn fractional_append_1() {
        let a = Delta {
            zdelta: 2,
            scale: 1,
            coords: TypedVector2D::new(Integer::from(-1), Integer::from(0)),
        };
        let b = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(1), Integer::from(0)),
        };

        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: 1,
                scale: 1,
                coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
            }
        );
    }

    #[test]
    fn fractional_append_2() {
        let a = Delta {
            zdelta: 1,
            scale: 0,
            coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
        };

        let b = Delta {
            zdelta: 1,
            scale: 1,
            coords: TypedVector2D::new(Integer::from(-1), Integer::from(0)),
        };
        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: 2,
                scale: 0,
                coords: TypedVector2D::new(Integer::from(-4), Integer::from(0)),
            }
        );
    }

    #[test]
    fn fractional_append_3() {
        let a = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(1), Integer::from(0)),
        };

        let b = Delta {
            zdelta: -1,
            scale: -1,
            coords: TypedVector2D::new(Integer::from(0), Integer::from(0)),
        };
        assert_eq!(
            a.append(&b),
            Delta {
                zdelta: -2,
                scale: -2,
                coords: TypedVector2D::new(Integer::from(2), Integer::from(0)),
            }
        );
    }

}
<|endoftext|>


<commit_before>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<commit_msg>Possible fix for Travis<commit_after>//! Bindings to various errno.h definitions.

///Error numbers defined in errno-base.h, with some exceptions which are marked accordingly
pub mod errno_base {

    ///Operation not permitted
    pub const EPERM: ::c_int = 1;

    ///No such file or directory
    pub const ENOENT: ::c_int = 2;

    ///No such process
    pub const ESRCH: ::c_int = 3;

    ///Interrupted system call. Oops
    pub const EINTR: ::c_int = 4;

    ///I/O error.
    pub const EIO: ::c_int = 5;

    ///No such device or address
    pub const ENXIO: ::c_int = 6;

    ///Argument list too long.
    ///
    ///You thought it was error too big, didn't you?
    pub const E2BIG: ::c_int = 7;

    ///Exec format error
    pub const ENOEXEC: ::c_int = 8;

    ///Bad file number
    pub const EBADF: ::c_int = 9;

    ///No child processes
    ///
    ///Alternatively, your name is Anthony Dinozzo Jr or Richard Castle
    pub const ECHILD: ::c_int = 10;

    ///Try again, I'm not really an error, just an annoyance
    pub const EAGAIN: ::c_int = 11;

    ///Out of memory
    pub const ENOMEM: ::c_int = 12;

    ///Permission denied!
    pub const EACCES: ::c_int = 13;

    ///Bad address
    pub const EFAULT: ::c_int = 14;

    ///Block device required but not found
    pub const ENOTBLK: ::c_int = 15;

    ///Device or resource is too busy to listen to you right now
    pub const EBUSY: ::c_int = 16;

    ///File already exists
    pub const EEXIST: ::c_int = 17;

    ///Cross-device link. Sorry, but quantum entanglement is not working in storage drives yet
    pub const EXDEV: ::c_int = 18;

    ///No such device.
    ///
    ///Alternatively, you have been robbed by a Jedi knight. "This is not the device you were searching for"
    pub const ENODEV: ::c_int = 19;

    ///That's... not a directory
    pub const ENOTDIR: ::c_int = 20;

    ///That's... not a file. That's a directory
    pub const EISDIR: ::c_int = 21;

    ///Your argument is invalid!
    pub const EINVAL: ::c_int = 22;

    ///File table overflowed
    pub const ENFILE: ::c_int = 23;

    ///Too many files are already open
    pub const EMFILE: ::c_int = 24;

    ///You are not a typewriter
    ///
    ///Does this expand to you are not a terminal? What a about a smart kettle? Or a WIFI-enabled microwave? Hey, somebody should go patent that
    pub const ENOTTTY: ::c_int = 25;

    ///Text file is too busy to listen to you right now
    pub const ETXTBSY: ::c_int = 26; //Ooooh, what are you writing?

    ///File is too large. What are you doing, downloading a car?
    pub const EFBIG: ::c_int = 27; //Okay, really, how?

    ///You don't have any (or at least enough) space left on the specified device. You might need a new hard drive.
    ///
    ///Might I suggest a SSD? They cost more but the performance gain is worth it
    pub const ENOSPC: ::c_int = 28; //I'm so sorry

    ///Illegal seek
    ///
    ///What the hell are you doing?
    pub const ESPIPE: ::c_int = 29;

    ///You're trying to write to a read-only file system.
    pub const EROFS: ::c_int = 30; //Haha, nice try

    ///Too many links exist
    pub const EMLINK: ::c_int = 31;

    ///Broken pipe
    pub const EPIPE: ::c_int = 32;

    ///Math argument is out of the function's domain
    ///
    ///??? I need more coffee to get this. Is it like trying to check if an int is NaN?
    pub const EDOM: ::c_int = 33;

    ///Math result could not be represented
    ///
    ///Stop trying to divide by ze--- ```EACCES```
    pub const ERANGE: ::c_int = 34;

}

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub mod errno_common {

    ///Resource deadlock would occur
    pub const EDEADLK: ::c_int = 35;

    ///File name is too long. (Hah!)
    pub const ENAMETOOLONG: ::c_int = 36;

    ///No record locks available
    pub const ENOLCK: ::c_int = 37;

    ///Invalid system call number
    ///
    ///This is special. Arch syscall entry code returns -ENOSYS if
    ///users try to call a syscall that doesn't exist.
    pub const ENOSYS: ::c_int = 38;

    ///Directory is not empty.
    pub const ENOTEMPTY: ::c_int = 39;

    ///Too many symbolic links encountered. This is probably an infinite loop
    ///
    ///Alternatively, you broke your computer.
    pub const ELOOP: ::c_int = 40;

    ///Operation would block. You should try again?
    pub const EWOULDBLOCK: ::c_int = self::errno_base::EAGAIN;

    ///No message of the desired type
    pub const ENOMSG: ::c_int = 42;

    ///Identifier was removed
    pub const EIDRM: ::c_int = 43;

    ///Channel number is out of acceptable range
    pub const ECHRNG: ::c_int = 44;

    ///Level 2 is not synchronized
    pub const EL2NSYNC: ::c_int = 45;

    ///Level 3 was halted
    pub const EL3HLT: ::c_int = 46;

    ///Level 3 was reset
    pub const EL3RST: ::c_int = 47;

    ///Link number is out of range
    ///
    ///How do you do this?
    pub const ELNRNG: ::c_int = 48;

    ///Protocol driver not attached
    pub const EUNATCH: ::c_int = 49;

    ///No CSI structure is available
    pub const ENOCSI: ::c_int = 50;

    ///Level 2 was halted
    pub const EL2HLT: ::c_int = 51;

    ///Invalid exchange
    pub const EBADE: ::c_int = 52;

    ///Invalid request descriptor
    pub const EBADR: ::c_int = 53;

    ///Exchange is full.
    ///
    ///I am so sorry
    pub const EXFULL: ::c_int = 54;

    ///No anode is available
    pub const ENOANO: ::c_int = 55;

    ///Invalid request code
    pub const EBADRQC: ::c_int = 56;

    ///Invalid slot
    pub const EBADSLT: ::c_int = 57;

    ///A deadlock would occur, again
    pub const EDEADLOCK: ::c_int = EDEADLK;

    ///Bad font file format
    pub const EBFONT: ::c_int = 59;

    ///Device is not a stream
    pub const ENOSTR: ::c_int = 60;

    ///No data is available
    pub const ENODATA: ::c_int = 61;

    ///Timer expired
    pub const ETIME: ::c_int = 62;

    ///Out of streams resources
    ///
    ///Should this be stream's? I'm not sure about the context. Is it the resources of the stream, or resources of the system's supply of streams?
    pub const ENOSR: ::c_int = 63;

    ///Requested machine was not on the network
    pub const ENONET: ::c_int = 64;

    ///Package is not installed
    pub const ENOPKG: ::c_int = 65;

    ///Object is remote when it is required to be local
    pub const EREMOTE: ::c_int = 66;

    ///Link has been severed
    pub const ENOLINK: ::c_int = 67;

    ///Error in advertising
    pub const EADV: ::c_int = 68;

    ///Srmount error
    pub const ESRMNT: ::c_int = 69;

    ///Communications error on send
    pub const ECOMM: ::c_int = 70;

    ///Protocol error
    pub const EPROTO: ::c_int = 71;

    ///A multihop was attempted
    pub const EMULTIHOP: ::c_int = 72;

    ///A RFS-specific error occurred
    pub const EDOTDOT: ::c_int = 73;

    ///Message is not a data message
    pub const EBADMASG: ::c_int = 74;

    ///Value is too large for the defined data type
    pub const EOVERFLOW: ::c_int = 75;

    ///Name is not unique on the network
    ///
    ///No, BILLY_TABLES, you can't have ten computers called '; DROP TABLE users' for "backup purposes"
    pub const ENOTUNIQ: ::c_int = 76;

    ///File descriptor is in a bad state
    ///
    ///Huh. I haven't seen this before
    pub const EBADFD: ::c_int = 77;

    ///The remote address changed.
    ///
    ///How does this happen? A change from wifi to 4g, etc?
    pub const EREMCHG: ::c_int = 78;

    ///Can not access a needed shared library
    ///
    ///Thankfully, with Cargo, this shouldn't happen :)
    pub const ELIBACC: ::c_int = 79;

    ///Attempted to access a shared library, only to find out it was corrupted
    ///
    ///WELL, FUCK.
    pub const ELIBBAD: ::c_int = 80;

    ///.lib section in a.out is corrupted
    pub const ELIBSCN: ::c_int = 81;

    ///Attempting to link in too many shared libraries
    ///
    ///Are... are you okay?
    pub const ELIBMAX: ::c_int = 82;

    ///Cannot exec a shared library directly
    pub const ELIBEXEC: ::c_int = 83;

    ///Illegal byte sequence
    ///
    ///I don't know what the hell you are doing, but you're probably doing it wrong
    pub const EILSEQ: ::c_int = 84;

    ///Interrupted system call, you should restart it
    ///
    ///Well, that's easy
    pub const ERESTART: ::c_int = 85;

    ///Streams pipe error
    pub const ESTRPIPE: ::c_int = 86;

    ///Too many users
    ///
    ///*Points finger and laughs*
    pub const EUSERS: ::c_int = 87;

    ///Socket operation attempted on an object that is not a socket
    pub const ENOTSOCK: ::c_int = 88;

    ///Destination address required
    pub const EDESTADDRREQ: ::c_int = 89;

    ///Message is too long
    pub const EMSGSIZE: ::c_int = 90;

    ///Protocol type is wrong for this socket
    pub const EPROTOTYPE: ::c_int = 91;

    ///Protocol is not available
    pub const ENOPROTOOPT: ::c_int = 92;

    ///Protocol is not supported
    pub const EPROTONOSUPPORT: ::c_int = 93;

    ///Socket type is not supported
    ///
    ///What?
    pub const ESOCKTNOSUPPORT: ::c_int = 94;

    ///Operation not supported on transport endpoint
    pub const EOPNOTSUPP: ::c_int = 95;

    ///Protocol family is not supported
    pub const EPFNOSUPPORT: ::c_int = 96;

    ///Address family is not supported by this protocol
    pub const EAFNOSUPPORT: ::c_int = 97;

    ///Address is already in use
    pub const EADDRINUSE: ::c_int = 98;

    ///Cannot assign the requested address
    pub const EADDRNOTAVAIL: ::c_int = 99;

    ///Network is down
    pub const ENETDOWN: ::c_int = 100;

    ///Network is unreachable :(
    pub const ENETUNREACH: ::c_int = 101;

    ///Network dropped connection because of a reset
    pub const ENETRESET: ::c_int = 102;

    ///Software caused the connection to abort
    pub const ECONNABORTED: ::c_int = 103;

    ///Connection was reset by a peer
    pub const ECONNRESET: ::c_int = 104;

    ///No buffer space is available
    pub const ENOBUFS: ::c_int = 105;

    ///Transport endpoint is already connected
    pub const EISCONN: ::c_int = 106;

    ///Transport endpoint is not connected
    pub const ENOTCONN: ::c_int = 107;

    ///Cannot send after the transport endpoint is shut down
    pub const ESHUTDOWN: ::c_int = 108;

    ///Too many references; Cannot splice
    pub const ETOOMANYREFS: ::c_int = 109;

    ///Connection timed out
    pub const ETIMEDOUT: ::c_int = 110;

    ///Connection was refused
    pub const ECONNREFUSED: ::c_int = 111;

    ///The host is down! D:
    pub const EHOSTDOWN: ::c_int = 112;

    ///There is no usable route to the host
    pub const EHOSTUNREACH: ::c_int = 113;

    ///Operation is already in progress. Be patient!
    pub const EALREADY: ::c_int = 114;

    ///Operation is in progress
    pub const EINPROGRESS: ::c_int = 115;

    ///The file handle is stale. Ew!
    pub const ESTALE: ::c_int = 116;

    ///The structure needs cleaning
    pub const EUCLEAN: ::c_int = 117;

    ///This is not a XENIX named type file
    pub const ENOTNAM: ::c_int = 118;

    ///No XENIX semaphores are available
    pub const ENAVAIL: ::c_int = 119;

    ///This is a named type file
    pub const EISNAM: ::c_int = 120;

    ///A remote I/O error occurred
    pub const EREMOTEIO: ::c_int = 121;

    ///You exceeded your quote
    pub const EDQUOT: ::c_int = 122;

    ///No medium was found
    pub const ENOMEDIUM: ::c_int = 123;

    ///You're using the wrong medium type
    pub const EMEDIUMTYPE: ::c_int = 124;

    ///The operation was cancelled
    pub const ECANCELED: ::c_int = 125;

    ///The required key is not available
    pub const ENOKEY: ::c_int = 126;

    ///The key you're using has expired
    pub const EKEYEXPIRED: ::c_int = 127;

    ///The key you're using has been revoked
    pub const EKEYREVOKED: ::c_int = 128;

    ///The key you're using was rejected by the service you're trying to access
    pub const EKEYREJECTED: ::c_int = 129;

    ///Your owner died.
    ///
    ///Dobby is a free computer!
    ///
    ///Just kidding. Your mutex's owner died. Dobby is still a slave
    pub const EOWNERDEAD: ::c_int = 130;

    ///The state of your mutex is not recoverable
    pub const ENOTRECOVERABLE: ::c_int = 131;

    ///Operation is not possible due to RF-kill
    pub const ERFKILL: ::c_int = 132;

    ///The memory page has a hardware error
    pub const EHWPOISON: ::c_int = 133;

}

pub use self::errno_base::*;

#[cfg(not(any(target_arch = "alpha", target_arch = "mips", target_arch = "parisc", target_arch = "sparc")))]
pub use self::errno_common::*;<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;

use ::Url;

/// The Errors that may occur when processing a `Request`.
#[derive(Debug)]
pub struct Error {
    kind: Kind,
    url: Option<Url>,
}

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = ::std::result::Result<T, Error>;

impl Error {
    /// Returns a possible URL related to this error.
    #[inline]
    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    /// Returns a reference to the internal error, if available.
    ///
    /// The `'static` bounds allows using `downcast_ref` to check the
    /// details of the error.
    #[inline]
    pub fn get_ref(&self) -> Option<&(StdError + 'static)> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop => None,
        }
    }

    /// Returns true if the error is related to HTTP.
    #[inline]
    pub fn is_http(&self) -> bool {
        match self.kind {
            Kind::Http(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is serialization related.
    #[inline]
    pub fn is_serialization(&self) -> bool {
        match self.kind {
            Kind::Json(_) |
            Kind::UrlEncoded(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    #[inline]
    pub fn is_redirect(&self) -> bool {
        match self.kind {
            Kind::TooManyRedirects |
            Kind::RedirectLoop => true,
            _ => false,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref url) = self.url {
            try!(fmt::Display::fmt(url, f));
            try!(f.write_str(": "));
        }
        match self.kind {
            Kind::Http(ref e) => fmt::Display::fmt(e, f),
            Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f),
            Kind::Json(ref e) => fmt::Display::fmt(e, f),
            Kind::TooManyRedirects => f.write_str("Too many redirects"),
            Kind::RedirectLoop => f.write_str("Infinite redirect loop"),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Http(ref e) => e.description(),
            Kind::UrlEncoded(ref e) => e.description(),
            Kind::Json(ref e) => e.description(),
            Kind::TooManyRedirects => "Too many redirects",
            Kind::RedirectLoop => "Infinite redirect loop",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop => None,
        }
    }
}

// pub(crate)

#[derive(Debug)]
pub enum Kind {
    Http(::hyper::Error),
    UrlEncoded(::serde_urlencoded::ser::Error),
    Json(::serde_json::Error),
    TooManyRedirects,
    RedirectLoop,
}

impl From<::hyper::Error> for Kind {
    #[inline]
    fn from(err: ::hyper::Error) -> Kind {
        Kind::Http(err)
    }
}

impl From<::url::ParseError> for Kind {
    #[inline]
    fn from(err: ::url::ParseError) -> Kind {
        Kind::Http(::hyper::Error::Uri(err))
    }
}

impl From<::serde_urlencoded::ser::Error> for Kind {
    #[inline]
    fn from(err: ::serde_urlencoded::ser::Error) -> Kind {
        Kind::UrlEncoded(err)
    }
}

impl From<::serde_json::Error> for Kind {
    #[inline]
    fn from(err: ::serde_json::Error) -> Kind {
        Kind::Json(err)
    }
}

pub struct InternalFrom<T>(pub T, pub Option<Url>);

impl From<InternalFrom<Error>> for Error {
    #[inline]
    fn from(other: InternalFrom<Error>) -> Error {
        other.0
    }
}

impl<T> From<InternalFrom<T>> for Error
where T: Into<Kind> {
    #[inline]
    fn from(other: InternalFrom<T>) -> Error {
         Error {
            kind: other.0.into(),
            url: other.1,
        }
    }
}

#[inline]
pub fn from<T>(err: T) -> Error
where T: Into<Kind> {
    InternalFrom(err, None).into()
}

#[inline]
pub fn loop_detected(url: Url) -> Error {
    Error {
        kind: Kind::RedirectLoop,
        url: Some(url),
    }
}

#[inline]
pub fn too_many_redirects(url: Url) -> Error {
    Error {
        kind: Kind::TooManyRedirects,
        url: Some(url),
    }
}

#[test]
fn test_error_get_ref_downcasts() {
    let err: Error = from(::hyper::Error::Status);
    let cause = err.get_ref().unwrap()
        .downcast_ref::<::hyper::Error>().unwrap();

    match cause {
        &::hyper::Error::Status => (),
        _ => panic!("unexpected downcast: {:?}", cause)
    }
}
<commit_msg>remove unintended export of private try_ macro<commit_after>use std::error::Error as StdError;
use std::fmt;

use ::Url;

/// The Errors that may occur when processing a `Request`.
#[derive(Debug)]
pub struct Error {
    kind: Kind,
    url: Option<Url>,
}

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = ::std::result::Result<T, Error>;

impl Error {
    /// Returns a possible URL related to this error.
    #[inline]
    pub fn url(&self) -> Option<&Url> {
        self.url.as_ref()
    }

    /// Returns a reference to the internal error, if available.
    ///
    /// The `'static` bounds allows using `downcast_ref` to check the
    /// details of the error.
    #[inline]
    pub fn get_ref(&self) -> Option<&(StdError + 'static)> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop => None,
        }
    }

    /// Returns true if the error is related to HTTP.
    #[inline]
    pub fn is_http(&self) -> bool {
        match self.kind {
            Kind::Http(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is serialization related.
    #[inline]
    pub fn is_serialization(&self) -> bool {
        match self.kind {
            Kind::Json(_) |
            Kind::UrlEncoded(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    #[inline]
    pub fn is_redirect(&self) -> bool {
        match self.kind {
            Kind::TooManyRedirects |
            Kind::RedirectLoop => true,
            _ => false,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref url) = self.url {
            try!(fmt::Display::fmt(url, f));
            try!(f.write_str(": "));
        }
        match self.kind {
            Kind::Http(ref e) => fmt::Display::fmt(e, f),
            Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f),
            Kind::Json(ref e) => fmt::Display::fmt(e, f),
            Kind::TooManyRedirects => f.write_str("Too many redirects"),
            Kind::RedirectLoop => f.write_str("Infinite redirect loop"),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Http(ref e) => e.description(),
            Kind::UrlEncoded(ref e) => e.description(),
            Kind::Json(ref e) => e.description(),
            Kind::TooManyRedirects => "Too many redirects",
            Kind::RedirectLoop => "Infinite redirect loop",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Http(ref e) => Some(e),
            Kind::UrlEncoded(ref e) => Some(e),
            Kind::Json(ref e) => Some(e),
            Kind::TooManyRedirects |
            Kind::RedirectLoop => None,
        }
    }
}

// pub(crate)

#[derive(Debug)]
pub enum Kind {
    Http(::hyper::Error),
    UrlEncoded(::serde_urlencoded::ser::Error),
    Json(::serde_json::Error),
    TooManyRedirects,
    RedirectLoop,
}

impl From<::hyper::Error> for Kind {
    #[inline]
    fn from(err: ::hyper::Error) -> Kind {
        Kind::Http(err)
    }
}

impl From<::url::ParseError> for Kind {
    #[inline]
    fn from(err: ::url::ParseError) -> Kind {
        Kind::Http(::hyper::Error::Uri(err))
    }
}

impl From<::serde_urlencoded::ser::Error> for Kind {
    #[inline]
    fn from(err: ::serde_urlencoded::ser::Error) -> Kind {
        Kind::UrlEncoded(err)
    }
}

impl From<::serde_json::Error> for Kind {
    #[inline]
    fn from(err: ::serde_json::Error) -> Kind {
        Kind::Json(err)
    }
}

pub struct InternalFrom<T>(pub T, pub Option<Url>);

impl From<InternalFrom<Error>> for Error {
    #[inline]
    fn from(other: InternalFrom<Error>) -> Error {
        other.0
    }
}

impl<T> From<InternalFrom<T>> for Error
where T: Into<Kind> {
    #[inline]
    fn from(other: InternalFrom<T>) -> Error {
         Error {
            kind: other.0.into(),
            url: other.1,
        }
    }
}

#[inline]
pub fn from<T>(err: T) -> Error
where T: Into<Kind> {
    InternalFrom(err, None).into()
}

#[inline]
pub fn loop_detected(url: Url) -> Error {
    Error {
        kind: Kind::RedirectLoop,
        url: Some(url),
    }
}

#[inline]
pub fn too_many_redirects(url: Url) -> Error {
    Error {
        kind: Kind::TooManyRedirects,
        url: Some(url),
    }
}

macro_rules! try_ {
    ($e:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::Error::from(::error::InternalFrom(err, None)));
            }
        }
    );
    ($e:expr, $url:expr) => (
        match $e {
            Ok(v) => v,
            Err(err) => {
                return Err(::Error::from(::error::InternalFrom(err, Some($url.clone()))));
            }
        }
    )
}

#[test]
fn test_error_get_ref_downcasts() {
    let err: Error = from(::hyper::Error::Status);
    let cause = err.get_ref().unwrap()
        .downcast_ref::<::hyper::Error>().unwrap();

    match cause {
        &::hyper::Error::Status => (),
        _ => panic!("unexpected downcast: {:?}", cause)
    }
}
<|endoftext|>