<commit_before>#![deny(missing_docs)]
//! Module for tracking the current thread, and wrapping non-`Send` objects in
//! guards that perform runtime thread checks.

use std::sync::Arc;
use std::fmt::{self, Debug};
use std::ptr;
use std::mem;
use std::cell::Cell;
use std::ops::{Deref,DerefMut};

/// A permanent identifier for a single thread, which will not be reused.
#[derive(Clone)]
pub struct ThreadId(Arc<()>);

impl PartialEq for ThreadId {
    fn eq(&self, other: &Self) -> bool {
        (&*self.0 as *const ()) == (&*other.0 as *const ())
    }
}
impl Eq for ThreadId {}

impl Debug for ThreadId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "thread({:?})", &*self.0 as *const ())
    }
}

// consider using https://github.com/rust-lang/rust/pull/29447 after it lands,
// or a u64 atomic where available
// is there a lock-free way to increment a 64-bit counter?
thread_local!(static THREAD_NONCE: ThreadId = ThreadId(Arc::new(())));

/// Returns a persistent identifier for the current thread.
pub fn current_thread_id() -> ThreadId {
    THREAD_NONCE.with(|r| r.clone())
}

struct TBListHead {
    // do not move
    owner: ThreadId,
    head: TBHeader,
    destroying: Cell<bool>,
}

struct TBList {
    list: Arc<TBListHead>,
}

struct TBHeader {
    // do not move
    next: Cell<*const TBHeader>,
    prev: Cell<*const TBHeader>,
    free: unsafe fn(*const TBHeader),
}

struct TBVar<T: 'static> {
    // do not move
    value: T,
    header: TBHeader,
}

/// A handle to a value of type `T` which is owned by a specific thread.  Code running on the same
/// thread can freely manipulate the value; attempts to manipulate the value from other threads
/// will panic at runtime.
///
/// Lifetime is subtle.  Since we do not assume `T` can be safely dropped from any thread other
/// than that where it was created, dropping a `ThreadBound<T>` will only immediately drop the
/// wrapped value in the originating thread.  Drops occuring on other threads will leave the value
/// in a thread-local list associated with the originating thread, and the value will live until
/// the originating thread exits, at which point it will be destroyed. Conversely, if the
/// originating thread exits while there are `ThreadBound<T>` capabilities alive in the heap, all
/// of the underlying values will be dropped (this causes the capabilities to become dangling
/// pointers, but that is OK as the only thread that could dereference them is exiting).
pub struct ThreadBound<T: 'static> {
    list: Arc<TBListHead>,
    var: *mut TBVar<T>,
}

unsafe impl<T: 'static> Send for ThreadBound<T> {}
unsafe impl<T: 'static> Sync for ThreadBound<T> {}

unsafe fn unlink_var(header: *const TBHeader) {
    // precondition: the list is being destroyed or the capability has just been
    // dropped
    // (either way there will be no future attempts to access this header)
    // println!("unlink header {:?}", header);
    let prev = (*header).prev.get();
    let next = (*header).next.get();
    (*next).prev.set(prev);
    (*prev).next.set(next);
}

// unsafe fn list_dumper(why: &'static str, lh: &TBListHead) {
//     let pstart = &lh.head as *const TBHeader;
//     let mut p2 = pstart;
//     println!("list dump {}", why);
//     loop {
//         println!("header@{:?}, next={next:?}, prev={prev:?}, free={free:?}", p2,
//             next = (*p2).next.get(), prev = (*p2).prev.get(), free = (*p2).free);
//         p2 = (*p2).next.get();
//         if p2 == pstart { break; }
//     }
// }

unsafe fn destroy_var(header: *const TBHeader) {
    // println!("destroy header {:?}", header);
    unlink_var(header);
    ((*header).free)(header);
}

impl Drop for TBList {
    fn drop(&mut self) {
        self.list.destroying.set(true);
        let headp = &self.list.head as *const TBHeader;

        unsafe {
            // list_dumper("A",&*self.list);
            while (*headp).next.get() != headp {
                destroy_var((*headp).next.get());
            }
        }
    }
}

impl<T: 'static> Drop for ThreadBound<T> {
    fn drop(&mut self) {
        if self.list.owner == current_thread_id() && !self.list.destroying.get() {
            unsafe {
                // list_dumper("B", &*self.list);
                destroy_var(&(*self.var).header);
            }
        }
        // otherwise the var leaks and will be cleaned up when the originating thread
        // exits.  we could provide a scrub() function to call from the originating
        // thread, at the cost of extra synchronization.
    }
}

impl TBList {
    fn new() -> Self {
        unsafe fn unreachable(_head: *const TBHeader) {
            panic!("attempt to free TBList header");
        }
        let lheader = Arc::new(TBListHead {
            owner: current_thread_id(),
            destroying: Cell::new(false),
            head: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: unreachable,
            },
        });
        let headp = &lheader.head as *const TBHeader;
        // println!("insert header {:?}", headp);
        unsafe {
            (*headp).next.set(headp);
            (*headp).prev.set(headp);
            // list_dumper("C", &*lheader);
        }
        TBList { list: lheader }
    }

    fn make_bound<T: 'static>(&self, value: T) -> ThreadBound<T> {
        unsafe fn free<T: 'static>(header: *const TBHeader) {
            let offset = &(*(0 as *const TBVar<T>)).header as *const TBHeader as usize;
            let varp = ((header as usize) - offset) as *mut TBVar<T>;
            // println!("free/box {:?}", varp);
            mem::drop(Box::from_raw(varp));
        }

        let new_var: *mut TBVar<T> = Box::into_raw(Box::new(TBVar {
            header: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: free::<T>,
            },
            value: value,
        }));

        unsafe {
            let new_head = &(*new_var).header as *const TBHeader;
            let list_head = &self.list.head as *const TBHeader;

            (*new_head).next.set(list_head);
            (*new_head).prev.set((*list_head).prev.get());
            (*(*list_head).prev.get()).next.set(new_head);
            (*list_head).prev.set(new_head);
            // list_dumper("D", &*self.list);
        }

        ThreadBound {
            var: new_var,
            list: self.list.clone(),
        }
    }
}

thread_local!(static THREAD_LIST_KEY: TBList = TBList::new());

impl<T: 'static> ThreadBound<T> {
    /// Wraps a value of type `T` in a capability bound to the current thread.
    pub fn new(inner: T) -> Self {
        THREAD_LIST_KEY.with(|tl| tl.make_bound(inner))
    }

    /// Returns true if this capability can be used without panicking.  This will remain true on
    /// the same thread as long as the thread does not enter the TLS destruction phase.
    pub fn accessible(&self) -> bool {
        return self.list.owner == current_thread_id() && !self.list.destroying.get();
    }

    /// Consumes this capability to regain ownership of the underlying value.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn into_inner(self) -> T {
        self.check_access();
        unsafe {
            unlink_var(&(*self.var).header as *const TBHeader);
            // yes, this is a move, so it invalidates the next/prev
            // println!("from_raw {:?}",self.var);
            let var_guts : TBVar<T> = *Box::from_raw(self.var);
            mem::forget(self); // no double free
            var_guts.value
        }
    }

    fn check_access(&self) {
        if self.list.owner != current_thread_id() {
            panic!("Attempt to access ThreadBound from incorrect thread");
        }

        if self.list.destroying.get() {
            panic!("Attempt to access ThreadBound during TLS destruction phase");
        }
    }
}

impl<T: 'static> Deref for ThreadBound<T> {
    type Target = T;
    /// Can this be documented?
    fn deref(&self) -> &T {
        self.check_access();
        unsafe { &(*self.var).value }
    }
}

impl<T: 'static> DerefMut for ThreadBound<T> {
    fn deref_mut(&mut self) -> &mut T {
        self.check_access();
        unsafe { &mut (*self.var).value }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::TBList;
    use std::thread;
    use std::mem;
    use std::sync::{Arc,Mutex};

    #[test]
    fn same_thread_id() {
        let id1 = current_thread_id();
        let id2 = current_thread_id();

        assert_eq!(id1, id2);
    }

    #[test]
    fn thread_id_formatting() {
        let strg = format!("{:?}", current_thread_id());
        assert!(strg.starts_with("thread("));
    }

    #[test]
    fn different_thread_id() {
        let id1 = current_thread_id();
        let id2 = thread::spawn(|| current_thread_id()).join().unwrap();

        assert!(id1 != id2);
    }

    #[test]
    fn round_tripping() {
        let y = 42;
        let mut cap = ThreadBound::new(y);

        assert!(cap.accessible());

        {
            let r1 : &i32 = &*cap;
            assert_eq!(*r1, 42);
        }

        {
            let r2 : &mut i32 = &mut *cap;
            assert_eq!(*r2, 42);
        }

        {
            let r3 : i32 = cap.into_inner();
            assert_eq!(r3, 42);
        }
    }

    #[test]
    fn wrong_thread_throws() {
        let mut cap = ThreadBound::new(42);
        let res: Box<&'static str> = thread::spawn(move || *cap = 55).join().err().unwrap().downcast().unwrap();
        assert_eq!(*res, "Attempt to access ThreadBound from incorrect thread")
    }

    #[test]
    fn wrong_thread_inaccessible() {
        let cap = ThreadBound::new(42);
        assert!(!thread::spawn(move || cap.accessible()).join().unwrap());
    }

    struct Trap(Arc<Mutex<bool>>);
    impl Drop for Trap {
        fn drop(&mut self) {
            (*self.0.lock().unwrap()) = true;
        }
    }

    #[test]
    fn inaccessible_after_teardown() {
        let cap = {
            let list = TBList::new();
            list.make_bound(42)
        };
        assert!(!cap.accessible());

        let error : Box<&'static str> = thread::spawn(|| {
            let mut cap2 = {
                let list = TBList::new();
                list.make_bound(42)
            };
            *cap2 = 55;
        }).join().err().unwrap().downcast().unwrap();

        assert_eq!(*error, "Attempt to access ThreadBound during TLS destruction phase");
    }

    #[test]
    fn sync_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let cap = ThreadBound::new(Trap(was_dropped.clone()));
        mem::drop(cap);
        assert!(*was_dropped.lock().unwrap());
    }

    #[test]
    fn async_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let was_dropped_2 = was_dropped.clone();
        let early_dropped = Arc::new(Mutex::new(false));
        let early_dropped_2 = early_dropped.clone();
        thread::spawn(move || {
            let cap = ThreadBound::new(Trap(was_dropped_2.clone()));
            thread::spawn(move || mem::drop(cap)).join().unwrap();
            (*early_dropped_2.lock().unwrap()) = *was_dropped_2.lock().unwrap();
        }).join().unwrap();
        assert!(!*early_dropped.lock().unwrap());
        assert!(*was_dropped.lock().unwrap());
    }
}
<commit_msg>whoops, I think deref was not actually safe<commit_after>#![deny(missing_docs)]
//! Module for tracking the current thread, and wrapping non-`Send` objects in
//! guards that perform runtime thread checks.

