<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) NPROCESSORS nprocs numstr threadstr sysconf

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use std::env;

#[cfg(target_os = "linux")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
#[cfg(target_vendor = "apple")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = libc::_SC_NPROCESSORS_CONF;
#[cfg(target_os = "freebsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 57;
#[cfg(target_os = "netbsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 1001;

static OPT_ALL: &str = "all";
static OPT_IGNORE: &str = "ignore";

static ABOUT: &str = "Print the number of cores available to the current process.";

fn usage() -> String {
    format!("{0} [OPTIONS]...", uucore::execution_phrase())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let mut ignore = match matches.value_of(OPT_IGNORE) {
        Some(numstr) => match numstr.parse() {
            Ok(num) => num,
            Err(e) => {
                show_error!("\"{}\" is not a valid number: {}", numstr, e);
                return 1;
            }
        },
        None => 0,
    };

    if !matches.is_present(OPT_ALL) {
        // OMP_NUM_THREADS doesn't have an impact on --all
        ignore += match env::var("OMP_NUM_THREADS") {
            Ok(threadstr) => threadstr.parse().unwrap_or(0),
            Err(_) => 0,
        };
    }

    let mut cores = if matches.is_present(OPT_ALL) {
        num_cpus_all()
    } else {
        num_cpus::get()
    };

    if cores <= ignore {
        cores = 1;
    } else {
        cores -= ignore;
    }
    println!("{}", cores);
    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(OPT_ALL)
                .short("")
                .long(OPT_ALL)
                .help("print the number of cores available to the system"),
        )
        .arg(
            Arg::with_name(OPT_IGNORE)
                .short("")
                .long(OPT_IGNORE)
                .takes_value(true)
                .help("ignore up to N cores"),
        )
}

#[cfg(any(
    target_os = "linux",
    target_vendor = "apple",
    target_os = "freebsd",
    target_os = "netbsd"
))]
fn num_cpus_all() -> usize {
    let nprocs = unsafe { libc::sysconf(_SC_NPROCESSORS_CONF) };
    if nprocs == 1 {
        // In some situation, /proc and /sys are not mounted, and sysconf returns 1.
        // However, we want to guarantee that `nproc --all` >= `nproc`.
        num_cpus::get()
    } else if nprocs > 0 {
        nprocs as usize
    } else {
        1
    }
}

// Other platforms (e.g., windows), num_cpus::get() directly.
#[cfg(not(any(
    target_os = "linux",
    target_vendor = "apple",
    target_os = "freebsd",
    target_os = "netbsd"
)))]
fn num_cpus_all() -> usize {
    num_cpus::get()
}
<commit_msg>nproc: use UResult<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) NPROCESSORS nprocs numstr threadstr sysconf

use clap::{crate_version, App, Arg};
use std::env;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};

#[cfg(target_os = "linux")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
#[cfg(target_vendor = "apple")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = libc::_SC_NPROCESSORS_CONF;
#[cfg(target_os = "freebsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 57;
#[cfg(target_os = "netbsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 1001;

static OPT_ALL: &str = "all";
static OPT_IGNORE: &str = "ignore";

static ABOUT: &str = "Print the number of cores available to the current process.";

fn usage() -> String {
    format!("{0} [OPTIONS]...", uucore::execution_phrase())
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let mut ignore = match matches.value_of(OPT_IGNORE) {
        Some(numstr) => match numstr.parse() {
            Ok(num) => num,
            Err(e) => {
                return Err(USimpleError::new(
                    1,
                    format!("{} is not a valid number: {}", numstr.quote(), e),
                ));
            }
        },
        None => 0,
    };

    if !matches.is_present(OPT_ALL) {
        // OMP_NUM_THREADS doesn't have an impact on --all
        ignore += match env::var("OMP_NUM_THREADS") {
            Ok(threadstr) => threadstr.parse().unwrap_or(0),
            Err(_) => 0,
        };
    }

    let mut cores = if matches.is_present(OPT_ALL) {
        num_cpus_all()
    } else {
        num_cpus::get()
    };

    if cores <= ignore {
        cores = 1;
    } else {
        cores -= ignore;
    }
    println!("{}", cores);
    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(OPT_ALL)
                .short("")
                .long(OPT_ALL)
                .help("print the number of cores available to the system"),
        )
        .arg(
            Arg::with_name(OPT_IGNORE)
                .short("")
                .long(OPT_IGNORE)
                .takes_value(true)
                .help("ignore up to N cores"),
        )
}

#[cfg(any(
    target_os = "linux",
    target_vendor = "apple",
    target_os = "freebsd",
    target_os = "netbsd"
))]
fn num_cpus_all() -> usize {
    let nprocs = unsafe { libc::sysconf(_SC_NPROCESSORS_CONF) };
    if nprocs == 1 {
        // In some situation, /proc and /sys are not mounted, and sysconf returns 1.
        // However, we want to guarantee that `nproc --all` >= `nproc`.
        num_cpus::get()
    } else if nprocs > 0 {
        nprocs as usize
    } else {
        1
    }
}

// Other platforms (e.g., windows), num_cpus::get() directly.
#[cfg(not(any(
    target_os = "linux",
    target_vendor = "apple",
    target_os = "freebsd",
    target_os = "netbsd"
)))]
fn num_cpus_all() -> usize {
    num_cpus::get()
}
<|endoftext|>


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

use super::scope::Stack;
use super::Composite::{List, Tuple};
use super::Op::{
    Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, InitList, InitThunk,
    InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Return, SelectJump, Sub, Sym, Val,
};
use super::Primitive::{Bool, Float, Int, Str};
use super::Value::{C, P};
use super::VM;

macro_rules! assert_cases {
    (__impl__ $cases:expr) => {
        for case in $cases.drain(0..) {
            let mut vm = VM::new(&case.0);
            vm.run().unwrap();
            assert_eq!(dbg!(vm.pop()).unwrap(), case.1);
        }
    };

    (($input:expr, $result:expr), $($tok:tt)*) => {
        assert_cases!(__impl__ vec![($input, $result), $($tok)*])
    };

    ($($input:expr => $result:expr, )* ) => {
        assert_cases!(
            $(($input, $result),)*
        )
    }
}

#[test]
fn test_math_ops() {
    assert_cases!(
        // 1+1;
        vec![Val(Int(1)), Val(Int(1)), Add] => P(Int(2)),
        // 1-1;
        vec![Val(Int(1)), Val(Int(1)), Sub] => P(Int(0)),
        // 2*2;
        vec![Val(Int(2)), Val(Int(2)), Mul] => P(Int(4)),
        // 6/3;
        vec![Val(Int(2)), Val(Int(6)), Div] => P(Int(3)),
        // 1.0+1.0;
        vec![Val(Float(1.0)), Val(Float(1.0)), Add] => P(Float(2.0)),
        // 1.0-1.0;
        vec![Val(Float(1.0)), Val(Float(1.0)), Sub] => P(Float(0.0)),
        // 2.0*2.0;
       vec![Val(Float(2.0)), Val(Float(2.0)), Mul] => P(Float(4.0)),
        // 6.0/3.0;
        vec![Val(Float(2.0)), Val(Float(6.0)), Div] => P(Float(3.0)),
        // string concatenation
        vec![Val(Str("bar".to_owned())), Val(Str("foo".to_owned())), Add] => P(Str("foobar".to_owned())),
        // Composite operations
        vec![
            Val(Int(1)),
            Val(Int(1)),
            Add, // 1 + 1
            Val(Int(1)),
            Add, // 2 + 1
            Val(Int(1)),
            Add, // 3 + 1
        ] => P(Int(4)),
    );
}

#[test]
fn test_bind_op() {
    let mut cases = vec![(
        vec![Sym("foo".to_owned()), Val(Int(1)), Bind],
        ("foo", P(Int(1))),
        vec![Sym("foo".to_owned()), Val(Int(1)), Val(Int(1)), Add, Bind],
        ("foo", P(Int(2))),
    )];

    for case in cases.drain(0..) {
        let mut vm = VM::new(&case.0);
        vm.run().unwrap();
        let (name, result) = case.1;
        let v = vm.get_binding(name).unwrap();
        assert_eq!(&result, v);
    }
}

#[test]
fn test_list_ops() {
    assert_cases!(
        vec![InitList] => C(List(Vec::new())),
        vec![InitList, Val(Int(1)), Element] => C(List(vec![P(Int(1))])),
        vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element] => C(List(vec![P(Int(2)), P(Int(1))])),
        vec![
            InitList,
            Val(Int(1)),
            Element,
            Val(Int(1)),
            Val(Int(1)),
            Add,
            Element,
        ] => C(List(vec![P(Int(1)), P(Int(2))])),
    );
}

