<commit_before>use peg::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult};
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

#[derive(Debug, Clone)]
pub struct FlatTokenStream {
    tokens: Vec<Token>,
}

#[derive(Debug, Clone)]
pub enum Token {
    Ident(Ident),
    Literal(Literal),
    Punct(Punct),
    Begin(Group, usize),
    End(Delimiter, Span),
}

impl FlatTokenStream {
    pub fn new(stream: TokenStream) -> FlatTokenStream {
        let mut tokens = vec![];

        fn flatten(tokens: &mut Vec<Token>, tree: TokenTree) {
            match tree {
                TokenTree::Ident(i) => tokens.push(Token::Ident(i)),
                TokenTree::Literal(l) => tokens.push(Token::Literal(l)),
                TokenTree::Punct(p) => tokens.push(Token::Punct(p)),
                TokenTree::Group(g) => {
                    let start_pos = tokens.len();

                    tokens.push(Token::End(g.delimiter(), g.span())); // placeholder
                    for tree in g.stream() {
                        flatten(tokens, tree);
                    }
                    tokens.push(Token::End(g.delimiter(), g.span()));

                    let end_pos = tokens.len();
                    tokens[start_pos] = Token::Begin(g, end_pos);
                }
            }
        }

        for tree in stream {
            flatten(&mut tokens, tree);
        }

        FlatTokenStream { tokens }
    }

    pub fn len(&self) -> usize {
        self.tokens.len()
    } //TODO

    pub fn ident(&self, pos: usize) -> RuleResult<Ident> {
        match self.tokens.get(pos) {
            Some(Token::Ident(i)) => RuleResult::Matched(pos + 1, i.clone()),
            _ => RuleResult::Failed,
        }
    }

    pub fn literal(&self, pos: usize) -> RuleResult<Literal> {
        match self.tokens.get(pos) {
            Some(Token::Literal(i)) => RuleResult::Matched(pos + 1, i.clone()),
            _ => RuleResult::Failed,
        }
    }

    pub fn group(&self, pos: usize, delim: Delimiter) -> RuleResult<Group> {
        match self.tokens.get(pos) {
            Some(Token::Begin(g, n)) if g.delimiter() == delim => {
                RuleResult::Matched(*n, g.clone())
            }
            _ => RuleResult::Failed,
        }
    }
}

#[derive(Debug, Clone)]
pub struct Sp(pub Span, pub usize);

impl ::std::fmt::Display for Sp {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?} ({})", self.0, self.1)
    }
}

impl Parse for FlatTokenStream {
    type PositionRepr = Sp;
    fn start(&self) -> usize {
        0
    }

    fn is_eof(&self, pos: usize) -> bool {
        pos >= self.len()
    }

    fn position_repr(&self, pos: usize) -> Sp {
        Sp(
            match &self.tokens[pos] {
                Token::Ident(i) => i.span(),
                Token::Literal(l) => l.span(),
                Token::Punct(p) => p.span(),
                Token::Begin(g, _) => g.span(),
                Token::End(_, span) => span.clone(),
            },
            pos,
        )
    }
}

impl ParseElem for FlatTokenStream {
    type Element = Token;

    fn parse_elem(&self, pos: usize) -> RuleResult<Token> {
        match self.tokens.get(pos) {
            Some(c) => RuleResult::Matched(pos + 1, c.clone()),
            None => RuleResult::Failed,
        }
    }
}

fn delimiter_start(d: Delimiter) -> &'static str {
    match d {
        Delimiter::Brace => "{",
        Delimiter::Bracket => "[",
        Delimiter::Parenthesis => "(",
        _ => "",
    }
}

fn delimiter_end(d: Delimiter) -> &'static str {
    match d {
        Delimiter::Brace => "}",
        Delimiter::Bracket => "]",
        Delimiter::Parenthesis => ")",
        _ => "",
    }
}

impl ParseLiteral for FlatTokenStream {
    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> {
        match self.tokens.get(pos) {
            Some(Token::Ident(i)) if i.to_string() == literal => RuleResult::Matched(pos + 1, ()),
            Some(Token::Punct(p)) if literal.starts_with(p.as_char()) => {
                if literal.len() == 1 {
                    RuleResult::Matched(pos + 1, ())
                } else if p.spacing() == Spacing::Joint {
                    self.parse_string_literal(pos + 1, &literal[1..])
                } else {
                    RuleResult::Failed
                }
            }
            Some(Token::Begin(g, _)) if delimiter_start(g.delimiter()) == literal => {
                RuleResult::Matched(pos + 1, ())
            }
            Some(Token::End(d, _)) if delimiter_end(*d) == literal => {
                RuleResult::Matched(pos + 1, ())
            }
            _ => RuleResult::Failed,
        }
    }
}

impl<'input> ParseSlice<'input> for FlatTokenStream {
    type Slice = TokenStream;
    fn parse_slice(&'input self, p1: usize, p2: usize) -> TokenStream {
        let mut ts = TokenStream::new();
        let mut pos = p1;

        while pos < p2 {
            let (t, next_pos): (TokenTree, usize) = match &self.tokens[pos] {
                Token::Ident(i) => (i.clone().into(), pos + 1),
                Token::Literal(l) => (l.clone().into(), pos + 1),
                Token::Punct(p) => (p.clone().into(), pos + 1),
                Token::Begin(g, end) => (g.clone().into(), *end),
                Token::End(..) => panic!("$-expr containing unmatched group end"),
            };
            ts.extend(Some(t));
            pos = next_pos;
        }

        assert_eq!(pos, p2, "$-expr containing unmatched group start");

        ts
    }
}
<commit_msg>Remove now-unnecessary FlatTokenStream::len<commit_after>use peg::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult};
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