use std::sync::Arc;
use std::fmt::{self, Debug};
use std::ptr;
use std::mem;
use std::cell::Cell;

/// A permanent identifier for a single thread, which will not be reused.
#[derive(Clone)]
pub struct ThreadId(Arc<()>);

impl PartialEq for ThreadId {
    fn eq(&self, other: &Self) -> bool {
        (&*self.0 as *const ()) == (&*other.0 as *const ())
    }
}
impl Eq for ThreadId {}

impl Debug for ThreadId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "thread({:?})", &*self.0 as *const ())
    }
}

// consider using https://github.com/rust-lang/rust/pull/29447 after it lands,
// or a u64 atomic where available
// is there a lock-free way to increment a 64-bit counter?
thread_local!(static THREAD_NONCE: ThreadId = ThreadId(Arc::new(())));

/// Returns a persistent identifier for the current thread.
pub fn current_thread_id() -> ThreadId {
    THREAD_NONCE.with(|r| r.clone())
}

struct TBListHead {
    // do not move
    owner: ThreadId,
    head: TBHeader,
    destroying: Cell<bool>,
}

/// A container for values which must be accessed within a particular scope in a particular thread.
/// Values may be added using the `bind_value` method, which returns a capability; the capability
/// may freely move between threads, but can only be used in the thread of the binding.  A bound
/// value will be destroyed when the capability is destroyed if that happens in the allowed thread;
/// otherwise it will be destroyed when the list is.
pub struct TBList {
    list: Arc<TBListHead>,
}

struct TBHeader {
    // do not move
    next: Cell<*const TBHeader>,
    prev: Cell<*const TBHeader>,
    free: unsafe fn(*const TBHeader),
}

struct TBVar<T: 'static> {
    // do not move
    value: T,
    header: TBHeader,
}

/// A handle to a value of type `T` which is owned by a specific thread.  Code running on the same
/// thread can freely manipulate the value; attempts to manipulate the value from other threads
/// will panic at runtime.
///
/// Lifetime is subtle.  Since we do not assume `T` can be safely dropped from any thread other
/// than that where it was created, dropping a `ThreadBound<T>` will only immediately drop the
/// wrapped value in the originating thread.  Drops occuring on other threads will leave the value
/// in a thread-local list associated with the originating thread, and the value will live until
/// the originating thread exits, at which point it will be destroyed. Conversely, if the
/// originating thread exits while there are `ThreadBound<T>` capabilities alive in the heap, all
/// of the underlying values will be dropped (this causes the capabilities to become dangling
/// pointers, but that is OK as the only thread that could dereference them is exiting).
pub struct ThreadBound<T: 'static> {
    list: Arc<TBListHead>,
    var: *mut TBVar<T>,
}

unsafe impl<T: 'static> Send for ThreadBound<T> {}
unsafe impl<T: 'static> Sync for ThreadBound<T> {}

unsafe fn unlink_var(header: *const TBHeader) {
    // precondition: the list is being destroyed or the capability has just been
    // dropped
    // (either way there will be no future attempts to access this header)
    // println!("unlink header {:?}", header);
    let prev = (*header).prev.get();
    let next = (*header).next.get();
    (*next).prev.set(prev);
    (*prev).next.set(next);
}

// unsafe fn list_dumper(why: &'static str, lh: &TBListHead) {
//     let pstart = &lh.head as *const TBHeader;
//     let mut p2 = pstart;
//     println!("list dump {}", why);
//     loop {
// println!("header@{:?}, next={next:?}, prev={prev:?}, free={free:?}",
// p2,
// next = (*p2).next.get(), prev = (*p2).prev.get(), free =
// (*p2).free);
//         p2 = (*p2).next.get();
//         if p2 == pstart { break; }
//     }
// }

unsafe fn destroy_var(header: *const TBHeader) {
    // println!("destroy header {:?}", header);
    unlink_var(header);
    ((*header).free)(header);
}

impl Drop for TBList {
    fn drop(&mut self) {
        self.list.destroying.set(true);
        let headp = &self.list.head as *const TBHeader;

        unsafe {
            // list_dumper("A",&*self.list);
            while (*headp).next.get() != headp {
                destroy_var((*headp).next.get());
            }
        }
    }
}

impl<T: 'static> Drop for ThreadBound<T> {
    fn drop(&mut self) {
        if self.list.owner == current_thread_id() && !self.list.destroying.get() {
            unsafe {
                // list_dumper("B", &*self.list);
                destroy_var(&(*self.var).header);
            }
        }
        // otherwise the var leaks and will be cleaned up when the originating thread
        // exits.  we could provide a scrub() function to call from the originating
        // thread, at the cost of extra synchronization.
    }
}

impl TBList {
    fn new() -> Self {
        unsafe fn unreachable(_head: *const TBHeader) {
            panic!("attempt to free TBList header");
        }
        let lheader = Arc::new(TBListHead {
            owner: current_thread_id(),
            destroying: Cell::new(false),
            head: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: unreachable,
            },
        });
        let headp = &lheader.head as *const TBHeader;
        // println!("insert header {:?}", headp);
        unsafe {
            (*headp).next.set(headp);
            (*headp).prev.set(headp);
            // list_dumper("C", &*lheader);
        }
        TBList { list: lheader }
    }

    /// Creates a new scope for value bindings.  The lifetime of a scope list is forced to be a
    /// dynamic scope so that it will be properly nested with all `with` and `with_mut` borrows.
    pub fn scope<F, R>(f: F) -> R
        where F: FnOnce(&mut Self) -> R
    {
        f(&mut Self::new())
    }

    /// Transfers ownership of a value into a scope, and returns a capability which can be used to
    /// access that value but only within the same thread and during the same scope.
    pub fn bind<T: 'static>(&self, value: T) -> ThreadBound<T> {
        unsafe fn free<T: 'static>(header: *const TBHeader) {
            let offset = &(*(0 as *const TBVar<T>)).header as *const TBHeader as usize;
            let varp = ((header as usize) - offset) as *mut TBVar<T>;
            // println!("free/box {:?}", varp);
            mem::drop(Box::from_raw(varp));
        }

        let new_var: *mut TBVar<T> = Box::into_raw(Box::new(TBVar {
            header: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: free::<T>,
            },
            value: value,
        }));

        unsafe {
            let new_head = &(*new_var).header as *const TBHeader;
            let list_head = &self.list.head as *const TBHeader;

            (*new_head).next.set(list_head);
            (*new_head).prev.set((*list_head).prev.get());
            (*(*list_head).prev.get()).next.set(new_head);
            (*list_head).prev.set(new_head);
            // list_dumper("D", &*self.list);
        }

        ThreadBound {
            var: new_var,
            list: self.list.clone(),
        }
    }
}

thread_local!(static THREAD_LIST_KEY: TBList = TBList::new());