#[test]
fn test_tuple_ops() {
    assert_cases!(
        vec![InitTuple] => C(Tuple(Vec::new())),
        vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), Field] => C(Tuple(vec![("foo".to_owned(), P(Int(1)))])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("quux".to_owned())),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(1))),
        ])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("quux".to_owned())),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("ux".to_owned())),
            Val(Str("qu".to_owned())),
            Add,
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
        vec![
            InitTuple, // Override tuple
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
            InitTuple, // Target tuple
            Sym("bar".to_owned()),
            Val(Str("ux".to_owned())),
            Val(Str("qu".to_owned())),
            Add,
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Cp, // Do the tuple copy operation
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
    );
}

#[test]
fn test_jump_ops() {
    assert_cases!(
        vec![Jump(1), Val(Int(1)), Noop, Val(Int(1))] => P(Int(1)),
    );
}

#[test]
fn test_equality_ops() {
    assert_cases![
        vec![
            Val(Str("foo".to_owned())),
            Val(Str("foo".to_owned())),
            Equal,
        ] => P(Bool(true)),
        vec![
            Val(Str("bar".to_owned())),
            Val(Str("foo".to_owned())),
            Equal,
        ] => P(Bool(false)),
        vec![Val(Int(1)), Val(Int(1)), Equal] => P(Bool(true)),
        vec![Val(Int(1)), Val(Int(2)), Equal] => P(Bool(false)),
        vec![Val(Bool(true)), Val(Bool(true)), Equal] => P(Bool(true)),
        vec![Val(Bool(false)), Val(Bool(false)), Equal] => P(Bool(true)),
        vec![Val(Bool(true)), Val(Bool(false)), Equal] => P(Bool(false)),
        vec![
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Equal,
        ] => P(Bool(true)),
        vec![
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            InitTuple,
            Val(Str("bar".to_owned())),
            Val(Int(1)),
            Field,
            Equal,
        ] => P(Bool(false)),
        vec![
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            Equal,
        ] => P(Bool(true)),
        vec![
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            InitList,
            Val(Str("bar".to_owned())),
            Element,
            Equal,
        ] => P(Bool(false)),
    ];
}

#[test]
fn test_conditional_jump_ops() {
    assert_cases![
        vec![
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Bool(true)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(2)),
        vec![
            Val(Bool(true)),
            JumpIfTrue(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
        vec![
            Val(Int(1)),
            Val(Int(1)),
            Equal,
            JumpIfTrue(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
        vec![
            Val(Int(1)),
            Val(Int(2)),
            Equal,
            JumpIfFalse(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
    ];
}

#[test]
fn test_function_definition_and_call() {
    assert_cases![
        vec![
            Sym("f".to_owned()),     // 0
            InitList,                // 1
            Sym("arg".to_owned()),   // 2
            Element,                 // 3
            Func(6),                 // 4
            DeRef("arg".to_owned()), // 5
            Return,                  // 6
            Bind,                    // 7
            Val(Int(1)),             // 8
            DeRef("f".to_owned()),   // 9
            FCall,                   // 10
        ] => P(Int(1)),
        vec![
            Sym("closed".to_owned()),   // 0
            Val(Int(1)),                // 1
            Bind,                       // 2
            Sym("f".to_owned()),        // 3
            InitList,                   // 4
            Sym("arg".to_owned()),      // 5
            Element,                    // 6
            Func(11),                   // 7
            DeRef("arg".to_owned()),    // 8
            DeRef("closed".to_owned()), // 9
            Add,                        // 10
            Return,                     // 11
            Bind,                       // 12
            Val(Int(1)),                // 13
            DeRef("f".to_owned()),      // 14
            FCall,                      // 16
        ] => P(Int(2)),
    ];
}

#[test]
fn test_module_call() {
    assert_cases![
        vec![
            InitTuple,               // 0 // override tuple
            Sym("one".to_owned()),   // 1
            Val(Int(11)),            // 2
            Field,                   // 3
            Sym("m".to_owned()),     // 4 // binding name for module
            InitTuple,               // 5 // Module tuple bindings
            Sym("one".to_owned()),   // 6
            Val(Int(1)),             // 7
            Field,                   // 8
            Sym("two".to_owned()),   // 9
            Val(Int(2)),             // 10
            Field,                   // 11
            Module(17),              // 12 // Module definition
            Bind,                    // 13
            Sym("foo".to_owned()),   // 14
            DeRef("mod".to_owned()), // 15
            Bind,                    // 16 // bind mod tuple to foo
            Return,                  // 17 // end the module
            Bind,                    // 18 // bind module to the binding name
            DeRef("m".to_owned()),   // 19
            Cp,                      // 20
        ] => C(Tuple(vec![(
            "foo".to_owned(),
            C(Tuple(vec![
                ("one".to_owned(), P(Int(11))),
                ("two".to_owned(), P(Int(2))),
            ])),
        )])),
        vec![
            InitTuple,               // 0 // override tuple
            Sym("one".to_owned()),   // 1
            Val(Int(11)),            // 2
            Field,                   // 3
            Sym("m".to_owned()),     // 4 // binding name for module
            InitTuple,               // 5 // Module tuple bindings
            Sym("one".to_owned()),   // 6
            Val(Int(1)),             // 7
            Field,                   // 8
            Sym("two".to_owned()),   // 9
            Val(Int(2)),             // 10
            Field,                   // 11
            InitThunk(2),            // 12 // Module Return expression
            Val(Int(1)),             // 13
            Return,                  // 14
            Module(20),              // 15 // Module definition
            Bind,                    // 16
            Sym("foo".to_owned()),   // 17
            DeRef("mod".to_owned()), // 18
            Bind,                    // 19 // bind mod tuple to foo
            Return,                  // 20 // end the module
            Bind,                    // 21 // bind module to the binding name
            DeRef("m".to_owned()),   // 22
            Cp,                      // 23
        ] => P(Int(1)),
    ];
}

#[test]
fn test_select_short_circuit() {
    assert_cases![
        vec![
            Sym("field".to_owned()),              // 0 // search field
            Sym("not_field".to_owned()),          // 1 // first field to compare
            SelectJump(2),                        // 2
            Val(Str("not our value".to_owned())), // 3 // expression for first field
            Jump(4),                              // 4
            Sym("field".to_owned()),              // 5 // second field to compare
            SelectJump(2),                        // 6
            Val(Int(1)),                          // 7 // expression for second field
            Jump(1),                              // 8
            Bang,                                 // 9 // default case
        ] => P(Int(1)),
    ];
}

#[test]
fn test_scope_stacks() {
    let mut stack = Stack::new();
    stack.add("one".to_owned(), P(Int(1)));
    let mut val = stack.get("one").unwrap();
    assert_eq!(val, &P(Int(1)));
    stack.push();
    assert!(stack.get("one").is_none());
    stack.to_open();
    val = stack.get("one").unwrap();
    assert_eq!(val, &P(Int(1)));
}
<commit_msg>DEV: Default test case for select expressions.<commit_after>// Copyright 2019 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::scope::Stack;
use super::Composite::{List, Tuple};
use super::Op::{
    Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, InitList, InitThunk,
    InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return, SelectJump, Sub, Sym,
    Val,
};
use super::Primitive::{Bool, Float, Int, Str};
use super::Value::{C, P};
use super::VM;

macro_rules! assert_cases {
    (__impl__ $cases:expr) => {
        for case in $cases.drain(0..) {
            let mut vm = VM::new(&case.0);
            vm.run().unwrap();
            assert_eq!(dbg!(vm.pop()).unwrap(), case.1);
        }
    };

    (($input:expr, $result:expr), $($tok:tt)*) => {
        assert_cases!(__impl__ vec![($input, $result), $($tok)*])
    };

    ($($input:expr => $result:expr, )* ) => {
        assert_cases!(
            $(($input, $result),)*
        )
    }
}

#[test]
fn test_math_ops() {
    assert_cases!(
        // 1+1;
        vec![Val(Int(1)), Val(Int(1)), Add] => P(Int(2)),
        // 1-1;
        vec![Val(Int(1)), Val(Int(1)), Sub] => P(Int(0)),
        // 2*2;
        vec![Val(Int(2)), Val(Int(2)), Mul] => P(Int(4)),
        // 6/3;
        vec![Val(Int(2)), Val(Int(6)), Div] => P(Int(3)),
        // 1.0+1.0;
        vec![Val(Float(1.0)), Val(Float(1.0)), Add] => P(Float(2.0)),
        // 1.0-1.0;
        vec![Val(Float(1.0)), Val(Float(1.0)), Sub] => P(Float(0.0)),
        // 2.0*2.0;
       vec![Val(Float(2.0)), Val(Float(2.0)), Mul] => P(Float(4.0)),
        // 6.0/3.0;
        vec![Val(Float(2.0)), Val(Float(6.0)), Div] => P(Float(3.0)),
        // string concatenation
        vec![Val(Str("bar".to_owned())), Val(Str("foo".to_owned())), Add] => P(Str("foobar".to_owned())),
        // Composite operations
        vec![
            Val(Int(1)),
            Val(Int(1)),
            Add, // 1 + 1
            Val(Int(1)),
            Add, // 2 + 1
            Val(Int(1)),
            Add, // 3 + 1
        ] => P(Int(4)),
    );
}

#[test]
fn test_bind_op() {
    let mut cases = vec![(
        vec![Sym("foo".to_owned()), Val(Int(1)), Bind],
        ("foo", P(Int(1))),
        vec![Sym("foo".to_owned()), Val(Int(1)), Val(Int(1)), Add, Bind],
        ("foo", P(Int(2))),
    )];

    for case in cases.drain(0..) {
        let mut vm = VM::new(&case.0);
        vm.run().unwrap();
        let (name, result) = case.1;
        let v = vm.get_binding(name).unwrap();
        assert_eq!(&result, v);
    }
}

#[test]
fn test_list_ops() {
    assert_cases!(
        vec![InitList] => C(List(Vec::new())),
        vec![InitList, Val(Int(1)), Element] => C(List(vec![P(Int(1))])),
        vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element] => C(List(vec![P(Int(2)), P(Int(1))])),
        vec![
            InitList,
            Val(Int(1)),
            Element,
            Val(Int(1)),
            Val(Int(1)),
            Add,
            Element,
        ] => C(List(vec![P(Int(1)), P(Int(2))])),
    );
}

#[test]
fn test_tuple_ops() {
    assert_cases!(
        vec![InitTuple] => C(Tuple(Vec::new())),
        vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), Field] => C(Tuple(vec![("foo".to_owned(), P(Int(1)))])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("quux".to_owned())),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(1))),
        ])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("quux".to_owned())),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
        vec![
            InitTuple,
            Sym("bar".to_owned()),
            Val(Str("ux".to_owned())),
            Val(Str("qu".to_owned())),
            Add,
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
        vec![
            InitTuple, // Override tuple
            Val(Str("foo".to_owned())),
            Val(Int(2)),
            Field,
            InitTuple, // Target tuple
            Sym("bar".to_owned()),
            Val(Str("ux".to_owned())),
            Val(Str("qu".to_owned())),
            Add,
            Field,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Cp, // Do the tuple copy operation
        ] => C(Tuple(vec![
            ("bar".to_owned(), P(Str("quux".to_owned()))),
            ("foo".to_owned(), P(Int(2))),
        ])),
    );
}