#[derive(Debug, Clone)]
pub struct FlatTokenStream {
    tokens: Vec<Token>,
}

#[derive(Debug, Clone)]
pub enum Token {
    Ident(Ident),
    Literal(Literal),
    Punct(Punct),
    Begin(Group, usize),
    End(Delimiter, Span),
}

impl FlatTokenStream {
    pub fn new(stream: TokenStream) -> FlatTokenStream {
        let mut tokens = vec![];

        fn flatten(tokens: &mut Vec<Token>, tree: TokenTree) {
            match tree {
                TokenTree::Ident(i) => tokens.push(Token::Ident(i)),
                TokenTree::Literal(l) => tokens.push(Token::Literal(l)),
                TokenTree::Punct(p) => tokens.push(Token::Punct(p)),
                TokenTree::Group(g) => {
                    let start_pos = tokens.len();

                    tokens.push(Token::End(g.delimiter(), g.span())); // placeholder
                    for tree in g.stream() {
                        flatten(tokens, tree);
                    }
                    tokens.push(Token::End(g.delimiter(), g.span()));

                    let end_pos = tokens.len();
                    tokens[start_pos] = Token::Begin(g, end_pos);
                }
            }
        }

        for tree in stream {
            flatten(&mut tokens, tree);
        }

        FlatTokenStream { tokens }
    }

    pub fn ident(&self, pos: usize) -> RuleResult<Ident> {
        match self.tokens.get(pos) {
            Some(Token::Ident(i)) => RuleResult::Matched(pos + 1, i.clone()),
            _ => RuleResult::Failed,
        }
    }

    pub fn literal(&self, pos: usize) -> RuleResult<Literal> {
        match self.tokens.get(pos) {
            Some(Token::Literal(i)) => RuleResult::Matched(pos + 1, i.clone()),
            _ => RuleResult::Failed,
        }
    }

    pub fn group(&self, pos: usize, delim: Delimiter) -> RuleResult<Group> {
        match self.tokens.get(pos) {
            Some(Token::Begin(g, n)) if g.delimiter() == delim => {
                RuleResult::Matched(*n, g.clone())
            }
            _ => RuleResult::Failed,
        }
    }
}

#[derive(Debug, Clone)]
pub struct Sp(pub Span, pub usize);

impl ::std::fmt::Display for Sp {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?} ({})", self.0, self.1)
    }
}

impl Parse for FlatTokenStream {
    type PositionRepr = Sp;
    fn start(&self) -> usize {
        0
    }

    fn is_eof(&self, pos: usize) -> bool {
        pos >= self.tokens.len()
    }

    fn position_repr(&self, pos: usize) -> Sp {
        Sp(
            match &self.tokens[pos] {
                Token::Ident(i) => i.span(),
                Token::Literal(l) => l.span(),
                Token::Punct(p) => p.span(),
                Token::Begin(g, _) => g.span(),
                Token::End(_, span) => span.clone(),
            },
            pos,
        )
    }
}

impl ParseElem for FlatTokenStream {
    type Element = Token;

    fn parse_elem(&self, pos: usize) -> RuleResult<Token> {
        match self.tokens.get(pos) {
            Some(c) => RuleResult::Matched(pos + 1, c.clone()),
            None => RuleResult::Failed,
        }
    }
}

fn delimiter_start(d: Delimiter) -> &'static str {
    match d {
        Delimiter::Brace => "{",
        Delimiter::Bracket => "[",
        Delimiter::Parenthesis => "(",
        _ => "",
    }
}

fn delimiter_end(d: Delimiter) -> &'static str {
    match d {
        Delimiter::Brace => "}",
        Delimiter::Bracket => "]",
        Delimiter::Parenthesis => ")",
        _ => "",
    }
}

impl ParseLiteral for FlatTokenStream {
    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> {
        match self.tokens.get(pos) {
            Some(Token::Ident(i)) if i.to_string() == literal => RuleResult::Matched(pos + 1, ()),
            Some(Token::Punct(p)) if literal.starts_with(p.as_char()) => {
                if literal.len() == 1 {
                    RuleResult::Matched(pos + 1, ())
                } else if p.spacing() == Spacing::Joint {
                    self.parse_string_literal(pos + 1, &literal[1..])
                } else {
                    RuleResult::Failed
                }
            }
            Some(Token::Begin(g, _)) if delimiter_start(g.delimiter()) == literal => {
                RuleResult::Matched(pos + 1, ())
            }
            Some(Token::End(d, _)) if delimiter_end(*d) == literal => {
                RuleResult::Matched(pos + 1, ())
            }
            _ => RuleResult::Failed,
        }
    }
}

impl<'input> ParseSlice<'input> for FlatTokenStream {
    type Slice = TokenStream;
    fn parse_slice(&'input self, p1: usize, p2: usize) -> TokenStream {
        let mut ts = TokenStream::new();
        let mut pos = p1;

        while pos < p2 {
            let (t, next_pos): (TokenTree, usize) = match &self.tokens[pos] {
                Token::Ident(i) => (i.clone().into(), pos + 1),
                Token::Literal(l) => (l.clone().into(), pos + 1),
                Token::Punct(p) => (p.clone().into(), pos + 1),
                Token::Begin(g, end) => (g.clone().into(), *end),
                Token::End(..) => panic!("$-expr containing unmatched group end"),
            };
            ts.extend(Some(t));
            pos = next_pos;
        }

        assert_eq!(pos, p2, "$-expr containing unmatched group start");

        ts
    }
}
<|endoftext|>