impl<T: 'static> ThreadBound<T> {
    /// Wraps a value of type `T` in a capability bound to the current thread.  This uses a
    /// thread-local instance of `TBList` with the lifetime of the calling thread.
    pub fn new(inner: T) -> Self {
        THREAD_LIST_KEY.with(|tl| tl.bind(inner))
    }

    /// Returns true if this capability can be used without panicking.  This will remain true on
    /// the same thread as long as the thread does not enter the TLS destruction phase.
    pub fn accessible(&self) -> bool {
        return self.list.owner == current_thread_id() && !self.list.destroying.get();
    }

    fn check_access(&self) {
        if self.list.owner != current_thread_id() {
            panic!("Attempt to access ThreadBound from incorrect thread");
        }

        if self.list.destroying.get() {
            panic!("Attempt to access ThreadBound during TLS destruction phase");
        }
    }

    /// Consumes this capability to regain ownership of the underlying value.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn into_inner(self) -> T {
        self.check_access();
        unsafe {
            unlink_var(&(*self.var).header as *const TBHeader);
            // yes, this is a move, so it invalidates the next/prev
            // println!("from_raw {:?}",self.var);
            let var_guts: TBVar<T> = *Box::from_raw(self.var);
            mem::forget(self); // no double free
            var_guts.value
        }
    }

    /// Temporarily acquires shared access to the guarded value.  It would not be safe to return a
    /// reference as by the standard `Deref` traits, as the lifetime of the capability could be
    /// much longer than the usable life of the referred value.  By only exposing borrowing and
    /// scoping as functions, we force the lifetimes of values and capabilities to be properly
    /// nested with each other in a thread, so a single liveness check at the beginning can
    /// suffice.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with<F, R>(&self, fun: F) -> R
        where F: FnOnce(&T) -> R
    {
        self.check_access();
        fun(unsafe { &(*self.var).value })
    }

    /// Temporarily acquires exclusive access to the guarded value.  See safety notes on `with`.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with_mut<F, R>(&mut self, fun: F) -> R
        where F: FnOnce(&mut T) -> R
    {
        self.check_access();
        fun(unsafe { &mut (*self.var).value })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::mem;
    use std::sync::{Arc, Mutex};

    #[test]
    fn same_thread_id() {
        let id1 = current_thread_id();
        let id2 = current_thread_id();

        assert_eq!(id1, id2);
    }

    #[test]
    fn thread_id_formatting() {
        let strg = format!("{:?}", current_thread_id());
        assert!(strg.starts_with("thread("));
    }

    #[test]
    fn different_thread_id() {
        let id1 = current_thread_id();
        let id2 = thread::spawn(|| current_thread_id()).join().unwrap();

        assert!(id1 != id2);
    }

    #[test]
    fn round_tripping() {
        let y = 42;
        let mut cap = ThreadBound::new(y);

        assert!(cap.accessible());

        cap.with(|r1| assert_eq!(*r1, 42));
        cap.with_mut(|r2| assert_eq!(*r2, 42));
        let r3: i32 = cap.into_inner();
        assert_eq!(r3, 42);
    }

    #[test]
    fn wrong_thread_throws() {
        let mut cap = ThreadBound::new(42);
        let joinh = thread::spawn(move || cap.with_mut(|r| *r = 55));
        let res: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();
        assert_eq!(*res, "Attempt to access ThreadBound from incorrect thread")
    }

    #[test]
    fn wrong_thread_inaccessible() {
        let cap = ThreadBound::new(42);
        assert!(!thread::spawn(move || cap.accessible()).join().unwrap());
    }

    struct Trap(Arc<Mutex<bool>>);
    impl Drop for Trap {
        fn drop(&mut self) {
            (*self.0.lock().unwrap()) = true;
        }
    }

    #[test]
    fn inaccessible_after_teardown() {
        let cap = TBList::scope(|list| list.bind(42));
        assert!(!cap.accessible());

        let joinh = thread::spawn(|| {
            let mut cap2 = TBList::scope(|list| list.bind(42));
            cap2.with_mut(|r| *r = 55);
        });
        let error: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();

        assert_eq!(*error,
                   "Attempt to access ThreadBound during TLS destruction phase");
    }

    #[test]
    fn sync_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let cap = ThreadBound::new(Trap(was_dropped.clone()));
        mem::drop(cap);
        assert!(*was_dropped.lock().unwrap());
    }

    #[test]
    fn async_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let was_dropped_2 = was_dropped.clone();
        let early_dropped = Arc::new(Mutex::new(false));
        let early_dropped_2 = early_dropped.clone();
        let thr = thread::spawn(move || {
            let cap = ThreadBound::new(Trap(was_dropped_2.clone()));
            thread::spawn(move || mem::drop(cap)).join().unwrap();
            (*early_dropped_2.lock().unwrap()) = *was_dropped_2.lock().unwrap();
        });
        thr.join().unwrap();
        assert!(!*early_dropped.lock().unwrap());
        assert!(*was_dropped.lock().unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::rc::Rc;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{warn, Event};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor};
use data_model::DataInit;
use futures::channel::mpsc;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::connection::socket::Listener as SocketListener;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::snd::cras_backend::{
    async_funcs::{handle_ctrl_queue, handle_pcm_queue, send_pcm_response_worker},
    hardcoded_snd_data, hardcoded_virtio_snd_config, Parameters, PcmResponse, SndData, StreamInfo,
    MAX_QUEUE_NUM, MAX_VRING_LEN,
};
use crate::virtio::snd::layout::virtio_snd_config;
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::{self, copy_config};

static SND_EXECUTOR: OnceCell<Executor> = OnceCell::new();

// Async workers:
// 0 - ctrl
// 1 - event
// 2 - tx
// 3 - rx
const PCM_RESPONSE_WORKER_IDX_OFFSET: usize = 2;
struct CrasSndBackend {
    cfg: virtio_snd_config,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
    response_workers: [Option<AbortHandle>; 2], // tx and rx
    snd_data: Rc<SndData>,
    streams: Rc<AsyncMutex<Vec<AsyncMutex<StreamInfo<'static>>>>>,
    params: Parameters,
    tx_send: mpsc::UnboundedSender<PcmResponse>,
    rx_send: mpsc::UnboundedSender<PcmResponse>,
    tx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
    rx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
}

impl CrasSndBackend {
    pub fn new(params: Parameters) -> anyhow::Result<Self> {
        let cfg = hardcoded_virtio_snd_config(&params);
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        let snd_data = hardcoded_snd_data(&params);

        let mut streams: Vec<AsyncMutex<StreamInfo>> = Vec::new();
        streams.resize_with(snd_data.pcm_info_len(), Default::default);
        let streams = Rc::new(AsyncMutex::new(streams));

        let (tx_send, tx_recv) = mpsc::unbounded();
        let (rx_send, rx_recv) = mpsc::unbounded();

        Ok(CrasSndBackend {
            cfg,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
            response_workers: Default::default(),
            snd_data: Rc::new(snd_data),
            streams,
            params,
            tx_send,
            rx_send,
            tx_recv: Some(tx_recv),
            rx_recv: Some(rx_recv),
        })
    }
}

impl VhostUserBackend for CrasSndBackend {
    const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM;
    const MAX_VRING_LEN: u16 = MAX_VRING_LEN;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        copy_config(data, 0, self.cfg.as_slice(), offset)
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Safe because the executor is initialized in main() below.
        let ex = SND_EXECUTOR.get().expect("Executor not initialized");

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt =
            EventAsync::new(kick_evt, ex).context("failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                // ctrl queue
                let streams = self.streams.clone();
                let snd_data = self.snd_data.clone();
                let tx_send = self.tx_send.clone();
                let rx_send = self.rx_send.clone();
                let params = self.params.clone();
                ex.spawn_local(Abortable::new(
                    async move {
                        handle_ctrl_queue(
                            &ex, &mem, &streams, &*snd_data, queue, kick_evt, &doorbell, tx_send,
                            rx_send, &params,
                        )
                        .await
                    },
                    registration,
                ))
                .detach();
            }
            1 => {} // TODO(woodychow): Add event queue support
            2 | 3 => {
                let (send, recv) = if idx == 2 {
                    (self.tx_send.clone(), self.tx_recv.take())
                } else {
                    (self.rx_send.clone(), self.rx_recv.take())
                };
                let mut recv = recv.ok_or_else(|| anyhow!("queue restart is not supported"))?;
                let queue = Rc::new(AsyncMutex::new(queue));
                let queue2 = Rc::clone(&queue);
                let mem = Rc::new(mem);
                let mem2 = Rc::clone(&mem);
                let streams = Rc::clone(&self.streams);
                ex.spawn_local(Abortable::new(
                    async move { handle_pcm_queue(&*mem, &streams, send, &queue, kick_evt).await },
                    registration,
                ))
                .detach();

                let (handle2, registration2) = AbortHandle::new_pair();

                ex.spawn_local(Abortable::new(
                    async move {
                        send_pcm_response_worker(&*mem2, &queue2, &doorbell, &mut recv).await
                    },
                    registration2,
                ))
                .detach();

                self.response_workers[idx - PCM_RESPONSE_WORKER_IDX_OFFSET] = Some(handle2);
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
        if idx == 2 || idx == 3 {
            if let Some(handle) = self
                .response_workers
                .get_mut(idx - PCM_RESPONSE_WORKER_IDX_OFFSET)
                .and_then(Option::take)
            {
                handle.abort();
            }
        }
    }
}

#[derive(FromArgs)]
#[argh(subcommand, name = "cras-snd")]
/// CRAS device
pub struct Options {
    #[argh(option, arg_name = "PATH")]
    /// path to a socket
    socket: String,
    #[argh(option, arg_name = "CONFIG")]
    /// comma separated key=value pairs for setting up cras snd devices.
    /// Possible key values:
    /// capture - Enable audio capture. Default to false.
    /// client_type - Set specific client type for cras backend.
    /// num_output_streams - Set number of output PCM streams.
    /// num_input_streams - Set number of input PCM streams.
    /// Example: [capture=true,client=crosvm,socket=unified,num_output_streams=1,num_input_streams=1]
    config: Option<String>,
}

/// Starts a vhost-user snd device with the cras backend.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_cras_snd_device(opts: Options) -> anyhow::Result<()> {
    let params = opts
        .config
        .unwrap_or("".to_string())
        .parse::<Parameters>()?;

    let snd_device = CrasSndBackend::new(params)?;

    // Create and bind unix socket
    let listener = SocketListener::new(opts.socket, true /* unlink */)?;

    let handler = DeviceRequestHandler::new(snd_device);

    // Child, we can continue by spawning the executor and set up the device
    let ex = Executor::new().context("Failed to create executor")?;

    let _ = SND_EXECUTOR.set(ex.clone());

    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(handler.run_with_listener(listener, &ex))?
}
<commit_msg>devices: vhost-user: cras: fix build with `audio_cras` feature<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::rc::Rc;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{warn, Event};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor};
use data_model::DataInit;
use futures::channel::mpsc;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::connection::socket::{Endpoint as SocketEndpoint, Listener as SocketListener};
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::snd::cras_backend::{
    async_funcs::{handle_ctrl_queue, handle_pcm_queue, send_pcm_response_worker},
    hardcoded_snd_data, hardcoded_virtio_snd_config, Parameters, PcmResponse, SndData, StreamInfo,
    MAX_QUEUE_NUM, MAX_VRING_LEN,
};
use crate::virtio::snd::layout::virtio_snd_config;
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::{self, copy_config};

static SND_EXECUTOR: OnceCell<Executor> = OnceCell::new();