#[test]
fn test_jump_ops() {
    assert_cases!(
        vec![Jump(1), Val(Int(1)), Noop, Val(Int(1))] => P(Int(1)),
    );
}

#[test]
fn test_equality_ops() {
    assert_cases![
        vec![
            Val(Str("foo".to_owned())),
            Val(Str("foo".to_owned())),
            Equal,
        ] => P(Bool(true)),
        vec![
            Val(Str("bar".to_owned())),
            Val(Str("foo".to_owned())),
            Equal,
        ] => P(Bool(false)),
        vec![Val(Int(1)), Val(Int(1)), Equal] => P(Bool(true)),
        vec![Val(Int(1)), Val(Int(2)), Equal] => P(Bool(false)),
        vec![Val(Bool(true)), Val(Bool(true)), Equal] => P(Bool(true)),
        vec![Val(Bool(false)), Val(Bool(false)), Equal] => P(Bool(true)),
        vec![Val(Bool(true)), Val(Bool(false)), Equal] => P(Bool(false)),
        vec![
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            Equal,
        ] => P(Bool(true)),
        vec![
            InitTuple,
            Val(Str("foo".to_owned())),
            Val(Int(1)),
            Field,
            InitTuple,
            Val(Str("bar".to_owned())),
            Val(Int(1)),
            Field,
            Equal,
        ] => P(Bool(false)),
        vec![
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            Equal,
        ] => P(Bool(true)),
        vec![
            InitList,
            Val(Str("foo".to_owned())),
            Element,
            InitList,
            Val(Str("bar".to_owned())),
            Element,
            Equal,
        ] => P(Bool(false)),
    ];
}