<commit_before>use ::std::slice;

/// Bytes allocated by leveldb
///
/// It's basically the same thing as `Box<[u8]>` except that it uses
/// leveldb_free() as a destructor.
pub struct Bytes {
    // We use static reference instead of pointer to inform the compiler that
    // it can't be null. (Because `NonZero` is unstable now.)
    bytes: &'static mut u8,
    size: usize,
    // Tells the compiler that we own u8
    _marker: ::std::marker::PhantomData<u8>,
}

impl Bytes {
    /// Creates instance of `Bytes` from leveldb-allocated data.
    ///
    /// Returns `None` if `ptr` is `null`.
    pub unsafe fn from_raw(ptr: *mut u8, size: usize) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(Bytes {
                bytes: &mut *ptr,
                size,
                _marker: Default::default(),
            })
        }
    }

    /// Creates instance of `Bytes` from leveldb-allocated data without null checking.
    pub unsafe fn from_raw_unchecked(ptr: *mut u8, size: usize) -> Self {
        Bytes {
            bytes: &mut *ptr,
            size,
            _marker: Default::default(),
        }
    }
}

impl Drop for Bytes {
    fn drop(&mut self) {
        unsafe {
            use libc::c_void;

            ::leveldb_sys::leveldb_free(self.bytes as *mut u8 as *mut c_void);
        }
    }
}

impl ::std::ops::Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe {
            slice::from_raw_parts(self.bytes, self.size)
        }
    }
}

impl ::std::ops::DerefMut for Bytes {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe {
            slice::from_raw_parts_mut(self.bytes as *mut u8, self.size)
        }
    }
}

impl ::std::borrow::Borrow<[u8]> for Bytes {
    fn borrow(&self) -> &[u8] {
        &*self
    }
}

impl ::std::borrow::BorrowMut<[u8]> for Bytes {
    fn borrow_mut(&mut self) -> &mut [u8] {
        &mut *self
    }
}

impl AsRef<[u8]> for Bytes {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl AsMut<[u8]> for Bytes {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut *self
    }
}

impl From<Bytes> for Vec<u8> {
    fn from(bytes: Bytes) -> Self {
        bytes.as_ref().into()
    }
}

impl From<Bytes> for Box<[u8]> {
    fn from(bytes: Bytes) -> Self {
        bytes.as_ref().into()
    }
}
<commit_msg>Support older versions of Rust.<commit_after>use ::std::slice;

/// Bytes allocated by leveldb
///
/// It's basically the same thing as `Box<[u8]>` except that it uses
/// leveldb_free() as a destructor.
pub struct Bytes {
    // We use static reference instead of pointer to inform the compiler that
    // it can't be null. (Because `NonZero` is unstable now.)
    bytes: &'static mut u8,
    size: usize,
    // Tells the compiler that we own u8
    _marker: ::std::marker::PhantomData<u8>,
}

impl Bytes {
    /// Creates instance of `Bytes` from leveldb-allocated data.
    ///
    /// Returns `None` if `ptr` is `null`.
    pub unsafe fn from_raw(ptr: *mut u8, size: usize) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(Bytes {
                bytes: &mut *ptr,
                size: size,
                _marker: Default::default(),
            })
        }
    }

    /// Creates instance of `Bytes` from leveldb-allocated data without null checking.
    pub unsafe fn from_raw_unchecked(ptr: *mut u8, size: usize) -> Self {
        Bytes {
            bytes: &mut *ptr,
            size: size,
            _marker: Default::default(),
        }
    }
}

impl Drop for Bytes {
    fn drop(&mut self) {
        unsafe {
            use libc::c_void;

            ::leveldb_sys::leveldb_free(self.bytes as *mut u8 as *mut c_void);
        }
    }
}

impl ::std::ops::Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe {
            slice::from_raw_parts(self.bytes, self.size)
        }
    }
}

impl ::std::ops::DerefMut for Bytes {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe {
            slice::from_raw_parts_mut(self.bytes as *mut u8, self.size)
        }
    }
}

impl ::std::borrow::Borrow<[u8]> for Bytes {
    fn borrow(&self) -> &[u8] {
        &*self
    }
}

impl ::std::borrow::BorrowMut<[u8]> for Bytes {
    fn borrow_mut(&mut self) -> &mut [u8] {
        &mut *self
    }
}

impl AsRef<[u8]> for Bytes {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl AsMut<[u8]> for Bytes {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut *self
    }
}

impl From<Bytes> for Vec<u8> {
    fn from(bytes: Bytes) -> Self {
        bytes.as_ref().into()
    }
}

impl From<Bytes> for Box<[u8]> {
    fn from(bytes: Bytes) -> Self {
        bytes.as_ref().into()
    }
}
<|endoftext|>


<commit_before>use criterion::Criterion;
use lucet_runtime_internals::context::{Context, ContextHandle};

/// Time the initialization of a context.
fn context_init(c: &mut Criterion) {
    extern "C" fn f() {}

    let mut stack = vec![0u64; 1024].into_boxed_slice();

    c.bench_function("context_init", move |b| {
        b.iter(|| {
            ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
        })
    });
}