// Async workers:
// 0 - ctrl
// 1 - event
// 2 - tx
// 3 - rx
const PCM_RESPONSE_WORKER_IDX_OFFSET: usize = 2;
struct CrasSndBackend {
    cfg: virtio_snd_config,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
    response_workers: [Option<AbortHandle>; 2], // tx and rx
    snd_data: Rc<SndData>,
    streams: Rc<AsyncMutex<Vec<AsyncMutex<StreamInfo<'static>>>>>,
    params: Parameters,
    tx_send: mpsc::UnboundedSender<PcmResponse>,
    rx_send: mpsc::UnboundedSender<PcmResponse>,
    tx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
    rx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
}

impl CrasSndBackend {
    pub fn new(params: Parameters) -> anyhow::Result<Self> {
        let cfg = hardcoded_virtio_snd_config(&params);
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        let snd_data = hardcoded_snd_data(&params);

        let mut streams: Vec<AsyncMutex<StreamInfo>> = Vec::new();
        streams.resize_with(snd_data.pcm_info_len(), Default::default);
        let streams = Rc::new(AsyncMutex::new(streams));

        let (tx_send, tx_recv) = mpsc::unbounded();
        let (rx_send, rx_recv) = mpsc::unbounded();

        Ok(CrasSndBackend {
            cfg,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
            response_workers: Default::default(),
            snd_data: Rc::new(snd_data),
            streams,
            params,
            tx_send,
            rx_send,
            tx_recv: Some(tx_recv),
            rx_recv: Some(rx_recv),
        })
    }
}

impl VhostUserBackend for CrasSndBackend {
    const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM;
    const MAX_VRING_LEN: u16 = MAX_VRING_LEN;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        copy_config(data, 0, self.cfg.as_slice(), offset)
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Safe because the executor is initialized in main() below.
        let ex = SND_EXECUTOR.get().expect("Executor not initialized");

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt =
            EventAsync::new(kick_evt, ex).context("failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                // ctrl queue
                let streams = self.streams.clone();
                let snd_data = self.snd_data.clone();
                let tx_send = self.tx_send.clone();
                let rx_send = self.rx_send.clone();
                let params = self.params.clone();
                ex.spawn_local(Abortable::new(
                    async move {
                        handle_ctrl_queue(
                            &ex, &mem, &streams, &*snd_data, queue, kick_evt, &doorbell, tx_send,
                            rx_send, &params,
                        )
                        .await
                    },
                    registration,
                ))
                .detach();
            }
            1 => {} // TODO(woodychow): Add event queue support
            2 | 3 => {
                let (send, recv) = if idx == 2 {
                    (self.tx_send.clone(), self.tx_recv.take())
                } else {
                    (self.rx_send.clone(), self.rx_recv.take())
                };
                let mut recv = recv.ok_or_else(|| anyhow!("queue restart is not supported"))?;
                let queue = Rc::new(AsyncMutex::new(queue));
                let queue2 = Rc::clone(&queue);
                let mem = Rc::new(mem);
                let mem2 = Rc::clone(&mem);
                let streams = Rc::clone(&self.streams);
                ex.spawn_local(Abortable::new(
                    async move { handle_pcm_queue(&*mem, &streams, send, &queue, kick_evt).await },
                    registration,
                ))
                .detach();

                let (handle2, registration2) = AbortHandle::new_pair();

                ex.spawn_local(Abortable::new(
                    async move {
                        send_pcm_response_worker(&*mem2, &queue2, &doorbell, &mut recv).await
                    },
                    registration2,
                ))
                .detach();

                self.response_workers[idx - PCM_RESPONSE_WORKER_IDX_OFFSET] = Some(handle2);
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
        if idx == 2 || idx == 3 {
            if let Some(handle) = self
                .response_workers
                .get_mut(idx - PCM_RESPONSE_WORKER_IDX_OFFSET)
                .and_then(Option::take)
            {
                handle.abort();
            }
        }
    }
}

#[derive(FromArgs)]
#[argh(subcommand, name = "cras-snd")]
/// CRAS device
pub struct Options {
    #[argh(option, arg_name = "PATH")]
    /// path to a socket
    socket: String,
    #[argh(option, arg_name = "CONFIG")]
    /// comma separated key=value pairs for setting up cras snd devices.
    /// Possible key values:
    /// capture - Enable audio capture. Default to false.
    /// client_type - Set specific client type for cras backend.
    /// num_output_streams - Set number of output PCM streams.
    /// num_input_streams - Set number of input PCM streams.
    /// Example: [capture=true,client=crosvm,socket=unified,num_output_streams=1,num_input_streams=1]
    config: Option<String>,
}

/// Starts a vhost-user snd device with the cras backend.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_cras_snd_device(opts: Options) -> anyhow::Result<()> {
    let params = opts
        .config
        .unwrap_or("".to_string())
        .parse::<Parameters>()?;

    let snd_device = CrasSndBackend::new(params)?;

    // Create and bind unix socket
    let listener = SocketListener::new(opts.socket, true /* unlink */)?;

    let handler = DeviceRequestHandler::new(snd_device);

    // Child, we can continue by spawning the executor and set up the device
    let ex = Executor::new().context("Failed to create executor")?;

    let _ = SND_EXECUTOR.set(ex.clone());

    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(handler.run_with_listener::<SocketEndpoint<_>>(listener, &ex))?
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

#![feature(test)]
#![allow(dead_code)]

extern crate test;
extern crate tempdir;
#[macro_use]
extern crate exonum;

#[cfg(test)]
mod tests {
    use tempdir::TempDir;

    use test::Bencher;
    use std::collections::BTreeMap;

    use exonum::storage::{ProofMapIndex, Database, Fork, LevelDB, LevelDBOptions, LevelDBCache,
                          StorageValue, Patch, RocksDB, RocksDBOptions, RocksBlockOptions};

    use std::collections::BTreeMap;
    use exonum::blockchain::{Blockchain, Transaction};
    use exonum::crypto::{gen_keypair, Hash, PublicKey, SecretKey};
    use exonum::messages::Message;
    use exonum::helpers::{Height, ValidatorId};

    fn execute_timestamping(db: Box<Database>, b: &mut Bencher) {
        let mut blockchain = Blockchain::new(db, Vec::new());

        message! {
            struct Tx {
                const TYPE = 1;
                const ID = 0;
                const SIZE = 64;

                field from: &PublicKey [00 => 32]
                field data: &Hash      [32 => 64]
            }
        }

        impl Transaction for Tx {
            fn verify(&self) -> bool {
                self.verify_signature(self.from())
            }

            fn execute(&self, _: &mut Fork) {}
        }

        fn prepare_txs(height: u64, count: u64) -> (Vec<Hash>, BTreeMap<Hash, Box<Transaction>>) {
            let (pub_key, sec_key) = gen_keypair();
            let mut txs = Vec::new();
            let mut pool = BTreeMap::new();
            for i in (height * count)..((height + 1) * count) {
                let tx = Tx::new(&pub_key, &i.hash(), &sec_key);
                let tx_hash = Transaction::hash(&tx);
                txs.push(tx_hash);
                pool.insert(tx_hash, Box::new(tx) as Box<Transaction>);
            }
            (txs, pool)
        }

        fn execute_block(
            blockchain: &Blockchain,
            height: u64,
            txs: &[Hash],
            pool: &BTreeMap<Hash, Box<Transaction>>,
        ) -> Patch {
            blockchain
                .create_patch(ValidatorId::zero(), Height(height), txs, pool)
                .1
        }

        for i in 0..100 {
            let (txs, pool) = prepare_txs(i, 1000);
            let patch = execute_block(&blockchain, i, &txs, &pool);
            blockchain.merge(patch).unwrap();
        }

        let (txs, pool) = prepare_txs(100, 1000);

        b.iter(|| execute_block(&blockchain, 100, &txs, &pool));
    }

    fn execute_cryptocurrency(db: Box<Database>, b: &mut Bencher) {
        let mut blockchain = Blockchain::new(db, Vec::new());

        message! {
            struct Tx {
                const TYPE = 1;
                const ID = 0;
                const SIZE = 64;

                field from: &PublicKey [00 => 32]
                field to:   &PublicKey [32 => 64]
            }
        }

        impl Transaction for Tx {
            fn verify(&self) -> bool {
                self.verify_signature(self.from())
            }

            fn execute(&self, view: &mut Fork) {
                let mut index = ProofMapIndex::new(vec![1], view);
                let from_balance = index.get(self.from()).unwrap_or(0u64);
                let to_balance = index.get(self.to()).unwrap_or(0u64);
                index.put(self.from(), from_balance - 1);
                index.put(self.to(), to_balance + 1);
            }
        }

        let mut keys = Vec::new();

        for _ in 0..10_000 {
            keys.push(gen_keypair());
        }

        fn prepare_txs(
            height: u64,
            count: u64,
            keys: &[(PublicKey, SecretKey)],
        ) -> (Vec<Hash>, BTreeMap<Hash, Box<Transaction>>) {
            let mut txs = Vec::new();
            let mut pool = BTreeMap::new();
            for i in (height * count)..((height + 1) * count) {
                let tx = Tx::new(
                    &keys[i as usize % 10_000].0,
                    &keys[(i as usize + 3_456) % 10_000].0,
                    &keys[i as usize % 10_000].1,
                );
                let tx_hash = Transaction::hash(&tx);
                txs.push(tx_hash);
                pool.insert(tx_hash, Box::new(tx) as Box<Transaction>);
            }
            (txs, pool)
        }

        fn execute_block(
            blockchain: &Blockchain,
            height: u64,
            txs: &[Hash],
            pool: &BTreeMap<Hash, Box<Transaction>>,
        ) -> Patch {
            blockchain
                .create_patch(ValidatorId::zero(), Height(height), txs, pool)
                .1
        }

        for i in 0..100 {
            let (txs, pool) = prepare_txs(i, 1000, &keys);
            let patch = execute_block(&blockchain, i, &txs, &pool);
            blockchain.merge(patch).unwrap();
        }

        let (txs, pool) = prepare_txs(100, 1000, &keys);

        b.iter(|| execute_block(&blockchain, 100, &txs, &pool));
    }