#[test]
fn test_conditional_jump_ops() {
    assert_cases![
        vec![
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Bool(true)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(2)),
        vec![
            Val(Bool(true)),
            JumpIfTrue(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
        vec![
            Val(Int(1)),
            Val(Int(1)),
            Equal,
            JumpIfTrue(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
        vec![
            Val(Int(1)),
            Val(Int(2)),
            Equal,
            JumpIfFalse(2),
            Val(Bool(false)),
            JumpIfTrue(2),
            Val(Int(1)),
            Jump(1),
            Val(Int(2)),
            Noop,
        ] => P(Int(1)),
    ];
}

#[test]
fn test_function_definition_and_call() {
    assert_cases![
        vec![
            Sym("f".to_owned()),     // 0
            InitList,                // 1
            Sym("arg".to_owned()),   // 2
            Element,                 // 3
            Func(6),                 // 4
            DeRef("arg".to_owned()), // 5
            Return,                  // 6
            Bind,                    // 7
            Val(Int(1)),             // 8
            DeRef("f".to_owned()),   // 9
            FCall,                   // 10
        ] => P(Int(1)),
        vec![
            Sym("closed".to_owned()),   // 0
            Val(Int(1)),                // 1
            Bind,                       // 2
            Sym("f".to_owned()),        // 3
            InitList,                   // 4
            Sym("arg".to_owned()),      // 5
            Element,                    // 6
            Func(11),                   // 7
            DeRef("arg".to_owned()),    // 8
            DeRef("closed".to_owned()), // 9
            Add,                        // 10
            Return,                     // 11
            Bind,                       // 12
            Val(Int(1)),                // 13
            DeRef("f".to_owned()),      // 14
            FCall,                      // 16
        ] => P(Int(2)),
    ];
}

#[test]
fn test_module_call() {
    assert_cases![
        vec![
            InitTuple,               // 0 // override tuple
            Sym("one".to_owned()),   // 1
            Val(Int(11)),            // 2
            Field,                   // 3
            Sym("m".to_owned()),     // 4 // binding name for module
            InitTuple,               // 5 // Module tuple bindings
            Sym("one".to_owned()),   // 6
            Val(Int(1)),             // 7
            Field,                   // 8
            Sym("two".to_owned()),   // 9
            Val(Int(2)),             // 10
            Field,                   // 11
            Module(17),              // 12 // Module definition
            Bind,                    // 13
            Sym("foo".to_owned()),   // 14
            DeRef("mod".to_owned()), // 15
            Bind,                    // 16 // bind mod tuple to foo
            Return,                  // 17 // end the module
            Bind,                    // 18 // bind module to the binding name
            DeRef("m".to_owned()),   // 19
            Cp,                      // 20
        ] => C(Tuple(vec![(
            "foo".to_owned(),
            C(Tuple(vec![
                ("one".to_owned(), P(Int(11))),
                ("two".to_owned(), P(Int(2))),
            ])),
        )])),
        vec![
            InitTuple,               // 0 // override tuple
            Sym("one".to_owned()),   // 1
            Val(Int(11)),            // 2
            Field,                   // 3
            Sym("m".to_owned()),     // 4 // binding name for module
            InitTuple,               // 5 // Module tuple bindings
            Sym("one".to_owned()),   // 6
            Val(Int(1)),             // 7
            Field,                   // 8
            Sym("two".to_owned()),   // 9
            Val(Int(2)),             // 10
            Field,                   // 11
            InitThunk(2),            // 12 // Module Return expression
            Val(Int(1)),             // 13
            Return,                  // 14
            Module(20),              // 15 // Module definition
            Bind,                    // 16
            Sym("foo".to_owned()),   // 17
            DeRef("mod".to_owned()), // 18
            Bind,                    // 19 // bind mod tuple to foo
            Return,                  // 20 // end the module
            Bind,                    // 21 // bind module to the binding name
            DeRef("m".to_owned()),   // 22
            Cp,                      // 23
        ] => P(Int(1)),
    ];
}

#[test]
fn test_select_short_circuit() {
    assert_cases![
        vec![
            Sym("field".to_owned()),              // 0 // search field
            Sym("not_field".to_owned()),          // 1 // first field to compare
            SelectJump(2),                        // 2
            Val(Str("not our value".to_owned())), // 3 // expression for first field
            Jump(4),                              // 4
            Sym("field".to_owned()),              // 5 // second field to compare
            SelectJump(2),                        // 6
            Val(Int(1)),                          // 7 // expression for second field
            Jump(2),                              // 8
            Pop,                                  // 9 // pop the search field off
            Bang,                                 // 10 // default case
        ] => P(Int(1)),
        vec![
            Sym("field".to_owned()),              // 0 // search field
            Sym("not_field".to_owned()),          // 1 // first field to compare
            SelectJump(2),                        // 2
            Val(Str("not our value".to_owned())), // 3 // expression for first field
            Jump(4),                              // 4
            Sym("als not field".to_owned()),      // 5 // second field to compare
            SelectJump(2),                        // 6
            Val(Int(1)),                          // 7 // expression for second field
            Jump(1),                              // 8
            Pop,                                  // 9 // pop the search field off
            Val(Int(1)),                          // 10 // default case
        ] => P(Int(1)),
    ];
}

#[test]
fn test_scope_stacks() {
    let mut stack = Stack::new();
    stack.add("one".to_owned(), P(Int(1)));
    let mut val = stack.get("one").unwrap();
    assert_eq!(val, &P(Int(1)));
    stack.push();
    assert!(stack.get("one").is_none());
    stack.to_open();
    val = stack.get("one").unwrap();
    assert_eq!(val, &P(Int(1)));
}
<|endoftext|>


<commit_before>use crate::fx::{FxHashMap, FxHasher};
use crate::sync::{Lock, LockGuard};
use smallvec::SmallVec;
use std::borrow::Borrow;
use std::collections::hash_map::RawEntryMut;
use std::hash::{Hash, Hasher};
use std::mem;

#[derive(Clone, Default)]
#[cfg_attr(parallel_compiler, repr(align(64)))]
struct CacheAligned<T>(T);

#[cfg(parallel_compiler)]
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
// but this should be tested on higher core count CPUs. How the `Sharded` type gets used
// may also affect the ideal number of shards.
const SHARD_BITS: usize = 5;

#[cfg(not(parallel_compiler))]
const SHARD_BITS: usize = 0;

pub const SHARDS: usize = 1 << SHARD_BITS;

/// An array of cache-line aligned inner locked structures with convenience methods.
#[derive(Clone)]
pub struct Sharded<T> {
    shards: [CacheAligned<Lock<T>>; SHARDS],
}

impl<T: Default> Default for Sharded<T> {
    #[inline]
    fn default() -> Self {
        Self::new(T::default)
    }
}

impl<T> Sharded<T> {
    #[inline]
    pub fn new(mut value: impl FnMut() -> T) -> Self {
        // Create a vector of the values we want
        let mut values: SmallVec<[_; SHARDS]> =
            (0..SHARDS).map(|_| CacheAligned(Lock::new(value()))).collect();

        // Create an uninitialized array
        let mut shards: mem::MaybeUninit<[CacheAligned<Lock<T>>; SHARDS]> =
            mem::MaybeUninit::uninit();

        unsafe {
            // Copy the values into our array
            let first = shards.as_mut_ptr() as *mut CacheAligned<Lock<T>>;
            values.as_ptr().copy_to_nonoverlapping(first, SHARDS);

            // Ignore the content of the vector
            values.set_len(0);

            Sharded { shards: shards.assume_init() }
        }
    }

    /// The shard is selected by hashing `val` with `FxHasher`.
    #[inline]
    pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
        if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
    }

    #[inline]
    pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
        &self.shards[get_shard_index_by_hash(hash)].0
    }

    #[inline]
    pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
        &self.shards[i].0
    }

    pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
        (0..SHARDS).map(|i| self.shards[i].0.lock()).collect()
    }

    pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
        (0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect()
    }
}

pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;

impl<K: Eq, V> ShardedHashMap<K, V> {
    pub fn len(&self) -> usize {
        self.lock_shards().iter().map(|shard| shard.len()).sum()
    }
}

impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
    #[inline]
    pub fn intern_ref<Q: ?Sized>(&self, value: &Q, make: impl FnOnce() -> K) -> K
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        let hash = make_hash(value);
        let mut shard = self.get_shard_by_hash(hash).lock();
        let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value);

        match entry {
            RawEntryMut::Occupied(e) => *e.key(),
            RawEntryMut::Vacant(e) => {
                let v = make();
                e.insert_hashed_nocheck(hash, v, ());
                v
            }
        }
    }

    #[inline]
    pub fn intern<Q>(&self, value: Q, make: impl FnOnce(Q) -> K) -> K
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        let hash = make_hash(&value);
        let mut shard = self.get_shard_by_hash(hash).lock();
        let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value);

        match entry {
            RawEntryMut::Occupied(e) => *e.key(),
            RawEntryMut::Vacant(e) => {
                let v = make(value);
                e.insert_hashed_nocheck(hash, v, ());
                v
            }
        }
    }
}

pub trait IntoPointer {
    /// Returns a pointer which outlives `self`.
    fn into_pointer(&self) -> *const ();
}

impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
    pub fn contains_pointer_to<T: Hash + IntoPointer>(&self, value: &T) -> bool {
        let hash = make_hash(&value);
        let shard = self.get_shard_by_hash(hash).lock();
        let value = value.into_pointer();
        shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some()
    }
}

#[inline]
fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
    let mut state = FxHasher::default();
    val.hash(&mut state);
    state.finish()
}

/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
/// `hash` can be computed with any hasher, so long as that hasher is used
/// consistently for each `Sharded` instance.
#[inline]
pub fn get_shard_index_by_hash(hash: u64) -> usize {
    let hash_len = mem::size_of::<usize>();
    // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
    // hashbrown also uses the lowest bits, so we can't use those
    let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
    bits % SHARDS
}
<commit_msg>Auto merge of #89069 - bjorn3:optimize_sharded_new, r=Mark-Simulacrum<commit_after>use crate::fx::{FxHashMap, FxHasher};
use crate::sync::{Lock, LockGuard};
use std::borrow::Borrow;
use std::collections::hash_map::RawEntryMut;
use std::hash::{Hash, Hasher};
use std::mem;

#[derive(Clone, Default)]
#[cfg_attr(parallel_compiler, repr(align(64)))]
struct CacheAligned<T>(T);

#[cfg(parallel_compiler)]
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
// but this should be tested on higher core count CPUs. How the `Sharded` type gets used
// may also affect the ideal number of shards.
const SHARD_BITS: usize = 5;

#[cfg(not(parallel_compiler))]
const SHARD_BITS: usize = 0;

pub const SHARDS: usize = 1 << SHARD_BITS;

/// An array of cache-line aligned inner locked structures with convenience methods.
#[derive(Clone)]
pub struct Sharded<T> {
    shards: [CacheAligned<Lock<T>>; SHARDS],
}

impl<T: Default> Default for Sharded<T> {
    #[inline]
    fn default() -> Self {
        Self::new(T::default)
    }
}

impl<T> Sharded<T> {
    #[inline]
    pub fn new(mut value: impl FnMut() -> T) -> Self {
        Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) }
    }

    /// The shard is selected by hashing `val` with `FxHasher`.
    #[inline]
    pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
        if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
    }

    #[inline]
    pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
        &self.shards[get_shard_index_by_hash(hash)].0
    }

    #[inline]
    pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
        &self.shards[i].0
    }

    pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
        (0..SHARDS).map(|i| self.shards[i].0.lock()).collect()
    }

    pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
        (0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect()
    }
}

pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;

impl<K: Eq, V> ShardedHashMap<K, V> {
    pub fn len(&self) -> usize {
        self.lock_shards().iter().map(|shard| shard.len()).sum()
    }
}