/// Time the swap from an already-initialized context to a guest function and back.
fn context_swap_return(c: &mut Criterion) {
    extern "C" fn f() {}

    c.bench_function("context_swap_return", move |b| {
        b.iter_batched(
            || {
                let mut stack = vec![0u64; 1024].into_boxed_slice();
                let parent = ContextHandle::new();
                let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
                (stack, parent, child)
            },
            |(stack, mut parent, mut child)| unsafe {
                Context::swap(&mut parent, &mut child);
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Time initialization plus swap and return.
fn context_init_swap_return(c: &mut Criterion) {
    extern "C" fn f() {}

    c.bench_function("context_init_swap_return", move |b| {
        b.iter_batched(
            || vec![0u64; 1024].into_boxed_slice(),
            |mut stack| {
                let mut parent = ContextHandle::new();
                let mut child =
                    ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
                unsafe { Context::swap(&mut parent, &mut child) };
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Swap to a trivial guest function that takes a bunch of arguments.
fn context_init_swap_return_many_args(c: &mut Criterion) {
    extern "C" fn f(
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
    ) {
    }

    let args = vec![
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
    ];

    c.bench_function("context_init_swap_return_many_args", move |b| {
        b.iter_batched(
            || vec![0u64; 1024].into_boxed_slice(),
            |mut stack| {
                let mut parent = ContextHandle::new();
                let mut child =
                    ContextHandle::create_and_init(&mut *stack, f as usize, &args).unwrap();
                unsafe { Context::swap(&mut parent, &mut child) };
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Time the call to pthread_sigmask as used in `Context::init()`.
fn context_pthread_sigmask(c: &mut Criterion) {
    use nix::sys::signal;
    c.bench_function("context_pthread_sigmask", |b| {
        b.iter_batched(
            || signal::SigSet::empty(),
            |mut sigset| {
                signal::pthread_sigmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset))
                    .unwrap()
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

pub fn context_benches(c: &mut Criterion) {
    context_init(c);
    context_swap_return(c);
    context_init_swap_return(c);
    context_init_swap_return_many_args(c);
    context_pthread_sigmask(c);
}
<commit_msg>[lucet-benchmarks] slightly simplify a setup iter<commit_after>use criterion::Criterion;
use lucet_runtime_internals::context::{Context, ContextHandle};

/// Time the initialization of a context.
fn context_init(c: &mut Criterion) {
    extern "C" fn f() {}

    let mut stack = vec![0u64; 1024].into_boxed_slice();

    c.bench_function("context_init", move |b| {
        b.iter(|| {
            ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
        })
    });
}

/// Time the swap from an already-initialized context to a guest function and back.
fn context_swap_return(c: &mut Criterion) {
    extern "C" fn f() {}

    c.bench_function("context_swap_return", move |b| {
        b.iter_batched(
            || {
                let mut stack = vec![0u64; 1024].into_boxed_slice();
                let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
                (stack, child)
            },
            |(stack, mut child)| unsafe {
                let mut parent = ContextHandle::new();
                Context::swap(&mut parent, &mut child);
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Time initialization plus swap and return.
fn context_init_swap_return(c: &mut Criterion) {
    extern "C" fn f() {}

    c.bench_function("context_init_swap_return", move |b| {
        b.iter_batched(
            || vec![0u64; 1024].into_boxed_slice(),
            |mut stack| {
                let mut parent = ContextHandle::new();
                let mut child =
                    ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
                unsafe { Context::swap(&mut parent, &mut child) };
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Swap to a trivial guest function that takes a bunch of arguments.
fn context_init_swap_return_many_args(c: &mut Criterion) {
    extern "C" fn f(
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
    ) {
    }

    let args = vec![
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
        0xAFu8.into(),
        0xAFu16.into(),
        0xAFu32.into(),
        0xAFu64.into(),
        175.0f32.into(),
        175.0f64.into(),
    ];

    c.bench_function("context_init_swap_return_many_args", move |b| {
        b.iter_batched(
            || vec![0u64; 1024].into_boxed_slice(),
            |mut stack| {
                let mut parent = ContextHandle::new();
                let mut child =
                    ContextHandle::create_and_init(&mut *stack, f as usize, &args).unwrap();
                unsafe { Context::swap(&mut parent, &mut child) };
                stack
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

/// Time the call to pthread_sigmask as used in `Context::init()`.
fn context_pthread_sigmask(c: &mut Criterion) {
    use nix::sys::signal;
    c.bench_function("context_pthread_sigmask", |b| {
        b.iter_batched(
            || signal::SigSet::empty(),
            |mut sigset| {
                signal::pthread_sigmask(signal::SigmaskHow::SIG_SETMASK, None, Some(&mut sigset))
                    .unwrap()
            },
            criterion::BatchSize::PerIteration,
        )
    });
}

pub fn context_benches(c: &mut Criterion) {
    context_init(c);
    context_swap_return(c);
    context_init_swap_return(c);
    context_init_swap_return_many_args(c);
    context_pthread_sigmask(c);
}
<|endoftext|>


<commit_before>use lucet_module_data::FunctionPointer;
use lucet_runtime::lucet_hostcalls;
use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module};
use lucet_runtime_tests::helpers::MockExportBuilder;
use lucet_wasi_sdk::{CompileOpts, Lucetc};
use lucetc::{Bindings, LucetcOpts, OptLevel};
use std::path::Path;
use std::sync::Arc;

fn wasi_bindings() -> Bindings {
    let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../lucet-wasi/bindings.json");
    Bindings::from_file(&path).unwrap()
}

pub fn compile_hello<P: AsRef<Path>>(so_file: P, opt_level: OptLevel) {
    let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("guests/hello.c");
    let wasm_build = Lucetc::new(&[&path])
        .with_cflag("-Wall")
        .with_cflag("-Werror")
        .with_bindings(wasi_bindings())
        .with_opt_level(opt_level);

    wasm_build.build(&so_file).unwrap();
}

pub fn null_mock() -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .build()
}

pub fn large_dense_heap_mock(heap_kb: usize) -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    let heap_len = heap_kb * 1024;

    let heap_spec = HeapSpec {
        reserved_size: heap_len as u64,
        guard_size: 4 * 1024 * 1024,
        initial_size: heap_len as u64,
        max_size: None,
    };

    let mut heap = vec![0x00; heap_len];
    (0..heap_len).into_iter().for_each(|i| {
        heap[i] = (i % 256) as u8;
    });

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .with_initial_heap(heap.as_slice())
        .with_heap_spec(heap_spec)
        .build()
}

pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    let heap_len = heap_kb * 1024;

    let heap_spec = HeapSpec {
        reserved_size: heap_len as u64,
        guard_size: 4 * 1024 * 1024,
        initial_size: heap_len as u64,
        max_size: None,
    };

    let mut heap = vec![0x00; heap_len];

    // fill every `stride`th page with data
    (0..heap_len)
        .into_iter()
        .step_by(4096 * stride)
        .for_each(|base| {
            for i in base..base + 4096 {
                heap[i] = (i % 256) as u8;
            }
        });

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .with_initial_heap(heap.as_slice())
        .with_heap_spec(heap_spec)
        .build()
}

pub fn fib_mock() -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {
        fn fib(n: u32) -> u32 {
            if n == 0 {
                0
            } else if n == 1 {
                1
            } else {
                fib(n - 1) + fib(n - 2)
            }
        }
        assert_eq!(fib(25), 75025);
    }

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .build()
}

pub fn many_args_mock() -> Arc<dyn Module> {
    extern "C" fn f(
        _vmctx: *mut lucet_vmctx,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
    ) {
    }

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .build()
}

pub fn hostcalls_mock() -> Arc<dyn Module> {
    lucet_hostcalls! {
        #[inline(never)]
        #[no_mangle]
        pub unsafe extern "C" fn hostcall_wrapped(
            &mut vmctx,
            x1: u64,
            x2: u64,
            x3: u64,
            x4: u64,
            x5: u64,
            x6: u64,
            x7: u64,
            x8: u64,
            x9: u64,
            x10: u64,
            x11: u64,
            x12: u64,
            x13: u64,
            x14: u64,
            x15: u64,
            x16: u64,
        ) -> () {
            vmctx.heap_mut()[0] =
                (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16)
                    as u8;
            assert_eq!(vmctx.heap()[0], 136);
        }
    }

    #[inline(never)]
    #[no_mangle]
    pub unsafe extern "C" fn hostcall_raw(
        vmctx: *mut lucet_vmctx,
        x1: u64,
        x2: u64,
        x3: u64,
        x4: u64,
        x5: u64,
        x6: u64,
        x7: u64,
        x8: u64,
        x9: u64,
        x10: u64,
        x11: u64,
        x12: u64,
        x13: u64,
        x14: u64,
        x15: u64,
        x16: u64,
    ) {
        let vmctx = Vmctx::from_raw(vmctx);
        vmctx.heap_mut()[0] =
            (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16)
                as u8;
        assert_eq!(vmctx.heap()[0], 136);
    }

    unsafe extern "C" fn wrapped(vmctx: *mut lucet_vmctx) {
        for _ in 0..1000 {
            hostcall_wrapped(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        }
    }

    unsafe extern "C" fn raw(vmctx: *mut lucet_vmctx) {
        for _ in 0..1000 {
            hostcall_raw(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        }
    }

    MockModuleBuilder::new()
        .with_export_func(
            MockExportBuilder::new("wrapped", FunctionPointer::from_usize(wrapped as usize)))
        .with_export_func(
            MockExportBuilder::new("raw", FunctionPointer::from_usize(raw as usize)))
        .build()
}
<commit_msg>add a non-default signature so benchmark functions typecheck (#191)<commit_after>use lucet_module_data::{lucet_signature, FunctionPointer};
use lucet_runtime::lucet_hostcalls;
use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder, Module};
use lucet_runtime_tests::helpers::MockExportBuilder;
use lucet_wasi_sdk::{CompileOpts, Lucetc};
use lucetc::{Bindings, LucetcOpts, OptLevel};
use std::path::Path;
use std::sync::Arc;

fn wasi_bindings() -> Bindings {
    let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../lucet-wasi/bindings.json");
    Bindings::from_file(&path).unwrap()
}

pub fn compile_hello<P: AsRef<Path>>(so_file: P, opt_level: OptLevel) {
    let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("guests/hello.c");
    let wasm_build = Lucetc::new(&[&path])
        .with_cflag("-Wall")
        .with_cflag("-Werror")
        .with_bindings(wasi_bindings())
        .with_opt_level(opt_level);

    wasm_build.build(&so_file).unwrap();
}

pub fn null_mock() -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .build()
}

pub fn large_dense_heap_mock(heap_kb: usize) -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    let heap_len = heap_kb * 1024;

    let heap_spec = HeapSpec {
        reserved_size: heap_len as u64,
        guard_size: 4 * 1024 * 1024,
        initial_size: heap_len as u64,
        max_size: None,
    };

    let mut heap = vec![0x00; heap_len];
    (0..heap_len).into_iter().for_each(|i| {
        heap[i] = (i % 256) as u8;
    });

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .with_initial_heap(heap.as_slice())
        .with_heap_spec(heap_spec)
        .build()
}

pub fn large_sparse_heap_mock(heap_kb: usize, stride: usize) -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {}

    let heap_len = heap_kb * 1024;

    let heap_spec = HeapSpec {
        reserved_size: heap_len as u64,
        guard_size: 4 * 1024 * 1024,
        initial_size: heap_len as u64,
        max_size: None,
    };

    let mut heap = vec![0x00; heap_len];

    // fill every `stride`th page with data
    (0..heap_len)
        .into_iter()
        .step_by(4096 * stride)
        .for_each(|base| {
            for i in base..base + 4096 {
                heap[i] = (i % 256) as u8;
            }
        });

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .with_initial_heap(heap.as_slice())
        .with_heap_spec(heap_spec)
        .build()
}

pub fn fib_mock() -> Arc<dyn Module> {
    extern "C" fn f(_vmctx: *mut lucet_vmctx) {
        fn fib(n: u32) -> u32 {
            if n == 0 {
                0
            } else if n == 1 {
                1
            } else {
                fib(n - 1) + fib(n - 2)
            }
        }
        assert_eq!(fib(25), 75025);
    }

    MockModuleBuilder::new()
        .with_export_func(MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize)))
        .build()
}

pub fn many_args_mock() -> Arc<dyn Module> {
    extern "C" fn f(
        _vmctx: *mut lucet_vmctx,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
        _: u8,
        _: u16,
        _: u32,
        _: u64,
        _: f32,
        _: f64,
    ) {
    }

    MockModuleBuilder::new()
        .with_export_func(
            MockExportBuilder::new("f", FunctionPointer::from_usize(f as usize))
                .with_sig(lucet_signature!(
                    (
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64,
                        I32, I32, I32, I64, F32, F64
                    ) -> ()
                ))
        )
        .build()
}

pub fn hostcalls_mock() -> Arc<dyn Module> {
    lucet_hostcalls! {
        #[inline(never)]
        #[no_mangle]
        pub unsafe extern "C" fn hostcall_wrapped(
            &mut vmctx,
            x1: u64,
            x2: u64,
            x3: u64,
            x4: u64,
            x5: u64,
            x6: u64,
            x7: u64,
            x8: u64,
            x9: u64,
            x10: u64,
            x11: u64,
            x12: u64,
            x13: u64,
            x14: u64,
            x15: u64,
            x16: u64,
        ) -> () {
            vmctx.heap_mut()[0] =
                (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16)
                    as u8;
            assert_eq!(vmctx.heap()[0], 136);
        }
    }

    #[inline(never)]
    #[no_mangle]
    pub unsafe extern "C" fn hostcall_raw(
        vmctx: *mut lucet_vmctx,
        x1: u64,
        x2: u64,
        x3: u64,
        x4: u64,
        x5: u64,
        x6: u64,
        x7: u64,
        x8: u64,
        x9: u64,
        x10: u64,
        x11: u64,
        x12: u64,
        x13: u64,
        x14: u64,
        x15: u64,
        x16: u64,
    ) {
        let vmctx = Vmctx::from_raw(vmctx);
        vmctx.heap_mut()[0] =
            (x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16)
                as u8;
        assert_eq!(vmctx.heap()[0], 136);
    }

    unsafe extern "C" fn wrapped(vmctx: *mut lucet_vmctx) {
        for _ in 0..1000 {
            hostcall_wrapped(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        }
    }

    unsafe extern "C" fn raw(vmctx: *mut lucet_vmctx) {
        for _ in 0..1000 {
            hostcall_raw(vmctx, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
        }
    }

    MockModuleBuilder::new()
        .with_export_func(
            MockExportBuilder::new("wrapped", FunctionPointer::from_usize(wrapped as usize)))
        .with_export_func(
            MockExportBuilder::new("raw", FunctionPointer::from_usize(raw as usize)))
        .build()
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{sync_channel, Receiver};
use std::sync::Arc;
use super::Executable;
use std::default::Default;
/// A very simple round-robin scheduler. This should really be more of a DRR scheduler.
pub struct Scheduler {
    /// The set of runnable items. Note we currently don't have a blocked queue.
    run_q: Vec<Box<Executable>>,
    /// Next task to run.
    next_task: usize,
    sched_channel: Receiver<SchedulerCommand>,
}

pub enum SchedulerCommand {
    Add(Box<Executable + Send>),
    Run(Arc<Fn(&mut Scheduler) + Send + Sync>),
    Execute,
}

const DEFAULT_Q_SIZE: usize = 256;

impl Default for Scheduler {
    fn default() -> Scheduler {
        Scheduler::new()
    }
}

impl Scheduler {
    pub fn new() -> Scheduler {
        let (_, receiver) = sync_channel(0);
        Scheduler::new_with_channel(receiver)
    }

    pub fn new_with_channel(channel: Receiver<SchedulerCommand>) -> Scheduler {
        Scheduler {
            run_q: Vec::with_capacity(DEFAULT_Q_SIZE),
            next_task: 0,
            sched_channel: channel,
        }
    }

    fn handle_request(&mut self, request: SchedulerCommand) {
        match request {
            SchedulerCommand::Add(ex) => self.run_q.push(ex),
            SchedulerCommand::Run(f) => { f(self) },
            SchedulerCommand::Execute => { self.execute_loop() }
        }
    }

    pub fn handle_requests(&mut self) {
        while let Ok(cmd) = self.sched_channel.recv() {
            self.handle_request(cmd)
        }
        println!("Scheduler exiting");
    }

    /// Add a task to the current scheduler.
    pub fn add_task<T: Executable + 'static>(&mut self, task: T) {
        self.run_q.push(box task)
    }

    #[inline]
    fn execute_internal(&mut self) {
        let len = self.run_q.len();
        let task = &mut (&mut self.run_q[self.next_task]);
        let next = self.next_task + 1;
        if next == len {
            self.next_task = 0;
        } else {
            self.next_task = next
        }
        task.execute()
    }

    /// Run the scheduling loop.
    // TODO: Add a variable to stop the scheduler (for whatever reason).
    pub fn execute_loop(&mut self) {
        if !self.run_q.is_empty() {
            loop {
                self.execute_internal()
            }
        }
    }

    pub fn execute_one(&mut self) {
        if !self.run_q.is_empty() {
            self.execute_internal()
        }
    }
}
<commit_msg>Check scheduling channel during loop (#15)<commit_after>use std::sync::mpsc::{sync_channel, Receiver};
use std::sync::Arc;
use super::Executable;
use std::default::Default;
/// A very simple round-robin scheduler. This should really be more of a DRR scheduler.
pub struct Scheduler {
    /// The set of runnable items. Note we currently don't have a blocked queue.
    run_q: Vec<Box<Executable>>,
    /// Next task to run.
    next_task: usize,
    sched_channel: Receiver<SchedulerCommand>,
}

pub enum SchedulerCommand {
    Add(Box<Executable + Send>),
    Run(Arc<Fn(&mut Scheduler) + Send + Sync>),
    Execute,
}

const DEFAULT_Q_SIZE: usize = 256;

impl Default for Scheduler {
    fn default() -> Scheduler {
        Scheduler::new()
    }
}

impl Scheduler {
    pub fn new() -> Scheduler {
        let (_, receiver) = sync_channel(0);
        Scheduler::new_with_channel(receiver)
    }

    pub fn new_with_channel(channel: Receiver<SchedulerCommand>) -> Scheduler {
        Scheduler {
            run_q: Vec::with_capacity(DEFAULT_Q_SIZE),
            next_task: 0,
            sched_channel: channel,
        }
    }

    fn handle_request(&mut self, request: SchedulerCommand) {
        match request {
            SchedulerCommand::Add(ex) => self.run_q.push(ex),
            SchedulerCommand::Run(f) => { f(self) },
            SchedulerCommand::Execute => { self.execute_loop() }
        }
    }

    pub fn handle_requests(&mut self) {
        while let Ok(cmd) = self.sched_channel.recv() {
            self.handle_request(cmd)
        }
        println!("Scheduler exiting");
    }

    /// Add a task to the current scheduler.
    pub fn add_task<T: Executable + 'static>(&mut self, task: T) {
        self.run_q.push(box task)
    }

    #[inline]
    fn execute_internal(&mut self) {
        {
            let task = &mut (&mut self.run_q[self.next_task]);
            task.execute()
        }
        let len = self.run_q.len();
        let next = self.next_task + 1;
        if next == len {
            self.next_task = 0;
            if let Ok(cmd) = self.sched_channel.try_recv() {
                self.handle_request(cmd);
            }
        } else {
            self.next_task = next;
        }
    }

    /// Run the scheduling loop.
    // TODO: Add a variable to stop the scheduler (for whatever reason).
    pub fn execute_loop(&mut self) {
        if !self.run_q.is_empty() {
            loop {
                self.execute_internal()
            }
        }
    }

    pub fn execute_one(&mut self) {
        if !self.run_q.is_empty() {
            self.execute_internal()
        }
    }
}
<|endoftext|>


<commit_before>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::paint_server::UserSpacePaintSource;
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterOutput, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// Common properties for filter primitives, with all lengths in user space coordinates.
pub struct UserSpacePrimitive {
    x: Option<f64>,
    y: Option<f64>,
    width: Option<f64>,
    height: Option<f64>,
    result: Option<CustomIdent>,
}

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

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn to_user_space(
        &self,
        ctx: &FilterContext,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> UserSpacePrimitive {
        let params = draw_ctx.push_coord_units(ctx.primitive_units());

        let x = self.x.map(|l| l.normalize(values, &params));
        let y = self.y.map(|l| l.normalize(values, &params));
        let width = self.width.map(|l| l.normalize(values, &params));
        let height = self.height.map(|l| l.normalize(values, &params));

        UserSpacePrimitive {
            x,
            y,
            width,
            height,
            result: self.result.clone(),
        }
    }
}

impl UserSpacePrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> BoundsBuilder {
        BoundsBuilder::new(self.x, self.y, self.width, self.height, ctx.paffine())
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    stroke_paint_source: UserSpacePaintSource,
    fill_paint_source: UserSpacePaintSource,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    let primitive_nodes: Vec<Node> = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|n| n.clone())
        .collect();

    let filter_element = filter_node.borrow_element();

    if filter_element.is_in_error() {
        return Ok(source_surface);
    }

    let filter_values = filter_element.get_computed_values();

    let filter = borrow_element_as!(filter_node, Filter);

    let resolved_filter = {
        // This is in a temporary scope so we don't leave the coord_units pushed during
        // the execution of all the filter primitives.
        let params = draw_ctx.push_coord_units(filter.get_filter_units());
        filter.to_user_space(filter_values, &params)
    };

    if let Ok(mut filter_ctx) = FilterContext::new(
        &resolved_filter,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        transform,
        node_bbox,
    ) {
        for primitive_node in primitive_nodes {
            let elt = primitive_node.borrow_element();
            let filter = elt.as_filter_effect().unwrap();

            let primitive_values = elt.get_computed_values();

            let start = Instant::now();

            if let Err(err) = filter
                .resolve(&primitive_node)
                .and_then(|(primitive, params)| {
                    let user_space_primitive =
                        primitive.to_user_space(&filter_ctx, primitive_values, draw_ctx);

                    let output = render_primitive(
                        &user_space_primitive,
                        &params,
                        &filter_ctx,
                        acquired_nodes,
                        draw_ctx,
                    )?;

                    Ok(FilterResult {
                        name: user_space_primitive.result,
                        output,
                    })
                })
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!(
                    "(filter primitive {} returned an error: {})",
                    primitive_node,
                    err
                );

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(RenderingError::from(status));
                }
            }

            let elapsed = start.elapsed();
            rsvg_log!(
                "(rendered filter primitive {} in\n    {} seconds)",
                primitive_node,
                elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
            );
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &UserSpacePrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterOutput, FilterError> {
    use PrimitiveParams::*;

    let bounds_builder = primitive.get_bounds(ctx);

    match params {
        Blend(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<commit_msg>Rename variable<commit_after>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::paint_server::UserSpacePaintSource;
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterOutput, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<(Primitive, PrimitiveParams), FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

/// Common properties for filter primitives, with all lengths in user space coordinates.
pub struct UserSpacePrimitive {
    x: Option<f64>,
    y: Option<f64>,
    width: Option<f64>,
    height: Option<f64>,
    result: Option<CustomIdent>,
}

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

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl Primitive {
    fn to_user_space(
        &self,
        ctx: &FilterContext,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> UserSpacePrimitive {
        let params = draw_ctx.push_coord_units(ctx.primitive_units());

        let x = self.x.map(|l| l.normalize(values, &params));
        let y = self.y.map(|l| l.normalize(values, &params));
        let width = self.width.map(|l| l.normalize(values, &params));
        let height = self.height.map(|l| l.normalize(values, &params));

        UserSpacePrimitive {
            x,
            y,
            width,
            height,
            result: self.result.clone(),
        }
    }
}

impl UserSpacePrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> BoundsBuilder {
        BoundsBuilder::new(self.x, self.y, self.width, self.height, ctx.paffine())
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    stroke_paint_source: UserSpacePaintSource,
    fill_paint_source: UserSpacePaintSource,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    let primitive_nodes: Vec<Node> = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|n| n.clone())
        .collect();

    let filter_element = filter_node.borrow_element();

    if filter_element.is_in_error() {
        return Ok(source_surface);
    }

    let filter_values = filter_element.get_computed_values();

    let filter = borrow_element_as!(filter_node, Filter);

    let resolved_filter = {
        // This is in a temporary scope so we don't leave the coord_units pushed during
        // the execution of all the filter primitives.
        let params = draw_ctx.push_coord_units(filter.get_filter_units());
        filter.to_user_space(filter_values, &params)
    };

    if let Ok(mut filter_ctx) = FilterContext::new(
        &resolved_filter,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        transform,
        node_bbox,
    ) {
        for primitive_node in primitive_nodes {
            let elt = primitive_node.borrow_element();
            let effect = elt.as_filter_effect().unwrap();

            let primitive_values = elt.get_computed_values();

            let start = Instant::now();

            if let Err(err) = effect
                .resolve(&primitive_node)
                .and_then(|(primitive, params)| {
                    let user_space_primitive =
                        primitive.to_user_space(&filter_ctx, primitive_values, draw_ctx);

                    let output = render_primitive(
                        &user_space_primitive,
                        &params,
                        &filter_ctx,
                        acquired_nodes,
                        draw_ctx,
                    )?;

                    Ok(FilterResult {
                        name: user_space_primitive.result,
                        output,
                    })
                })
                .and_then(|result| filter_ctx.store_result(result))
            {
                rsvg_log!(
                    "(filter primitive {} returned an error: {})",
                    primitive_node,
                    err
                );

                // Exit early on Cairo errors. Continue rendering otherwise.
                if let FilterError::CairoError(status) = err {
                    return Err(RenderingError::from(status));
                }
            }

            let elapsed = start.elapsed();
            rsvg_log!(
                "(rendered filter primitive {} in\n    {} seconds)",
                primitive_node,
                elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
            );
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &UserSpacePrimitive,
    params: &PrimitiveParams,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterOutput, FilterError> {
    use PrimitiveParams::*;

    let bounds_builder = primitive.get_bounds(ctx);

    match params {
        Blend(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(p)       => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Composite(p)         => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(p)    => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Flood(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(p)      => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Image(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Merge(p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Morphology(p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Offset(p)            => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(p)  => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Tile(p)              => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Turbulence(p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<|endoftext|>