    fn create_rocksdb(tempdir: &TempDir) -> Box<Database> {
        let mut block_options = RocksBlockOptions::default();
        block_options.set_block_size(4 * 1024);
        block_options.set_lru_cache(512 * 1024 * 1024);
        block_options.set_bloom_filter(128, true);
        block_options.set_cache_index_and_filter_blocks(true);
        let mut options = RocksDBOptions::default();
        options.create_if_missing(true);
        options.increase_parallelism(4);
        options.set_max_write_buffer_number(16);
        options.set_write_buffer_size(536_870_912);
        options.set_max_open_files(-1);
        options.set_block_based_table_factory(&block_options);
        options.set_max_bytes_for_level_base(512 * 1024 * 1024);
        let db = Box::new(RocksDB::open(tempdir.path(), options).unwrap());
        db as Box<Database>
    }

    #[bench]
    fn bench_execute_block_timestamping_leveldb(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_timestamping_leveldb_cache(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        options.cache = Some(LevelDBCache::new(100_000_000));
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_leveldb(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_cryptocurrency(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_leveldb_cache(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        options.cache = Some(LevelDBCache::new(100_000_000));
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_cryptocurrency(db, b)
    }

    #[bench]
    fn bench_execute_block_timestamping_rocksdb(b: &mut Bencher) {
        let tempdir = TempDir::new("exonum").unwrap();
        let db = create_rocksdb(&tempdir);
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_rocksdb(b: &mut Bencher) {
        let tempdir = TempDir::new("exonum").unwrap();
        let db = create_rocksdb(&tempdir);
        execute_cryptocurrency(db, b)
    }
}
<commit_msg>Removed duplicated import<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

#![feature(test)]
#![allow(dead_code)]

extern crate test;
extern crate tempdir;
#[macro_use]
extern crate exonum;

#[cfg(test)]
mod tests {
    use tempdir::TempDir;

    use test::Bencher;
    use std::collections::BTreeMap;

    use exonum::storage::{ProofMapIndex, Database, Fork, LevelDB, LevelDBOptions, LevelDBCache,
                          StorageValue, Patch, RocksDB, RocksDBOptions, RocksBlockOptions};
    use exonum::blockchain::{Blockchain, Transaction};
    use exonum::crypto::{gen_keypair, Hash, PublicKey, SecretKey};
    use exonum::messages::Message;
    use exonum::helpers::{Height, ValidatorId};

    fn execute_timestamping(db: Box<Database>, b: &mut Bencher) {
        let mut blockchain = Blockchain::new(db, Vec::new());

        message! {
            struct Tx {
                const TYPE = 1;
                const ID = 0;
                const SIZE = 64;

                field from: &PublicKey [00 => 32]
                field data: &Hash      [32 => 64]
            }
        }

        impl Transaction for Tx {
            fn verify(&self) -> bool {
                self.verify_signature(self.from())
            }

            fn execute(&self, _: &mut Fork) {}
        }

        fn prepare_txs(height: u64, count: u64) -> (Vec<Hash>, BTreeMap<Hash, Box<Transaction>>) {
            let (pub_key, sec_key) = gen_keypair();
            let mut txs = Vec::new();
            let mut pool = BTreeMap::new();
            for i in (height * count)..((height + 1) * count) {
                let tx = Tx::new(&pub_key, &i.hash(), &sec_key);
                let tx_hash = Transaction::hash(&tx);
                txs.push(tx_hash);
                pool.insert(tx_hash, Box::new(tx) as Box<Transaction>);
            }
            (txs, pool)
        }

        fn execute_block(
            blockchain: &Blockchain,
            height: u64,
            txs: &[Hash],
            pool: &BTreeMap<Hash, Box<Transaction>>,
        ) -> Patch {
            blockchain
                .create_patch(ValidatorId::zero(), Height(height), txs, pool)
                .1
        }

        for i in 0..100 {
            let (txs, pool) = prepare_txs(i, 1000);
            let patch = execute_block(&blockchain, i, &txs, &pool);
            blockchain.merge(patch).unwrap();
        }

        let (txs, pool) = prepare_txs(100, 1000);

        b.iter(|| execute_block(&blockchain, 100, &txs, &pool));
    }

    fn execute_cryptocurrency(db: Box<Database>, b: &mut Bencher) {
        let mut blockchain = Blockchain::new(db, Vec::new());

        message! {
            struct Tx {
                const TYPE = 1;
                const ID = 0;
                const SIZE = 64;

                field from: &PublicKey [00 => 32]
                field to:   &PublicKey [32 => 64]
            }
        }

        impl Transaction for Tx {
            fn verify(&self) -> bool {
                self.verify_signature(self.from())
            }

            fn execute(&self, view: &mut Fork) {
                let mut index = ProofMapIndex::new(vec![1], view);
                let from_balance = index.get(self.from()).unwrap_or(0u64);
                let to_balance = index.get(self.to()).unwrap_or(0u64);
                index.put(self.from(), from_balance - 1);
                index.put(self.to(), to_balance + 1);
            }
        }

        let mut keys = Vec::new();

        for _ in 0..10_000 {
            keys.push(gen_keypair());
        }

        fn prepare_txs(
            height: u64,
            count: u64,
            keys: &[(PublicKey, SecretKey)],
        ) -> (Vec<Hash>, BTreeMap<Hash, Box<Transaction>>) {
            let mut txs = Vec::new();
            let mut pool = BTreeMap::new();
            for i in (height * count)..((height + 1) * count) {
                let tx = Tx::new(
                    &keys[i as usize % 10_000].0,
                    &keys[(i as usize + 3_456) % 10_000].0,
                    &keys[i as usize % 10_000].1,
                );
                let tx_hash = Transaction::hash(&tx);
                txs.push(tx_hash);
                pool.insert(tx_hash, Box::new(tx) as Box<Transaction>);
            }
            (txs, pool)
        }

        fn execute_block(
            blockchain: &Blockchain,
            height: u64,
            txs: &[Hash],
            pool: &BTreeMap<Hash, Box<Transaction>>,
        ) -> Patch {
            blockchain
                .create_patch(ValidatorId::zero(), Height(height), txs, pool)
                .1
        }

        for i in 0..100 {
            let (txs, pool) = prepare_txs(i, 1000, &keys);
            let patch = execute_block(&blockchain, i, &txs, &pool);
            blockchain.merge(patch).unwrap();
        }

        let (txs, pool) = prepare_txs(100, 1000, &keys);

        b.iter(|| execute_block(&blockchain, 100, &txs, &pool));
    }

    fn create_rocksdb(tempdir: &TempDir) -> Box<Database> {
        let mut block_options = RocksBlockOptions::default();
        block_options.set_block_size(4 * 1024);
        block_options.set_lru_cache(512 * 1024 * 1024);
        block_options.set_bloom_filter(128, true);
        block_options.set_cache_index_and_filter_blocks(true);
        let mut options = RocksDBOptions::default();
        options.create_if_missing(true);
        options.increase_parallelism(4);
        options.set_max_write_buffer_number(16);
        options.set_write_buffer_size(536_870_912);
        options.set_max_open_files(-1);
        options.set_block_based_table_factory(&block_options);
        options.set_max_bytes_for_level_base(512 * 1024 * 1024);
        let db = Box::new(RocksDB::open(tempdir.path(), options).unwrap());
        db as Box<Database>
    }

    #[bench]
    fn bench_execute_block_timestamping_leveldb(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_timestamping_leveldb_cache(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        options.cache = Some(LevelDBCache::new(100_000_000));
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_leveldb(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_cryptocurrency(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_leveldb_cache(b: &mut Bencher) {
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        options.cache = Some(LevelDBCache::new(100_000_000));
        let path = TempDir::new("exonum").unwrap();
        let db = Box::new(LevelDB::open(path.path(), options).unwrap()) as Box<Database>;
        execute_cryptocurrency(db, b)
    }

    #[bench]
    fn bench_execute_block_timestamping_rocksdb(b: &mut Bencher) {
        let tempdir = TempDir::new("exonum").unwrap();
        let db = create_rocksdb(&tempdir);
        execute_timestamping(db, b)
    }

    #[bench]
    fn bench_execute_block_cryptocurrency_rocksdb(b: &mut Bencher) {
        let tempdir = TempDir::new("exonum").unwrap();
        let db = create_rocksdb(&tempdir);
        execute_cryptocurrency(db, b)
    }
}
<|endoftext|>


<commit_before>#![allow(
    clippy::eq_op,
    clippy::items_after_statements,
    clippy::shadow_unrelated,
    clippy::wildcard_imports
)]

mod common;

use self::common::*;
use anyhow::{anyhow, ensure};
use std::future;

#[test]
fn test_messages() {
    assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
    assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
    assert_eq!("oh no!", bail_error().unwrap_err().to_string());
}

#[test]
fn test_ensure() {
    let f = || {
        ensure!(1 + 1 == 2, "This is correct");
        Ok(())
    };
    assert!(f().is_ok());

    let v = 1;
    let f = || {
        ensure!(v + v == 2, "This is correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_ok());

    let f = || {
        ensure!(v + v == 1, "This is not correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_err());

    let f = || {
        ensure!(v + v == 1);
        Ok(())
    };
    assert_eq!(
        f().unwrap_err().to_string(),
        "Condition failed: `v + v == 1`",
    );
}

#[test]
fn test_temporaries() {
    fn require_send_sync(_: impl Send + Sync) {}

    require_send_sync(async {
        // If anyhow hasn't dropped any temporary format_args it creates by the
        // time it's done evaluating, those will stick around until the
        // semicolon, which is on the other side of the await point, making the
        // enclosing future non-Send.
        future::ready(anyhow!("...")).await;
    });
}

#[test]
fn test_brace_escape() {
    let err = anyhow!("unterminated ${{..}} expression");
    assert_eq!("unterminated ${..} expression", err.to_string());
}
<commit_msg>Ignore needless_pass_by_value Clippy pedantic lint in test suite<commit_after>#![allow(
    clippy::eq_op,
    clippy::items_after_statements,
    clippy::needless_pass_by_value,
    clippy::shadow_unrelated,
    clippy::wildcard_imports
)]

mod common;

use self::common::*;
use anyhow::{anyhow, ensure};
use std::future;

#[test]
fn test_messages() {
    assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
    assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
    assert_eq!("oh no!", bail_error().unwrap_err().to_string());
}

#[test]
fn test_ensure() {
    let f = || {
        ensure!(1 + 1 == 2, "This is correct");
        Ok(())
    };
    assert!(f().is_ok());

    let v = 1;
    let f = || {
        ensure!(v + v == 2, "This is correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_ok());

    let f = || {
        ensure!(v + v == 1, "This is not correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_err());

    let f = || {
        ensure!(v + v == 1);
        Ok(())
    };
    assert_eq!(
        f().unwrap_err().to_string(),
        "Condition failed: `v + v == 1`",
    );
}

#[test]
fn test_temporaries() {
    fn require_send_sync(_: impl Send + Sync) {}

    require_send_sync(async {
        // If anyhow hasn't dropped any temporary format_args it creates by the
        // time it's done evaluating, those will stick around until the
        // semicolon, which is on the other side of the await point, making the
        // enclosing future non-Send.
        future::ready(anyhow!("...")).await;
    });
}

#[test]
fn test_brace_escape() {
    let err = anyhow!("unterminated ${{..}} expression");
    assert_eq!("unterminated ${..} expression", err.to_string());
}
<|endoftext|>


<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! BitTorrent DHT implementation.

pub use self::krpc::KRpcService;

#[experimental]
mod krpc;
#[experimental]
pub mod protocol;
#[experimental]
pub mod udpwrapper;
<commit_msg>Export one more public type<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! BitTorrent DHT implementation.

pub use self::krpc::DefaultKRpcService;
pub use self::krpc::KRpcService;

#[experimental]
mod krpc;
#[experimental]
pub mod protocol;
#[experimental]
pub mod udpwrapper;
<|endoftext|>


<commit_before>use nalgebra::{normalize, cross, zero, Vec3, BaseFloat};

pub struct Camera {
    fov: f32,
    near: f32,
    far: f32,
    aspect_ratio: f32,
    pos: Vec3<f32>,
    look_at: Vec3<f32>,
}

impl Camera {
    pub fn new(pos: Vec3<f32>) -> Self {
        Camera { fov: BaseFloat::frac_pi_2(), near: 0.1, far: 1024., aspect_ratio: 4./3.,
                 pos: pos, look_at: zero() }
    }

    pub fn set_pos(&mut self, pos: Vec3<f32>) {
        self.pos = pos;
    }

    pub fn get_projection_matrix(&self) -> [[f32; 4]; 4] {
        let n = self.near;
        let f = self.far;

        let y = 1. / (self.fov / 2.).tan();
        let x = y * self.aspect_ratio;
        let a = (f + n) / (f - n);
        let b = (2. * f * n) / (f - n);

        [[x,  0., 0., 0.],
         [0., y,  0., 0.],
         [0., 0., a, -1.],
         [0., 0., b,  0.]]
    }

    pub fn get_view_matrix(&self) -> [[f32; 4]; 4] {
        // Forward vector
        let w = normalize(&(self.look_at - self.pos));
        let up = Vec3::new(0., 1., 0.);

        // The up vector cannot be parallel (in this case, the same) as the forward vector
        debug_assert!(w != up);

        // Right vector
        let u = normalize(&cross(&w, &up));

        // Up vector (we shouldn't need to normalize as the cross product of two orthogonal unit
        // vectors is a unit vector)
        let v = cross(&u, &w);

        [[u.x, v.x, -w.x, 0.],
         [u.y, v.y, -w.y, 0.],
         [u.z, v.z, -w.z, 0.],
         [-self.pos.x, -self.pos.y, -self.pos.z, 1.]]
    }
}
<commit_msg>Fix camera<commit_after>use nalgebra::{normalize, cross, zero, Vec3, BaseFloat};

pub struct Camera {
    fov: f32,
    near: f32,
    far: f32,
    aspect_ratio: f32,
    pos: Vec3<f32>,
    look_at: Vec3<f32>,
}

impl Camera {
    pub fn new(pos: Vec3<f32>) -> Self {
        Camera { fov: BaseFloat::frac_pi_2(), near: 0.1, far: 1024., aspect_ratio: 4./3.,
                 pos: pos, look_at: zero() }
    }

    pub fn set_pos(&mut self, pos: Vec3<f32>) {
        self.pos = pos;
    }

    pub fn get_projection_matrix(&self) -> [[f32; 4]; 4] {
        let n = self.near;
        let f = self.far;

        let y = 1. / (self.fov / 2.).tan();
        let x = y * self.aspect_ratio;
        let a = (f + n) / (n - f);
        let b = (2. * f * n) / (n - f);

        [[x,  0., 0., 0.],
         [0., y,  0., 0.],
         [0., 0., a, -1.],
         [0., 0., b,  0.]]
    }

    pub fn get_view_matrix(&self) -> [[f32; 4]; 4] {
        // Forward vector
        let w = normalize(&(self.look_at - self.pos));
        let up = Vec3::new(0., 1., 0.);

        // The up vector cannot be parallel (in this case, the same) as the forward vector
        debug_assert!(w != up);

        // Right vector
        let u = normalize(&cross(&w, &up));

        // Up vector (we shouldn't need to normalize as the cross product of two orthogonal unit
        // vectors is a unit vector)
        let v = cross(&u, &w);

        [[u.x, v.x, -w.x, 0.],
         [u.y, v.y, -w.y, 0.],
         [u.z, v.z, -w.z, 0.],
         [-self.pos.x, -self.pos.y, -self.pos.z, 1.]]
    }
}
<|endoftext|>


<commit_before>//canvas widget based on image widget

use image;
use orbtk;
use orbclient::{Color, Renderer};
use orbimage;
use std::cell::{Cell, RefCell};
use std::path::Path;
use std::sync::Arc;
use orbtk::event::Event;
use orbtk::point::Point;
use orbtk::rect::Rect;
use orbtk::traits::{Click, Place};
use orbtk::widgets::Widget;
use std::slice;
use std::io::Error;

use AddOnsToOrbimage;

pub struct Canvas {
    pub rect: Cell<Rect>,
    pub image: RefCell<orbimage::Image>,
    undo_image: RefCell<orbimage::Image>,
    click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
    right_click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
    clear_click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
}

impl Canvas {
    pub fn new(width: u32, height: u32) -> Arc<Self> {
        Self::from_image(orbimage::Image::new(width, height))
    }

    pub fn from_color(width: u32, height: u32, color: Color) -> Arc<Self> {
        Self::from_image(orbimage::Image::from_color(width, height, color))
    }

    pub fn from_image(image: orbimage::Image) -> Arc<Self> {
        Arc::new(Canvas {
            rect: Cell::new(Rect::new(0, 0, image.width(), image.height())),
            undo_image: RefCell::new(orbimage::Image::new(image.width(),image.height())),
            image: RefCell::new(image),
            click_callback: RefCell::new(None),
            right_click_callback: RefCell::new(None),
            clear_click_callback: RefCell::new(None)
        })
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Arc<Self>, String> {
        Ok(Self::from_image(orbimage::Image::from_path(path)?))
    }

    pub fn save(&self, filename: &String) -> Result <i32, Error>{
        let width = self.rect.get().width as u32;
        let height = self.rect.get().height as u32;
        //get image data in form of [Color] slice
        let image_data = self.image.clone().into_inner().into_data();

        // convert u32 values to 4 * u8 (r g b a) values
        let image_buffer = unsafe {
            slice::from_raw_parts(image_data.as_ptr() as *const u8, 4 * image_data.len())
        };
        //let () = image_buffer;
        //To save corectly the image with image::save_buffer
        // we have to switch r with b but dont know why!
        let mut new_image_buffer = Vec::new();
        let mut i = 0;
        while i <= image_buffer.len() - 4 {
            new_image_buffer.push(image_buffer[i + 2]);
            new_image_buffer.push(image_buffer[i + 1]);
            new_image_buffer.push(image_buffer[i]);
            new_image_buffer.push(image_buffer[i + 3]);
            i = i + 4;
        }

        if cfg!(feature = "debug"){
            println!("Saving {}", &filename);
            println!("x{} y{} len={}", width, height, image_data.len());
        }

        match image::save_buffer(&Path::new(&filename),
                           &new_image_buffer,
                           width,
                           height,
                           image::RGBA(8)){
                Ok(_)   => {
                            if cfg!(feature = "debug"){println!("Saved");}
                            Ok(0)
                            },
                Err(e) => {
                            if cfg!(feature = "debug"){println!("Error: {}",e);}
                            Err(e)
                            },

        }
    }

    pub fn clear(&self){
        //first prepare for undo
        self.undo_save();

       let mut image = self.image.borrow_mut();
       //image.clear();
       image.set(Color::rgba(255, 255, 255,255));
    }
/*
    ///draws image into curent canvas starting at x,y (paste)
    pub fn paste_selection (&self, x: i32, y:i32,buffer: orbimage::Image){
        let mut image = self.image.borrow_mut();

        let w = buffer.width() as i32;
        let h = buffer.height() as i32;
        let data = buffer.into_data();
        let mut i:usize = 0;
        let x1:i32;
        let y1:i32;

        for y1 in y..y+h {
            for x1 in x..x+w {
                if i < data.len(){
                    image.pixel(x1,y1,data[i]);
                }
                i += 1;
            }
        }
    }
*/

    //crop new image from curent canvas (copy)
    pub fn copy_selection(&self, x: i32,y: i32,w: u32, h: u32) -> orbimage::Image {
        let image = self.image.borrow();
        let data = image.data();
        let mut vec = vec![];

        for y1 in y..y+h as i32 {
            for x1 in x..x+w as i32 {
                vec.push(self.pixcol(x1,y1));
            }
        }
        //println!("len {} w*h {}",vec.len(), w*h);
        orbimage::Image::from_data(w ,h ,vec.into_boxed_slice()).unwrap()
    }

    ///return rgba color of pixel at canvas position (x,y)
    pub fn pixcol(&self, x:i32, y:i32) -> Color {
        let image = self.image.borrow();
        let p = image.width()as i32 * y + x;
        let rgba = image.data()[p as usize];
        rgba
    }

    ///apply some transformations to entire canvas
    pub fn transformation(&self, cod: &str, a: i32, b:i32){
        //first prepare for undo
        self.undo_save();

        //using image::imageops library
        let mut width = self.rect.get().width as u32;
        let mut height = self.rect.get().height as u32;
        //get image data in form of [Color] slice
        let image_data = self.image.clone().into_inner().into_data();//mut

        let image_buffer = unsafe {
            slice::from_raw_parts(image_data.as_ptr() as *const u8, 4 * image_data.len())
        };

        let imgbuf : image::ImageBuffer<image::Rgba<u8>, _> = image::ImageBuffer::from_raw(width as u32, height as u32, image_buffer.to_vec()).unwrap();
        let vec_image_buffer:Vec<u8> = image::ImageBuffer::into_raw ( match cod.as_ref() {

                                                             "blur"            => image::imageops::blur(&imgbuf,5.1),
                                                             "unsharpen"       => image::imageops::unsharpen(&imgbuf,5.1,10),
                                                             "flip_vertical"   => image::imageops::flip_vertical(&imgbuf),
                                                             "flip_horizontal" => image::imageops::flip_horizontal(&imgbuf),
                                                             "brighten"        => image::imageops::colorops::brighten(&imgbuf, 10),
                                                             "darken"          => image::imageops::colorops::brighten(&imgbuf, -10),
                                                             "grayscale"       => self.gray2rgba(image::imageops::colorops::grayscale(&imgbuf),
                                                                                1.2,1.2,1.2),
                                                             "resize"          => { width = a as u32;
                                                                                height = b as u32;
                                                                                self.image.borrow_mut().clear();
                                                                 image::imageops::resize(&imgbuf,a as u32,b as u32,image::FilterType::Nearest)
                                                                 },
                                                                             _ => imgbuf,
         });

        //convert rgba 8u image buffer back into Color slice
        let mut i = 0 ;
        let mut r: u8 ;
        let mut g: u8 ;
        let mut b: u8 ;
        let mut a: u8 ;
        let mut new_slice = Vec::new();
        while i <= vec_image_buffer.len() - 4 {

            r = vec_image_buffer[i];
            g = vec_image_buffer[i+1];
            b = vec_image_buffer[i+2];
            a = vec_image_buffer[i+3];
            new_slice.push(orbtk::Color::rgba(b, g, r, a)); //taking care of wird bug
            i += 4;
        }

        let mut image = self.image.borrow_mut();
        //image.clear();
        image.image(0,0,width,height,&new_slice[..]);

    }

/// convert grayscale image to rgba format
    fn gray2rgba (&self,
                    grayimage: image::ImageBuffer<image::Luma<u8>, Vec<u8>>,
                    r_factor : f32,
                    g_factor : f32,
                    b_factor : f32
                    )
                    -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
        let mut r: u8 ;
        let mut g: u8 ;
        let mut b: u8 ;
        let mut a: u8 ;
        let mut new_buffer = Vec::new();
        let width = grayimage.width();
        let height = grayimage.height();

        for luma in image::ImageBuffer::into_raw (grayimage) {

            if luma == 255 {
                r=255;
                g=255;
                b=255;
            }else{
            r = (luma as f32 / r_factor) as u8;
            g = (luma as f32 / g_factor) as u8;
            b = (luma as f32 / b_factor) as u8;
            }
            a = 255;
            new_buffer.push(b);
            new_buffer.push(g);
            new_buffer.push(r);
            new_buffer.push(a);

        }
        let imgbuf : image::ImageBuffer<image::Rgba<u8>, _> = image::ImageBuffer::from_raw(width as u32, height as u32, new_buffer).unwrap();
            imgbuf
    }

    pub fn on_right_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.right_click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
    pub fn emit_right_click(&self, point: Point) {
        if let Some(ref right_click_callback) = *self.right_click_callback.borrow() {
            right_click_callback(self, point);
        }
    }

    pub fn on_clear_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.clear_click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }

    pub fn emit_clear_click(&self, point: Point) {
        if let Some(ref clear_click_callback) = *self.clear_click_callback.borrow() {
            clear_click_callback(self, point);
        }
    }

    /// simple undo
    pub fn undo(&self) {
        let mut image = self.image.borrow_mut();
        let undo_image = self.undo_image.borrow_mut();
        *image=undo_image.clone();
    }

    /// save image state to be used if undo is required
    pub fn undo_save(&self) {
        //copy current image to undo_image
        let image = self.image.borrow_mut();
        let mut undo_image = self.undo_image.borrow_mut();
        *undo_image=image.clone();
    }

    ///wrapper for filling an image within a canvas
    pub fn fill (&self, x: i32 , y: i32, color: Color){
        self.undo_save();  //save state for undo
        let mut image = self.image.borrow_mut();
        image.fill(x,y,color);
    }

    /// wrapper for paste_selection
    pub fn paste_selection (&self, x: i32, y:i32, opacity: u8, buffer: orbimage::Image, ){
        self.undo_save();  //save state for undo
        let mut image = self.image.borrow_mut();
        image.paste_selection(x,y,opacity,buffer);
    }

}

impl Click for Canvas {
    fn emit_click(&self, point: Point) {
        if let Some(ref click_callback) = *self.click_callback.borrow() {
            click_callback(self, point);
        }
    }

    fn on_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }

}

impl Place for Canvas {}

impl Widget for Canvas {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let rect = self.rect.get();
        let image = self.image.borrow();
        renderer.image(rect.x, rect.y, image.width(), image.height(), image.data());
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
         /*   Event::Mouse { point, left_button, .. } => {
                let rect = self.rect.get();
                if rect.contains(point) && left_button {
                    let click_point: Point = point - rect.point();
                    self.emit_click(click_point);
                    *redraw = true;
                }
            }*/

            Event::Mouse {point, right_button, left_button, middle_button, ..} => {
                let rect = self.rect.get();
                if rect.contains(point) {
                    let click_point: Point = point - rect.point();
                    if right_button {
                        //println!("Right_button");
                        let click_point: Point = point - rect.point();
                        self.emit_right_click(click_point);
                        *redraw = true;
                        }
                    if left_button {
                        let click_point: Point = point - rect.point();
                        self.emit_click(click_point);
                        *redraw = true;
                        }
                    if middle_button {println!("Middle_button");}
                    //mouse is moving without clicking, emit clear previous click position
                    if !right_button && !left_button && !middle_button {
                        let click_point= Point{x:0,y:0};
                        self.emit_clear_click(click_point);
                    }

                    }
                }
            _ => if cfg!(feature = "debug"){println!("CanvasEvent: {:?}", event)} else {()},
        }

        focused
    }

    fn visible(&self, flag: bool){
        !flag;
    }

}
<commit_msg>undo shortcut<commit_after>//canvas widget based on image widget

use image;
use orbtk;
use orbclient::{Color, Renderer};
use orbimage;
use std::cell::{Cell, RefCell};
use std::path::Path;
use std::sync::Arc;
use orbtk::event::Event;
use orbtk::point::Point;
use orbtk::rect::Rect;
use orbtk::traits::{Click, Place};
use orbtk::widgets::Widget;
use std::slice;
use std::io::Error;

use AddOnsToOrbimage;

pub struct Canvas {
    pub rect: Cell<Rect>,
    pub image: RefCell<orbimage::Image>,
    undo_image: RefCell<orbimage::Image>,
    click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
    right_click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
    clear_click_callback: RefCell<Option<Arc<Fn(&Canvas, Point)>>>,
}

impl Canvas {
    pub fn new(width: u32, height: u32) -> Arc<Self> {
        Self::from_image(orbimage::Image::new(width, height))
    }

    pub fn from_color(width: u32, height: u32, color: Color) -> Arc<Self> {
        Self::from_image(orbimage::Image::from_color(width, height, color))
    }

    pub fn from_image(image: orbimage::Image) -> Arc<Self> {
        Arc::new(Canvas {
            rect: Cell::new(Rect::new(0, 0, image.width(), image.height())),
            undo_image: RefCell::new(orbimage::Image::new(image.width(),image.height())),
            image: RefCell::new(image),
            click_callback: RefCell::new(None),
            right_click_callback: RefCell::new(None),
            clear_click_callback: RefCell::new(None)
        })
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Arc<Self>, String> {
        Ok(Self::from_image(orbimage::Image::from_path(path)?))
    }

    pub fn save(&self, filename: &String) -> Result <i32, Error>{
        let width = self.rect.get().width as u32;
        let height = self.rect.get().height as u32;
        //get image data in form of [Color] slice
        let image_data = self.image.clone().into_inner().into_data();

        // convert u32 values to 4 * u8 (r g b a) values
        let image_buffer = unsafe {
            slice::from_raw_parts(image_data.as_ptr() as *const u8, 4 * image_data.len())
        };
        //let () = image_buffer;
        //To save corectly the image with image::save_buffer
        // we have to switch r with b but dont know why!
        let mut new_image_buffer = Vec::new();
        let mut i = 0;
        while i <= image_buffer.len() - 4 {
            new_image_buffer.push(image_buffer[i + 2]);
            new_image_buffer.push(image_buffer[i + 1]);
            new_image_buffer.push(image_buffer[i]);
            new_image_buffer.push(image_buffer[i + 3]);
            i = i + 4;
        }

        if cfg!(feature = "debug"){
            println!("Saving {}", &filename);
            println!("x{} y{} len={}", width, height, image_data.len());
        }

        match image::save_buffer(&Path::new(&filename),
                           &new_image_buffer,
                           width,
                           height,
                           image::RGBA(8)){
                Ok(_)   => {
                            if cfg!(feature = "debug"){println!("Saved");}
                            Ok(0)
                            },
                Err(e) => {
                            if cfg!(feature = "debug"){println!("Error: {}",e);}
                            Err(e)
                            },

        }
    }

    pub fn clear(&self){
        //first prepare for undo
        self.undo_save();

       let mut image = self.image.borrow_mut();
       //image.clear();
       image.set(Color::rgba(255, 255, 255,255));
    }
/*
    ///draws image into curent canvas starting at x,y (paste)
    pub fn paste_selection (&self, x: i32, y:i32,buffer: orbimage::Image){
        let mut image = self.image.borrow_mut();

        let w = buffer.width() as i32;
        let h = buffer.height() as i32;
        let data = buffer.into_data();
        let mut i:usize = 0;
        let x1:i32;
        let y1:i32;

        for y1 in y..y+h {
            for x1 in x..x+w {
                if i < data.len(){
                    image.pixel(x1,y1,data[i]);
                }
                i += 1;
            }
        }
    }
*/

    //crop new image from curent canvas (copy)
    pub fn copy_selection(&self, x: i32,y: i32,w: u32, h: u32) -> orbimage::Image {
        let image = self.image.borrow();
        let data = image.data();
        let mut vec = vec![];

        for y1 in y..y+h as i32 {
            for x1 in x..x+w as i32 {
                vec.push(self.pixcol(x1,y1));
            }
        }
        //println!("len {} w*h {}",vec.len(), w*h);
        orbimage::Image::from_data(w ,h ,vec.into_boxed_slice()).unwrap()
    }

    ///return rgba color of pixel at canvas position (x,y)
    pub fn pixcol(&self, x:i32, y:i32) -> Color {
        let image = self.image.borrow();
        let p = image.width()as i32 * y + x;
        let rgba = image.data()[p as usize];
        rgba
    }

    ///apply some transformations to entire canvas
    pub fn transformation(&self, cod: &str, a: i32, b:i32){
        //first prepare for undo
        self.undo_save();

        //using image::imageops library
        let mut width = self.rect.get().width as u32;
        let mut height = self.rect.get().height as u32;
        //get image data in form of [Color] slice
        let image_data = self.image.clone().into_inner().into_data();//mut

        let image_buffer = unsafe {
            slice::from_raw_parts(image_data.as_ptr() as *const u8, 4 * image_data.len())
        };

        let imgbuf : image::ImageBuffer<image::Rgba<u8>, _> = image::ImageBuffer::from_raw(width as u32, height as u32, image_buffer.to_vec()).unwrap();
        let vec_image_buffer:Vec<u8> = image::ImageBuffer::into_raw ( match cod.as_ref() {

                                                             "blur"            => image::imageops::blur(&imgbuf,5.1),
                                                             "unsharpen"       => image::imageops::unsharpen(&imgbuf,5.1,10),
                                                             "flip_vertical"   => image::imageops::flip_vertical(&imgbuf),
                                                             "flip_horizontal" => image::imageops::flip_horizontal(&imgbuf),
                                                             "brighten"        => image::imageops::colorops::brighten(&imgbuf, 10),
                                                             "darken"          => image::imageops::colorops::brighten(&imgbuf, -10),
                                                             "grayscale"       => self.gray2rgba(image::imageops::colorops::grayscale(&imgbuf),
                                                                                1.2,1.2,1.2),
                                                             "resize"          => { width = a as u32;
                                                                                height = b as u32;
                                                                                self.image.borrow_mut().clear();
                                                                                image::imageops::resize(&imgbuf,a as u32,b as u32,image::FilterType::Nearest)
                                                                                },
                                                                             _ => imgbuf,
         });

        //convert rgba 8u image buffer back into Color slice
        let mut i = 0 ;
        let mut r: u8 ;
        let mut g: u8 ;
        let mut b: u8 ;
        let mut a: u8 ;
        let mut new_slice = Vec::new();
        while i <= vec_image_buffer.len() - 4 {

            r = vec_image_buffer[i];
            g = vec_image_buffer[i+1];
            b = vec_image_buffer[i+2];
            a = vec_image_buffer[i+3];
            new_slice.push(orbtk::Color::rgba(b, g, r, a)); //taking care of wird bug
            i += 4;
        }

        let mut image = self.image.borrow_mut();
        //image.clear();
        image.image(0,0,width,height,&new_slice[..]);

    }

/// convert grayscale image to rgba format
    fn gray2rgba (&self,
                    grayimage: image::ImageBuffer<image::Luma<u8>, Vec<u8>>,
                    r_factor : f32,
                    g_factor : f32,
                    b_factor : f32
                    )
                    -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
        let mut r: u8 ;
        let mut g: u8 ;
        let mut b: u8 ;
        let mut a: u8 ;
        let mut new_buffer = Vec::new();
        let width = grayimage.width();
        let height = grayimage.height();

        for luma in image::ImageBuffer::into_raw (grayimage) {

            if luma == 255 {
                r=255;
                g=255;
                b=255;
            }else{
            r = (luma as f32 / r_factor) as u8;
            g = (luma as f32 / g_factor) as u8;
            b = (luma as f32 / b_factor) as u8;
            }
            a = 255;
            new_buffer.push(b);
            new_buffer.push(g);
            new_buffer.push(r);
            new_buffer.push(a);

        }
        let imgbuf : image::ImageBuffer<image::Rgba<u8>, _> = image::ImageBuffer::from_raw(width as u32, height as u32, new_buffer).unwrap();
            imgbuf
    }

    pub fn on_right_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.right_click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
    pub fn emit_right_click(&self, point: Point) {
        if let Some(ref right_click_callback) = *self.right_click_callback.borrow() {
            right_click_callback(self, point);
        }
    }

    pub fn on_clear_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.clear_click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }

    pub fn emit_clear_click(&self, point: Point) {
        if let Some(ref clear_click_callback) = *self.clear_click_callback.borrow() {
            clear_click_callback(self, point);
        }
    }

    /// simple undo
    pub fn undo(&self) {
        let mut image = self.image.borrow_mut();
        let undo_image = self.undo_image.borrow_mut();
        *image=undo_image.clone();
    }

    /// save image state to be used if undo is required
    pub fn undo_save(&self) {
        //copy current image to undo_image
        let image = self.image.borrow_mut();
        let mut undo_image = self.undo_image.borrow_mut();
        *undo_image=image.clone();
    }

    ///wrapper for filling an image within a canvas
    pub fn fill (&self, x: i32 , y: i32, color: Color){
        self.undo_save();  //save state for undo
        let mut image = self.image.borrow_mut();
        image.fill(x,y,color);
    }

    /// wrapper for paste_selection
    pub fn paste_selection (&self, x: i32, y:i32, opacity: u8, buffer: orbimage::Image, ){
        self.undo_save();  //save state for undo
        let mut image = self.image.borrow_mut();
        image.paste_selection(x,y,opacity,buffer);
    }

}

impl Click for Canvas {
    fn emit_click(&self, point: Point) {
        if let Some(ref click_callback) = *self.click_callback.borrow() {
            click_callback(self, point);
        }
    }

    fn on_click<T: Fn(&Self, Point) + 'static>(&self, func: T) -> &Self {
        *self.click_callback.borrow_mut() = Some(Arc::new(func));
        self
    }

}

impl Place for Canvas {}

impl Widget for Canvas {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let rect = self.rect.get();
        let image = self.image.borrow();
        renderer.image(rect.x, rect.y, image.width(), image.height(), image.data());
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
         /*   Event::Mouse { point, left_button, .. } => {
                let rect = self.rect.get();
                if rect.contains(point) && left_button {
                    let click_point: Point = point - rect.point();
                    self.emit_click(click_point);
                    *redraw = true;
                }
            }*/

            Event::Mouse {point, right_button, left_button, middle_button, ..} => {
                let rect = self.rect.get();
                if rect.contains(point) {
                    let click_point: Point = point - rect.point();
                    if right_button {
                        //println!("Right_button");
                        let click_point: Point = point - rect.point();
                        self.emit_right_click(click_point);
                        *redraw = true;
                        }
                    if left_button {
                        let click_point: Point = point - rect.point();
                        self.emit_click(click_point);
                        *redraw = true;
                        }
                    if middle_button {println!("Middle_button");}
                    //mouse is moving without clicking, emit clear previous click position
                    if !right_button && !left_button && !middle_button {
                        let click_point= Point{x:0,y:0};
                        self.emit_clear_click(click_point);
                    }

                    }
                },
             // Ctrl+z
            Event::Text {c} => {
                if c == 'z' {
                    self.undo();
                    *redraw = true;
                }
            },
            _ => if cfg!(feature = "debug"){println!("CanvasEvent: {:?}", event)} else {()},
        }

        focused
    }

    fn visible(&self, flag: bool){
        !flag;
    }

}
<|endoftext|>