impl<K: Eq + Hash + Copy> ShardedHashMap<K, ()> {
    #[inline]
    pub fn intern_ref<Q: ?Sized>(&self, value: &Q, make: impl FnOnce() -> K) -> K
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        let hash = make_hash(value);
        let mut shard = self.get_shard_by_hash(hash).lock();
        let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value);

        match entry {
            RawEntryMut::Occupied(e) => *e.key(),
            RawEntryMut::Vacant(e) => {
                let v = make();
                e.insert_hashed_nocheck(hash, v, ());
                v
            }
        }
    }

    #[inline]
    pub fn intern<Q>(&self, value: Q, make: impl FnOnce(Q) -> K) -> K
    where
        K: Borrow<Q>,
        Q: Hash + Eq,
    {
        let hash = make_hash(&value);
        let mut shard = self.get_shard_by_hash(hash).lock();
        let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value);

        match entry {
            RawEntryMut::Occupied(e) => *e.key(),
            RawEntryMut::Vacant(e) => {
                let v = make(value);
                e.insert_hashed_nocheck(hash, v, ());
                v
            }
        }
    }
}

pub trait IntoPointer {
    /// Returns a pointer which outlives `self`.
    fn into_pointer(&self) -> *const ();
}

impl<K: Eq + Hash + Copy + IntoPointer> ShardedHashMap<K, ()> {
    pub fn contains_pointer_to<T: Hash + IntoPointer>(&self, value: &T) -> bool {
        let hash = make_hash(&value);
        let shard = self.get_shard_by_hash(hash).lock();
        let value = value.into_pointer();
        shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some()
    }
}

#[inline]
fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
    let mut state = FxHasher::default();
    val.hash(&mut state);
    state.finish()
}

/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
/// `hash` can be computed with any hasher, so long as that hasher is used
/// consistently for each `Sharded` instance.
#[inline]
pub fn get_shard_index_by_hash(hash: u64) -> usize {
    let hash_len = mem::size_of::<usize>();
    // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
    // hashbrown also uses the lowest bits, so we can't use those
    let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
    bits % SHARDS
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::cell::RefCell;

use glib::translate::*;
use glib_sys;

use aspect_ratio::*;
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use float_eq_cairo::ApproxEqCairo;
use handle::RsvgHandle;
use length::*;
use libc;
use node::*;
use parsers::{parse, parse_and_validate, Parse};
use property_bag::{OwnedPropertyBag, PropertyBag};
use state::Overflow;
use viewbox::*;
use viewport::{draw_in_viewport, ClipMode};

pub struct NodeGroup();

impl NodeGroup {
    pub fn new() -> NodeGroup {
        NodeGroup()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

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

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

pub struct NodeDefs();

impl NodeDefs {
    pub fn new() -> NodeDefs {
        NodeDefs()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

pub struct NodeSwitch();

impl NodeSwitch {
    pub fn new() -> NodeSwitch {
        NodeSwitch()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

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

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node.children().find(|c| c.get_cond()) {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(())
            }
        })
    }
}

pub struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Length>,
    h: Cell<Length>,
    vbox: Cell<Option<ViewBox>>,
    pbag: RefCell<Option<OwnedPropertyBag>>,
}

impl NodeSvg {
    pub fn new() -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            x: Cell::new(Length::parse_str("0", LengthDir::Horizontal).unwrap()),
            y: Cell::new(Length::parse_str("0", LengthDir::Vertical).unwrap()),
            w: Cell::new(Length::parse_str("100%", LengthDir::Horizontal).unwrap()),
            h: Cell::new(Length::parse_str("100%", LengthDir::Vertical).unwrap()),
            vbox: Cell::new(None),
            pbag: RefCell::new(None),
        }
    }

    pub fn set_delayed_style(&self, node: &RsvgNode, handle: *const RsvgHandle) {
        if let Some(owned_pbag) = self.pbag.borrow().as_ref() {
            let pbag = PropertyBag::from_owned(owned_pbag);
            node.set_style(handle, &pbag);
        }
    }
}

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

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = node.get_parent().is_some();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::X => {
                    if is_inner_svg {
                        self.x.set(parse("x", value, LengthDir::Horizontal)?);
                    }
                }

                Attribute::Y => {
                    if is_inner_svg {
                        self.y.set(parse("y", value, LengthDir::Vertical)?);
                    }
                }

                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),

                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        *self.pbag.borrow_mut() = Some(pbag.to_owned());

        Ok(())
    }

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

        let params = draw_ctx.get_view_params();

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

        let do_clip = !values.is_overflow() && node.get_parent().is_some();

        draw_in_viewport(
            nx,
            ny,
            nw,
            nh,
            ClipMode::ClipToViewport,
            do_clip,
            self.vbox.get(),
            self.preserve_aspect_ratio.get(),
            node,
            values,
            draw_ctx.get_cairo_context().get_matrix(),
            draw_ctx,
            clipping,
            &mut |dc| {
                // we don't push a layer because draw_in_viewport() already does it
                node.draw_children(cascaded, dc, clipping)
            },
        )
    }
}

pub struct NodeUse {
    link: RefCell<Option<String>>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Option<Length>>,
    h: Cell<Option<Length>>,
}

impl NodeUse {
    pub fn new() -> NodeUse {
        NodeUse {
            link: RefCell::new(None),
            x: Cell::new(Length::default()),
            y: Cell::new(Length::default()),
            w: Cell::new(None),
            h: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeUse {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag<'_>) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),

                Attribute::Width => self.w.set(
                    parse_and_validate(
                        "width",
                        value,
                        LengthDir::Horizontal,
                        Length::check_nonnegative,
                    )
                    .map(Some)?,
                ),
                Attribute::Height => self.h.set(
                    parse_and_validate(
                        "height",
                        value,
                        LengthDir::Vertical,
                        Length::check_nonnegative,
                    )
                    .map(Some)?,
                ),

                _ => (),
            }
        }

        Ok(())
    }

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

        let link = self.link.borrow();

        if link.is_none() {
            return Ok(());
        }

        let child = if let Some(acquired) = draw_ctx.get_acquired_node(link.as_ref().unwrap()) {
            // Here we clone the acquired child, so that we can drop the AcquiredNode as
            // early as possible.  This is so that the child's drawing method will be able
            // to re-acquire the child for other purposes.
            acquired.get().clone()
        } else {
            return Ok(());
        };

        if Node::is_ancestor(child.clone(), node.clone()) {
            // or, if we're <use>'ing ourselves
            return Err(RenderingError::CircularReference);
        }

        draw_ctx.increase_num_elements_rendered_through_use(1);

        let params = draw_ctx.get_view_params();

        let nx = self.x.get().normalize(values, &params);
        let ny = self.y.get().normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .get()
            .unwrap_or_else(|| Length::parse_str("100%", LengthDir::Horizontal).unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .get()
            .unwrap_or_else(|| Length::parse_str("100%", LengthDir::Vertical).unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(&0.0) || nh.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        if child.get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(nx, ny);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            child.with_impl(|symbol: &NodeSymbol| {
                let do_clip = !values.is_overflow()
                    || (values.overflow == Overflow::Visible && child.is_overflow());

                draw_in_viewport(
                    nx,
                    ny,
                    nw,
                    nh,
                    ClipMode::ClipToVbox,
                    do_clip,
                    symbol.vbox.get(),
                    symbol.preserve_aspect_ratio.get(),
                    node,
                    values,
                    draw_ctx.get_cairo_context().get_matrix(),
                    draw_ctx,
                    clipping,
                    &mut |dc| {
                        // We don't push a layer because draw_in_viewport() already does it
                        child.draw_children(
                            &CascadedValues::new_from_values(&child, values),
                            dc,
                            clipping,
                        )
                    },
                )
            })
        }
    }
}

pub struct NodeSymbol {
    preserve_aspect_ratio: Cell<AspectRatio>,
    vbox: Cell<Option<ViewBox>>,
}

impl NodeSymbol {
    pub fn new() -> NodeSymbol {
        NodeSymbol {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            vbox: Cell::new(None),
        }
    }
}

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

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        Ok(())
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_size(
    raw_node: *const RsvgNode,
    dpi_x: libc::c_double,
    dpi_y: libc::c_double,
    out_width: *mut i32,
    out_height: *mut i32,
) -> glib_sys::gboolean {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    assert!(!out_width.is_null());
    assert!(!out_height.is_null());

    node.with_impl(
        |svg: &NodeSvg| match (svg.w.get(), svg.h.get(), svg.vbox.get()) {
            (w, h, Some(vb)) => {
                unsafe {
                    *out_width = w.hand_normalize(dpi_x, vb.0.width, 12.0).round() as i32;
                    *out_height = h.hand_normalize(dpi_y, vb.0.height, 12.0).round() as i32;
                }
                true.to_glib()
            }
            (w, h, None) if w.unit != LengthUnit::Percent && h.unit != LengthUnit::Percent => {
                unsafe {
                    *out_width = w.hand_normalize(dpi_x, 0.0, 12.0).round() as i32;
                    *out_height = h.hand_normalize(dpi_y, 0.0, 12.0).round() as i32;
                }
                true.to_glib()
            }
            (_, _, _) => false.to_glib(),
        },
    )
}
<commit_msg>NodeUse: Log when referencing a nonexistent element<commit_after>use std::cell::Cell;
use std::cell::RefCell;

use glib::translate::*;
use glib_sys;

use aspect_ratio::*;
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use float_eq_cairo::ApproxEqCairo;
use handle::RsvgHandle;
use length::*;
use libc;
use node::*;
use parsers::{parse, parse_and_validate, Parse};
use property_bag::{OwnedPropertyBag, PropertyBag};
use state::Overflow;
use viewbox::*;
use viewport::{draw_in_viewport, ClipMode};

pub struct NodeGroup();

impl NodeGroup {
    pub fn new() -> NodeGroup {
        NodeGroup()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

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

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            node.draw_children(cascaded, dc, clipping)
        })
    }
}

pub struct NodeDefs();

impl NodeDefs {
    pub fn new() -> NodeDefs {
        NodeDefs()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }
}

pub struct NodeSwitch();

impl NodeSwitch {
    pub fn new() -> NodeSwitch {
        NodeSwitch()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag<'_>) -> NodeResult {
        Ok(())
    }

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

        draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
            if let Some(child) = node.children().find(|c| c.get_cond()) {
                dc.draw_node_from_stack(&CascadedValues::new(cascaded, &child), &child, clipping)
            } else {
                Ok(())
            }
        })
    }
}

pub struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Length>,
    h: Cell<Length>,
    vbox: Cell<Option<ViewBox>>,
    pbag: RefCell<Option<OwnedPropertyBag>>,
}

impl NodeSvg {
    pub fn new() -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            x: Cell::new(Length::parse_str("0", LengthDir::Horizontal).unwrap()),
            y: Cell::new(Length::parse_str("0", LengthDir::Vertical).unwrap()),
            w: Cell::new(Length::parse_str("100%", LengthDir::Horizontal).unwrap()),
            h: Cell::new(Length::parse_str("100%", LengthDir::Vertical).unwrap()),
            vbox: Cell::new(None),
            pbag: RefCell::new(None),
        }
    }

    pub fn set_delayed_style(&self, node: &RsvgNode, handle: *const RsvgHandle) {
        if let Some(owned_pbag) = self.pbag.borrow().as_ref() {
            let pbag = PropertyBag::from_owned(owned_pbag);
            node.set_style(handle, &pbag);
        }
    }
}

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

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        let is_inner_svg = node.get_parent().is_some();

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::X => {
                    if is_inner_svg {
                        self.x.set(parse("x", value, LengthDir::Horizontal)?);
                    }
                }

                Attribute::Y => {
                    if is_inner_svg {
                        self.y.set(parse("y", value, LengthDir::Vertical)?);
                    }
                }

                Attribute::Width => self.w.set(parse_and_validate(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Length::check_nonnegative,
                )?),

                Attribute::Height => self.h.set(parse_and_validate(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Length::check_nonnegative,
                )?),

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        *self.pbag.borrow_mut() = Some(pbag.to_owned());

        Ok(())
    }

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

        let params = draw_ctx.get_view_params();

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

        let do_clip = !values.is_overflow() && node.get_parent().is_some();

        draw_in_viewport(
            nx,
            ny,
            nw,
            nh,
            ClipMode::ClipToViewport,
            do_clip,
            self.vbox.get(),
            self.preserve_aspect_ratio.get(),
            node,
            values,
            draw_ctx.get_cairo_context().get_matrix(),
            draw_ctx,
            clipping,
            &mut |dc| {
                // we don't push a layer because draw_in_viewport() already does it
                node.draw_children(cascaded, dc, clipping)
            },
        )
    }
}

pub struct NodeUse {
    link: RefCell<Option<String>>,
    x: Cell<Length>,
    y: Cell<Length>,
    w: Cell<Option<Length>>,
    h: Cell<Option<Length>>,
}

impl NodeUse {
    pub fn new() -> NodeUse {
        NodeUse {
            link: RefCell::new(None),
            x: Cell::new(Length::default()),
            y: Cell::new(Length::default()),
            w: Cell::new(None),
            h: Cell::new(None),
        }
    }
}

impl NodeTrait for NodeUse {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag<'_>) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical)?),

                Attribute::Width => self.w.set(
                    parse_and_validate(
                        "width",
                        value,
                        LengthDir::Horizontal,
                        Length::check_nonnegative,
                    )
                    .map(Some)?,
                ),
                Attribute::Height => self.h.set(
                    parse_and_validate(
                        "height",
                        value,
                        LengthDir::Vertical,
                        Length::check_nonnegative,
                    )
                    .map(Some)?,
                ),

                _ => (),
            }
        }

        Ok(())
    }

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

        let link = self.link.borrow();

        if link.is_none() {
            return Ok(());
        }

        let uri = link.as_ref().unwrap();

        let child = if let Some(acquired) = draw_ctx.get_acquired_node(uri) {
            // Here we clone the acquired child, so that we can drop the AcquiredNode as
            // early as possible.  This is so that the child's drawing method will be able
            // to re-acquire the child for other purposes.
            acquired.get().clone()
        } else {
            rsvg_log!(
                "element {} references nonexistent \"{}\"",
                node.get_human_readable_name(),
                uri,
            );
            return Ok(());
        };

        if Node::is_ancestor(child.clone(), node.clone()) {
            // or, if we're <use>'ing ourselves
            return Err(RenderingError::CircularReference);
        }

        draw_ctx.increase_num_elements_rendered_through_use(1);

        let params = draw_ctx.get_view_params();

        let nx = self.x.get().normalize(values, &params);
        let ny = self.y.get().normalize(values, &params);

        // If attributes ‘width’ and/or ‘height’ are not specified,
        // [...] use values of '100%' for these attributes.
        // From https://www.w3.org/TR/SVG/struct.html#UseElement in
        // "If the ‘use’ element references a ‘symbol’ element"

        let nw = self
            .w
            .get()
            .unwrap_or_else(|| Length::parse_str("100%", LengthDir::Horizontal).unwrap())
            .normalize(values, &params);
        let nh = self
            .h
            .get()
            .unwrap_or_else(|| Length::parse_str("100%", LengthDir::Vertical).unwrap())
            .normalize(values, &params);

        // width or height set to 0 disables rendering of the element
        // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
        if nw.approx_eq_cairo(&0.0) || nh.approx_eq_cairo(&0.0) {
            return Ok(());
        }

        if child.get_type() != NodeType::Symbol {
            let cr = draw_ctx.get_cairo_context();
            cr.translate(nx, ny);

            draw_ctx.with_discrete_layer(node, values, clipping, &mut |dc| {
                dc.draw_node_from_stack(
                    &CascadedValues::new_from_values(&child, values),
                    &child,
                    clipping,
                )
            })
        } else {
            child.with_impl(|symbol: &NodeSymbol| {
                let do_clip = !values.is_overflow()
                    || (values.overflow == Overflow::Visible && child.is_overflow());

                draw_in_viewport(
                    nx,
                    ny,
                    nw,
                    nh,
                    ClipMode::ClipToVbox,
                    do_clip,
                    symbol.vbox.get(),
                    symbol.preserve_aspect_ratio.get(),
                    node,
                    values,
                    draw_ctx.get_cairo_context().get_matrix(),
                    draw_ctx,
                    clipping,
                    &mut |dc| {
                        // We don't push a layer because draw_in_viewport() already does it
                        child.draw_children(
                            &CascadedValues::new_from_values(&child, values),
                            dc,
                            clipping,
                        )
                    },
                )
            })
        }
    }
}

pub struct NodeSymbol {
    preserve_aspect_ratio: Cell<AspectRatio>,
    vbox: Cell<Option<ViewBox>>,
}

impl NodeSymbol {
    pub fn new() -> NodeSymbol {
        NodeSymbol {
            preserve_aspect_ratio: Cell::new(AspectRatio::default()),
            vbox: Cell::new(None),
        }
    }
}

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

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.preserve_aspect_ratio
                        .set(parse("preserveAspectRatio", value, ())?)
                }

                Attribute::ViewBox => self.vbox.set(parse("viewBox", value, ()).map(Some)?),

                _ => (),
            }
        }

        Ok(())
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_svg_get_size(
    raw_node: *const RsvgNode,
    dpi_x: libc::c_double,
    dpi_y: libc::c_double,
    out_width: *mut i32,
    out_height: *mut i32,
) -> glib_sys::gboolean {
    assert!(!raw_node.is_null());
    let node: &RsvgNode = unsafe { &*raw_node };

    assert!(!out_width.is_null());
    assert!(!out_height.is_null());

    node.with_impl(
        |svg: &NodeSvg| match (svg.w.get(), svg.h.get(), svg.vbox.get()) {
            (w, h, Some(vb)) => {
                unsafe {
                    *out_width = w.hand_normalize(dpi_x, vb.0.width, 12.0).round() as i32;
                    *out_height = h.hand_normalize(dpi_y, vb.0.height, 12.0).round() as i32;
                }
                true.to_glib()
            }
            (w, h, None) if w.unit != LengthUnit::Percent && h.unit != LengthUnit::Percent => {
                unsafe {
                    *out_width = w.hand_normalize(dpi_x, 0.0, 12.0).round() as i32;
                    *out_height = h.hand_normalize(dpi_y, 0.0, 12.0).round() as i32;
                }
                true.to_glib()
            }
            (_, _, _) => false.to_glib(),
        },
    )
}
<|endoftext|>


<commit_before>//! Deserialization support for the `application/x-www-form-urlencoded` format.

use std::{
    borrow::Cow,
    collections::btree_map::{self, BTreeMap},
    io::Read,
};

use form_urlencoded::{parse, Parse as UrlEncodedParse};
use serde::{
    de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer},
    forward_to_deserialize_any,
};

#[doc(inline)]
pub use serde::de::value::Error;

mod val_or_vec;

use val_or_vec::ValOrVec;

/// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`.
///
/// ```
/// let meal = vec![
///     ("bread".to_owned(), "baguette".to_owned()),
///     ("cheese".to_owned(), "comté".to_owned()),
///     ("fat".to_owned(), "butter".to_owned()),
///     ("meat".to_owned(), "ham".to_owned()),
/// ];
///
/// assert_eq!(
///     ruma_serde::urlencoded::from_bytes::<Vec<(String, String)>>(
///         b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
///     Ok(meal));
/// ```
pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result<T, Error>
where
    T: de::Deserialize<'de>,
{
    T::deserialize(Deserializer::new(parse(input)))
}

/// Deserializes a `application/x-www-form-urlencoded` value from a `&str`.
///
/// ```
/// let meal = vec![
///     ("bread".to_owned(), "baguette".to_owned()),
///     ("cheese".to_owned(), "comté".to_owned()),
///     ("fat".to_owned(), "butter".to_owned()),
///     ("meat".to_owned(), "ham".to_owned()),
/// ];
///
/// assert_eq!(
///     ruma_serde::urlencoded::from_str::<Vec<(String, String)>>(
///         "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
///     Ok(meal));
/// ```
pub fn from_str<'de, T>(input: &'de str) -> Result<T, Error>
where
    T: de::Deserialize<'de>,
{
    from_bytes(input.as_bytes())
}

/// Convenience function that reads all bytes from `reader` and deserializes
/// them with `from_bytes`.
pub fn from_reader<T, R>(mut reader: R) -> Result<T, Error>
where
    T: de::DeserializeOwned,
    R: Read,
{
    let mut buf = vec![];
    reader
        .read_to_end(&mut buf)
        .map_err(|e| de::Error::custom(format_args!("could not read input: {}", e)))?;
    from_bytes(&buf)
}

/// A deserializer for the `application/x-www-form-urlencoded` format.
///
/// * Supported top-level outputs are structs, maps and sequences of pairs,
///   with or without a given length.
///
/// * Main `deserialize` methods defers to `deserialize_map`.
///
/// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size`
///   defers to `deserialize`.
pub struct Deserializer<'de> {
    inner: MapDeserializer<'de, EntryIterator<'de>, Error>,
}

impl<'de> Deserializer<'de> {
    /// Returns a new `Deserializer`.
    pub fn new(parse: UrlEncodedParse<'de>) -> Self {
        Deserializer { inner: MapDeserializer::new(group_entries(parse).into_iter()) }
    }
}

impl<'de> de::Deserializer<'de> for Deserializer<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_map(self.inner)
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_seq(self.inner)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.inner.end()?;
        visitor.visit_unit()
    }

    forward_to_deserialize_any! {
        bool
        u8
        u16
        u32
        u64
        i8
        i16
        i32
        i64
        f32
        f64
        char
        str
        string
        option
        bytes
        byte_buf
        unit_struct
        newtype_struct
        tuple_struct
        struct
        identifier
        tuple
        enum
        ignored_any
    }
}

fn group_entries<'de>(parse: UrlEncodedParse<'de>) -> BTreeMap<Part<'de>, ValOrVec<Part<'de>>> {
    use btree_map::Entry::*;

    let mut res = BTreeMap::new();

    for (key, value) in parse {
        match res.entry(Part(key)) {
            Vacant(v) => {
                v.insert(ValOrVec::Val(Part(value)));
            }
            Occupied(mut o) => {
                o.get_mut().push(Part(value));
            }
        }
    }

    res
}

/*
input: a=b&c=d&a=c

vvvvv

next(): a => Wrapper([b, c])
next(): c => Wrapper([d])

struct Foo {
    a: Vec<String>,
    c: Vec<String>,
}

struct Bar {
    a: Vec<String>,
    c: String,
}

struct Baz {
    a: String,
}
*/

type EntryIterator<'de> = btree_map::IntoIter<Part<'de>, ValOrVec<Part<'de>>>;

#[derive(PartialEq, PartialOrd, Eq, Ord)]
struct Part<'de>(Cow<'de, str>);

impl<'de> IntoDeserializer<'de> for Part<'de> {
    type Deserializer = Self;

    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

macro_rules! forward_parsed_value {
    ($($ty:ident => $method:ident,)*) => {
        $(
            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
                where V: de::Visitor<'de>
            {
                match self.0.parse::<$ty>() {
                    Ok(val) => val.into_deserializer().$method(visitor),
                    Err(e) => Err(de::Error::custom(e))
                }
            }
        )*
    }
}

impl<'de> de::Deserializer<'de> for Part<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.0 {
            Cow::Borrowed(value) => visitor.visit_borrowed_str(value),
            Cow::Owned(value) => visitor.visit_string(value),
        }
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_some(self)
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_enum(ValueEnumAccess(self.0))
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        char
        str
        string
        unit
        bytes
        byte_buf
        unit_struct
        tuple_struct
        struct
        identifier
        tuple
        ignored_any
        seq
        map
    }

    forward_parsed_value! {
        bool => deserialize_bool,
        u8 => deserialize_u8,
        u16 => deserialize_u16,
        u32 => deserialize_u32,
        u64 => deserialize_u64,
        i8 => deserialize_i8,
        i16 => deserialize_i16,
        i32 => deserialize_i32,
        i64 => deserialize_i64,
        f32 => deserialize_f32,
        f64 => deserialize_f64,
    }
}

struct ValueEnumAccess<'de>(Cow<'de, str>);

impl<'de> de::EnumAccess<'de> for ValueEnumAccess<'de> {
    type Error = Error;
    type Variant = UnitOnlyVariantAccess;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    where
        V: de::DeserializeSeed<'de>,
    {
        let variant = seed.deserialize(self.0.into_deserializer())?;
        Ok((variant, UnitOnlyVariantAccess))
    }
}

struct UnitOnlyVariantAccess;

impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
    where
        T: de::DeserializeSeed<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }

    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        _visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }
}
<commit_msg>Remove unnecessary lifetimes<commit_after>//! Deserialization support for the `application/x-www-form-urlencoded` format.

use std::{
    borrow::Cow,
    collections::btree_map::{self, BTreeMap},
    io::Read,
};

use form_urlencoded::{parse, Parse as UrlEncodedParse};
use serde::{
    de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer},
    forward_to_deserialize_any,
};

#[doc(inline)]
pub use serde::de::value::Error;

mod val_or_vec;

use val_or_vec::ValOrVec;

/// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`.
///
/// ```
/// let meal = vec![
///     ("bread".to_owned(), "baguette".to_owned()),
///     ("cheese".to_owned(), "comté".to_owned()),
///     ("fat".to_owned(), "butter".to_owned()),
///     ("meat".to_owned(), "ham".to_owned()),
/// ];
///
/// assert_eq!(
///     ruma_serde::urlencoded::from_bytes::<Vec<(String, String)>>(
///         b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
///     Ok(meal));
/// ```
pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result<T, Error>
where
    T: de::Deserialize<'de>,
{
    T::deserialize(Deserializer::new(parse(input)))
}

/// Deserializes a `application/x-www-form-urlencoded` value from a `&str`.
///
/// ```
/// let meal = vec![
///     ("bread".to_owned(), "baguette".to_owned()),
///     ("cheese".to_owned(), "comté".to_owned()),
///     ("fat".to_owned(), "butter".to_owned()),
///     ("meat".to_owned(), "ham".to_owned()),
/// ];
///
/// assert_eq!(
///     ruma_serde::urlencoded::from_str::<Vec<(String, String)>>(
///         "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"),
///     Ok(meal));
/// ```
pub fn from_str<'de, T>(input: &'de str) -> Result<T, Error>
where
    T: de::Deserialize<'de>,
{
    from_bytes(input.as_bytes())
}

/// Convenience function that reads all bytes from `reader` and deserializes
/// them with `from_bytes`.
pub fn from_reader<T, R>(mut reader: R) -> Result<T, Error>
where
    T: de::DeserializeOwned,
    R: Read,
{
    let mut buf = vec![];
    reader
        .read_to_end(&mut buf)
        .map_err(|e| de::Error::custom(format_args!("could not read input: {}", e)))?;
    from_bytes(&buf)
}

/// A deserializer for the `application/x-www-form-urlencoded` format.
///
/// * Supported top-level outputs are structs, maps and sequences of pairs,
///   with or without a given length.
///
/// * Main `deserialize` methods defers to `deserialize_map`.
///
/// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size`
///   defers to `deserialize`.
pub struct Deserializer<'de> {
    inner: MapDeserializer<'de, EntryIterator<'de>, Error>,
}

impl<'de> Deserializer<'de> {
    /// Returns a new `Deserializer`.
    pub fn new(parse: UrlEncodedParse<'de>) -> Self {
        Deserializer { inner: MapDeserializer::new(group_entries(parse).into_iter()) }
    }
}

impl<'de> de::Deserializer<'de> for Deserializer<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_map(self.inner)
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_seq(self.inner)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.inner.end()?;
        visitor.visit_unit()
    }

    forward_to_deserialize_any! {
        bool
        u8
        u16
        u32
        u64
        i8
        i16
        i32
        i64
        f32
        f64
        char
        str
        string
        option
        bytes
        byte_buf
        unit_struct
        newtype_struct
        tuple_struct
        struct
        identifier
        tuple
        enum
        ignored_any
    }
}

fn group_entries(parse: UrlEncodedParse<'_>) -> BTreeMap<Part<'_>, ValOrVec<Part<'_>>> {
    use btree_map::Entry::*;

    let mut res = BTreeMap::new();

    for (key, value) in parse {
        match res.entry(Part(key)) {
            Vacant(v) => {
                v.insert(ValOrVec::Val(Part(value)));
            }
            Occupied(mut o) => {
                o.get_mut().push(Part(value));
            }
        }
    }

    res
}

/*
input: a=b&c=d&a=c

vvvvv

next(): a => Wrapper([b, c])
next(): c => Wrapper([d])

struct Foo {
    a: Vec<String>,
    c: Vec<String>,
}

struct Bar {
    a: Vec<String>,
    c: String,
}

struct Baz {
    a: String,
}
*/

type EntryIterator<'de> = btree_map::IntoIter<Part<'de>, ValOrVec<Part<'de>>>;

#[derive(PartialEq, PartialOrd, Eq, Ord)]
struct Part<'de>(Cow<'de, str>);

impl<'de> IntoDeserializer<'de> for Part<'de> {
    type Deserializer = Self;

    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

macro_rules! forward_parsed_value {
    ($($ty:ident => $method:ident,)*) => {
        $(
            fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
                where V: de::Visitor<'de>
            {
                match self.0.parse::<$ty>() {
                    Ok(val) => val.into_deserializer().$method(visitor),
                    Err(e) => Err(de::Error::custom(e))
                }
            }
        )*
    }
}

impl<'de> de::Deserializer<'de> for Part<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.0 {
            Cow::Borrowed(value) => visitor.visit_borrowed_str(value),
            Cow::Owned(value) => visitor.visit_string(value),
        }
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_some(self)
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_enum(ValueEnumAccess(self.0))
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        char
        str
        string
        unit
        bytes
        byte_buf
        unit_struct
        tuple_struct
        struct
        identifier
        tuple
        ignored_any
        seq
        map
    }

    forward_parsed_value! {
        bool => deserialize_bool,
        u8 => deserialize_u8,
        u16 => deserialize_u16,
        u32 => deserialize_u32,
        u64 => deserialize_u64,
        i8 => deserialize_i8,
        i16 => deserialize_i16,
        i32 => deserialize_i32,
        i64 => deserialize_i64,
        f32 => deserialize_f32,
        f64 => deserialize_f64,
    }
}

struct ValueEnumAccess<'de>(Cow<'de, str>);

impl<'de> de::EnumAccess<'de> for ValueEnumAccess<'de> {
    type Error = Error;
    type Variant = UnitOnlyVariantAccess;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    where
        V: de::DeserializeSeed<'de>,
    {
        let variant = seed.deserialize(self.0.into_deserializer())?;
        Ok((variant, UnitOnlyVariantAccess))
    }
}

struct UnitOnlyVariantAccess;

impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
    where
        T: de::DeserializeSeed<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }

    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        _visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Err(Error::custom("expected unit variant"))
    }
}
<|endoftext|>


<commit_before>use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;

pub trait IsInDiary {

    fn is_in_diary(&self, name: &str) -> bool;

}

impl IsInDiary for Entry {

    fn is_in_diary(&self, name: &str) -> bool {
        self.get_location().clone().is_in_diary(name)
    }

}

impl IsInDiary for StoreId {

    fn is_in_diary(&self, name: &str) -> bool {
        self.to_str().map(|s| s.contains(name)).unwrap_or(false)
    }

}

<commit_msg>Reimplement IsInDiary for StoreId with StoreId::is_in_collection()<commit_after>use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;

pub trait IsInDiary {

    fn is_in_diary(&self, name: &str) -> bool;

}

impl IsInDiary for Entry {

    fn is_in_diary(&self, name: &str) -> bool {
        self.get_location().clone().is_in_diary(name)
    }

}

impl IsInDiary for StoreId {

    fn is_in_diary(&self, name: &str) -> bool {
        self.is_in_collection(&["diary", name])
    }

}

<|endoftext|>


<commit_before>extern crate libc;
extern crate libqmlbind_sys as ffi;

use libc::c_char;
use libc::c_int;

use std::ffi::CString;

fn main() {
    println!("Example");

    // http://stackoverflow.com/a/34379937/178154
    // create a vector of zero terminated strings
    let args = std::env::args().map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
    // convert the strings to raw pointers
    let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
    unsafe {
        ffi::qmlbind_application_new(c_args.len() as c_int, c_args.as_ptr());
    }
}
<commit_msg>Initial port of libqmlbind's hello world example; it works!<commit_after>extern crate libc;
extern crate libqmlbind_sys as ffi;

use libc::c_char;
use libc::c_int;

use std::ffi::CString;

fn main() {
    println!("libqmlbind-sys example");

    // Port of https://github.com/seanchas116/libqmlbind/blob/master/examples/hello_world_window/main.c

    // http://stackoverflow.com/a/34379937/178154
    // create a vector of zero terminated strings
    let args = std::env::args().map(|arg| CString::new(arg).unwrap() ).collect::<Vec<CString>>();
    // convert the strings to raw pointers
    let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
    unsafe {
        let app = ffi::qmlbind_application_new(c_args.len() as c_int, c_args.as_ptr());
        let engine = ffi::qmlbind_engine_new();
        let component = ffi::qmlbind_component_new(engine);
        ffi::qmlbind_component_load_path(component, CString::new("main.qml").unwrap().as_ptr());

        let errorString = ffi::qmlbind_component_get_error_string(component);
        println!("errorString: {:?}", errorString);
        // let errorChar = ffi::qmlbind_string_get_chars(errorString);
        // println!("errorChar: {:?}", errorChar);

        let instance = ffi::qmlbind_component_create(component);

        let exit_code = ffi::qmlbind_application_exec(app);
    }
}
<|endoftext|>