<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use gc_error::{GcError, Result};
use js_types::js_var::JsPtrEnum;
use js_types::allocator::Allocator;
use js_types::binding::Binding;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Binding, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Binding, Alloc<JsPtrEnum>>,
    white_set: HashMap<Binding, Alloc<JsPtrEnum>>,
}

impl Allocator for AllocBox {
    type Error = GcError;

    fn alloc(&mut self, binding: Binding, ptr: JsPtrEnum) -> Result<()> {
        if let None = self.white_set.insert(binding.clone(), Rc::new(RefCell::new(ptr))) {
            Ok(())
        } else {
            // If a binding already exists and we try to allocate it, this should
            // be an unrecoverable error.
            Err(GcError::AllocError(binding))
        }
    }
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn mark_roots(&mut self, marks: &HashSet<Binding>) {
        for mark in marks {
            if let Some(ptr) = self.white_set.remove(mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark.clone(), ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            } else if let Some(ptr) = self.grey_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark.clone(), ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (bnd, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(bnd, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.drain().collect();
        self.grey_set.clear();
        self.black_set.clear();
    }

    pub fn find_id(&self, bnd: &Binding) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(bnd).or(
            self.grey_set.get(bnd).or(
                self.black_set.get(bnd)))
    }

    pub fn update_ptr(&mut self, binding: &Binding, ptr: JsPtrEnum) -> Result<()> {
        if let Entry::Occupied(mut view) = self.find_id_mut(binding) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            Ok(())
        } else {
            Err(GcError::StoreError)
        }
    }

    fn grey_children(&mut self, child_ids: HashSet<Binding>) {
        for child_id in child_ids {
            if let Some(var) = self.white_set.remove(&child_id) {
                self.grey_set.insert(child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Binding> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, bnd: &Binding) -> Entry<Binding, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(bnd.clone()) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(bnd.clone()) {
            e
        } else { self.black_set.entry(bnd.clone()) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;

    use gc_error::GcError;
    use js_types::allocator::Allocator;
    use js_types::binding::Binding;
    use js_types::js_var::JsPtrEnum;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert_eq!(ab.is_empty());
        assert!(ab.alloc(Binding::anon(), test_utils::make_str("").1).is_ok());
        assert_eq!(ab.len(), 1);
    }

    #[test]
    fn test_alloc() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let (_, y_ptr, y_bnd) = test_utils::make_str("y");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        assert!(ab.alloc(y_bnd, y_ptr).is_ok());
    }

    #[test]
    fn test_alloc_fail() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        let res = ab.alloc(x_bnd_2, x_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::AllocError(x_bnd_2))));
    }

    #[test]
    fn test_update_ptr() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        let (_, new_ptr, _) = test_utils::make_str("y");
        assert!(ab.update_ptr(&x_bnd_2, new_ptr).is_ok());
        let opt_ptr = ab.find_id(&x_bnd_2);
        assert!(opt_ptr.is_some());
        // Hack to get around some borrowck failures I don't fully understand
        if let Some(ptr) = opt_ptr {
            match ptr.borrow().clone() {
                JsPtrEnum::JsStr(JsStrStruct { ref text }) => assert_eq!(text.clone(), "y".to_string()),
                _ => unreachable!(),
            }
        } else {
            unreachable!()
        }
    }

    #[test]
    fn test_update_ptr_fail() {
        let mut ab = AllocBox::new();
        let (_, ptr, _) = test_utils::make_str("");
        let res = ab.update_ptr(&Binding::anon(), ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::StoreError)));
    }

    #[test]
    fn test_mark_roots() {
        let mut ab = AllocBox::new();
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        let (y, y_ptr, y_bnd) = test_utils::make_str("y");

        ab.alloc(x.binding, x_ptr).unwrap();
        ab.alloc(y.binding, y_ptr).unwrap();

        let mut marks = HashSet::new();
        marks.insert(x_bnd.clone()); marks.insert(y_bnd.clone());
        ab.mark_roots(&marks);
        assert!(ab.black_set.contains_key(&x_bnd));
        assert!(ab.black_set.contains_key(&y_bnd));
    }
}
<commit_msg>Fix broken test<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use gc_error::{GcError, Result};
use js_types::js_var::JsPtrEnum;
use js_types::allocator::Allocator;
use js_types::binding::Binding;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Binding, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Binding, Alloc<JsPtrEnum>>,
    white_set: HashMap<Binding, Alloc<JsPtrEnum>>,
}

impl Allocator for AllocBox {
    type Error = GcError;

    fn alloc(&mut self, binding: Binding, ptr: JsPtrEnum) -> Result<()> {
        if let None = self.white_set.insert(binding.clone(), Rc::new(RefCell::new(ptr))) {
            Ok(())
        } else {
            // If a binding already exists and we try to allocate it, this should
            // be an unrecoverable error.
            Err(GcError::AllocError(binding))
        }
    }
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn mark_roots(&mut self, marks: &HashSet<Binding>) {
        for mark in marks {
            if let Some(ptr) = self.white_set.remove(mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark.clone(), ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            } else if let Some(ptr) = self.grey_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark.clone(), ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (bnd, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(bnd, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.drain().collect();
        self.grey_set.clear();
        self.black_set.clear();
    }

    pub fn find_id(&self, bnd: &Binding) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(bnd).or(
            self.grey_set.get(bnd).or(
                self.black_set.get(bnd)))
    }

    pub fn update_ptr(&mut self, binding: &Binding, ptr: JsPtrEnum) -> Result<()> {
        if let Entry::Occupied(mut view) = self.find_id_mut(binding) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            Ok(())
        } else {
            Err(GcError::StoreError)
        }
    }

    fn grey_children(&mut self, child_ids: HashSet<Binding>) {
        for child_id in child_ids {
            if let Some(var) = self.white_set.remove(&child_id) {
                self.grey_set.insert(child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Binding> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, bnd: &Binding) -> Entry<Binding, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(bnd.clone()) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(bnd.clone()) {
            e
        } else { self.black_set.entry(bnd.clone()) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;

    use gc_error::GcError;
    use js_types::allocator::Allocator;
    use js_types::binding::Binding;
    use js_types::js_var::JsPtrEnum;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert!(ab.is_empty());
        assert!(ab.alloc(Binding::anon(), test_utils::make_str("").1).is_ok());
        assert_eq!(ab.len(), 1);
    }

    #[test]
    fn test_alloc() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let (_, y_ptr, y_bnd) = test_utils::make_str("y");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        assert!(ab.alloc(y_bnd, y_ptr).is_ok());
    }

    #[test]
    fn test_alloc_fail() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        let res = ab.alloc(x_bnd_2, x_ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::AllocError(x_bnd_2))));
    }

    #[test]
    fn test_update_ptr() {
        let mut ab = AllocBox::new();
        let (_, x_ptr, x_bnd) = test_utils::make_str("x");
        let x_bnd_2 = x_bnd.clone();
        assert!(ab.alloc(x_bnd, x_ptr.clone()).is_ok());
        let (_, new_ptr, _) = test_utils::make_str("y");
        assert!(ab.update_ptr(&x_bnd_2, new_ptr).is_ok());
        let opt_ptr = ab.find_id(&x_bnd_2);
        assert!(opt_ptr.is_some());
        // Hack to get around some borrowck failures I don't fully understand
        if let Some(ptr) = opt_ptr {
            match ptr.borrow().clone() {
                JsPtrEnum::JsStr(JsStrStruct { ref text }) => assert_eq!(text.clone(), "y".to_string()),
                _ => unreachable!(),
            }
        } else {
            unreachable!()
        }
    }

    #[test]
    fn test_update_ptr_fail() {
        let mut ab = AllocBox::new();
        let (_, ptr, _) = test_utils::make_str("");
        let res = ab.update_ptr(&Binding::anon(), ptr);
        assert!(res.is_err());
        assert!(matches!(res, Err(GcError::StoreError)));
    }

    #[test]
    fn test_mark_roots() {
        let mut ab = AllocBox::new();
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        let (y, y_ptr, y_bnd) = test_utils::make_str("y");

        ab.alloc(x.binding, x_ptr).unwrap();
        ab.alloc(y.binding, y_ptr).unwrap();

        let mut marks = HashSet::new();
        marks.insert(x_bnd.clone()); marks.insert(y_bnd.clone());
        ab.mark_roots(&marks);
        assert!(ab.black_set.contains_key(&x_bnd));
        assert!(ab.black_set.contains_key(&y_bnd));
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly",
            feature(duration_span))]

extern crate crossbeam;

use std::collections::VecDeque;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::time::Duration;

use crossbeam::scope;
use crossbeam::sync::MsQueue;
use crossbeam::sync::SegQueue;

use extra_impls::mpsc_queue::Queue as MpscQueue;

mod extra_impls;

const COUNT: u64 = 10000000;
const THREADS: u64 = 2;

#[cfg(feature = "nightly")]
fn time<F: FnOnce()>(f: F) -> Duration {
    Duration::span(f)
}

#[cfg(not(feature = "nightly"))]
fn time<F: FnOnce()>(_f: F) -> Duration {
    Duration::new(0, 0)
}

fn nanos(d: Duration) -> f64 {
    d.as_secs() as f64 * 1000000000f64 + (d.subsec_nanos() as f64)
}

trait Queue<T> {
    fn push(&self, T);
    fn try_pop(&self) -> Option<T>;
}

impl<T> Queue<T> for MsQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> { self.try_pop() }
}

impl<T> Queue<T> for SegQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> { self.try_pop() }
}

impl<T> Queue<T> for MpscQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> {
        use extra_impls::mpsc_queue::*;

        loop {
            match self.pop() {
                Data(t) => return Some(t),
                Empty => return None,
                Inconsistent => (),
            }
        }
    }
}

impl<T> Queue<T> for Mutex<VecDeque<T>> {
    fn push(&self, t: T) { self.lock().unwrap().push_back(t) }
    fn try_pop(&self) -> Option<T> { self.lock().unwrap().pop_front() }
}

fn bench_queue_mpsc<Q: Queue<u64> + Sync>(q: Q) -> f64 {
    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let qr = &q;
                scope.spawn(move || {
                    for x in 0..COUNT {
                        let _ = qr.push(x);
                    }
                });
            }

            let mut count = 0;
            while count < COUNT*THREADS {
                if q.try_pop().is_some() {
                    count += 1;
                }
            }
        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn bench_queue_mpmc<Q: Queue<bool> + Sync>(q: Q) -> f64 {
    use std::sync::atomic::AtomicUsize;
    use std::sync::atomic::Ordering::Relaxed;

    let prod_count = AtomicUsize::new(0);

    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let qr = &q;
                let pcr = &prod_count;
                scope.spawn(move || {
                    for _x in 0..COUNT {
                        qr.push(true);
                    }
                    if pcr.fetch_add(1, Relaxed) == (THREADS as usize) - 1 {
                        for _x in 0..THREADS {
                            qr.push(false)
                        }
                    }
                });
                scope.spawn(move || {
                    loop {
                        if let Some(false) = qr.try_pop() { break }
                    }
                });
            }

        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn bench_chan_mpsc() -> f64 {
    let (tx, rx) = channel();

    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let my_tx = tx.clone();

                scope.spawn(move || {
                    for x in 0..COUNT {
                        let _ = my_tx.send(x);
                    }
                });
            }

            for _i in 0..COUNT*THREADS {
                let _ = rx.recv().unwrap();
            }
        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn main() {
    println!("MSQ mpsc: {}", bench_queue_mpsc(MsQueue::new()));
    println!("chan mpsc: {}", bench_chan_mpsc());
    println!("mpsc mpsc: {}", bench_queue_mpsc(MpscQueue::new()));
    println!("Seg mpsc: {}", bench_queue_mpsc(SegQueue::new()));

    println!("MSQ mpmc: {}", bench_queue_mpmc(MsQueue::new()));
    println!("Seg mpmc: {}", bench_queue_mpmc(SegQueue::new()));

//    println!("queue_mpsc: {}", bench_queue_mpsc());
//    println!("queue_mpmc: {}", bench_queue_mpmc());
//   println!("mutex_mpmc: {}", bench_mutex_mpmc());
}
<commit_msg>Remove use of `span`<commit_after>extern crate crossbeam;

use std::collections::VecDeque;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::time::Duration;

use crossbeam::scope;
use crossbeam::sync::MsQueue;
use crossbeam::sync::SegQueue;

use extra_impls::mpsc_queue::Queue as MpscQueue;

mod extra_impls;

const COUNT: u64 = 10000000;
const THREADS: u64 = 2;

#[cfg(feature = "nightly")]
fn time<F: FnOnce()>(f: F) -> Duration {
    let start = ::std::time::Instant::now();
    f();
    start.elapsed()
}

#[cfg(not(feature = "nightly"))]
fn time<F: FnOnce()>(_f: F) -> Duration {
    Duration::new(0, 0)
}

fn nanos(d: Duration) -> f64 {
    d.as_secs() as f64 * 1000000000f64 + (d.subsec_nanos() as f64)
}

trait Queue<T> {
    fn push(&self, T);
    fn try_pop(&self) -> Option<T>;
}

impl<T> Queue<T> for MsQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> { self.try_pop() }
}

impl<T> Queue<T> for SegQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> { self.try_pop() }
}

impl<T> Queue<T> for MpscQueue<T> {
    fn push(&self, t: T) { self.push(t) }
    fn try_pop(&self) -> Option<T> {
        use extra_impls::mpsc_queue::*;

        loop {
            match self.pop() {
                Data(t) => return Some(t),
                Empty => return None,
                Inconsistent => (),
            }
        }
    }
}

impl<T> Queue<T> for Mutex<VecDeque<T>> {
    fn push(&self, t: T) { self.lock().unwrap().push_back(t) }
    fn try_pop(&self) -> Option<T> { self.lock().unwrap().pop_front() }
}

fn bench_queue_mpsc<Q: Queue<u64> + Sync>(q: Q) -> f64 {
    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let qr = &q;
                scope.spawn(move || {
                    for x in 0..COUNT {
                        let _ = qr.push(x);
                    }
                });
            }

            let mut count = 0;
            while count < COUNT*THREADS {
                if q.try_pop().is_some() {
                    count += 1;
                }
            }
        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn bench_queue_mpmc<Q: Queue<bool> + Sync>(q: Q) -> f64 {
    use std::sync::atomic::AtomicUsize;
    use std::sync::atomic::Ordering::Relaxed;

    let prod_count = AtomicUsize::new(0);

    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let qr = &q;
                let pcr = &prod_count;
                scope.spawn(move || {
                    for _x in 0..COUNT {
                        qr.push(true);
                    }
                    if pcr.fetch_add(1, Relaxed) == (THREADS as usize) - 1 {
                        for _x in 0..THREADS {
                            qr.push(false)
                        }
                    }
                });
                scope.spawn(move || {
                    loop {
                        if let Some(false) = qr.try_pop() { break }
                    }
                });
            }

        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn bench_chan_mpsc() -> f64 {
    let (tx, rx) = channel();

    let d = time(|| {
        scope(|scope| {
            for _i in 0..THREADS {
                let my_tx = tx.clone();

                scope.spawn(move || {
                    for x in 0..COUNT {
                        let _ = my_tx.send(x);
                    }
                });
            }

            for _i in 0..COUNT*THREADS {
                let _ = rx.recv().unwrap();
            }
        });
    });

    nanos(d) / ((COUNT * THREADS) as f64)
}

fn main() {
    println!("MSQ mpsc: {}", bench_queue_mpsc(MsQueue::new()));
    println!("chan mpsc: {}", bench_chan_mpsc());
    println!("mpsc mpsc: {}", bench_queue_mpsc(MpscQueue::new()));
    println!("Seg mpsc: {}", bench_queue_mpsc(SegQueue::new()));

    println!("MSQ mpmc: {}", bench_queue_mpmc(MsQueue::new()));
    println!("Seg mpmc: {}", bench_queue_mpmc(SegQueue::new()));

//    println!("queue_mpsc: {}", bench_queue_mpsc());
//    println!("queue_mpmc: {}", bench_queue_mpmc());
//   println!("mutex_mpmc: {}", bench_mutex_mpmc());
}
<|endoftext|>


<commit_before>use bounded_spsc_queue::{Consumer};
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;
use osc::osc_sender::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::thread;
use std::thread::{JoinHandle};
use std::sync::{Arc, Mutex};
use itertools::Itertools;

const OSC_PER_SEC : usize = 30usize;

#[derive(Clone, Debug)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}

fn index_magnitudes(mags : &Vec<f32>) -> Vec<IndexedMagnitude> {
    let mut indexed = vec!();
    let mut i = 0usize;
    for mag in mags {
        indexed.push(IndexedMagnitude{index : i, magnitude : *mag});
        i += 1usize;
    }
    indexed
}

fn pitch_detect(buckets : &Vec<f32>, fs : usize) -> Option<f32> {
    //  1 indexed
    //  filter to peaks
    if let Some(peak) = first_peak(&find_peaks(&index_magnitudes(buckets), 1./10.).0, 1./10.) {
        return Some((peak.index * fs) as f32 / (buckets.len() as f32 * 2.0));
    }
    None
}

fn idx_to_freq(idx : usize, n : usize, fs : usize) -> f32 {
    (idx * fs) as f32 / n as f32
}

fn bkt_to_freq(bkt : &IndexedMagnitude, buckets : usize, fs : usize) -> f32 {
    idx_to_freq(bkt.index, buckets, fs)
}

fn compute_dissonance(buckets : &Vec<f32>, fs : usize) -> f32{
    let (mut peaks, _) = find_peaks(&find_peaks(&index_magnitudes(buckets), 1./12.).0, 1./12.);
    peaks.sort_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
    if peaks.len() < 3 {
        return 0.;
    }
    let f1 = bkt_to_freq(&peaks[0], buckets.len() * 2, fs);
    let f2 = bkt_to_freq(&peaks[1], buckets.len() * 2, fs);
    let f3 = bkt_to_freq(&peaks[2], buckets.len() * 2, fs);
    let d1 = f2 / f1;
    let d2 = f3 / f1;

    let fd1 = (d1 - d1.floor() - 0.5).abs() * 2.;
    let fd2 = (d2 - d2.floor() - 0.5).abs() * 2.;
    return (fd1 - fd2).abs();
}

/// Return peaks of the signal considering values above threshold * the maximum
/// Expects a vector of magnitudes
/// Also returns the valleys
fn find_peaks(buckets : &Vec<IndexedMagnitude>,
              threshold_coef : f32) -> (Vec<IndexedMagnitude>,
                                        Vec<Option<IndexedMagnitude>>) {
    let mut threshold = 0.0;
    for bucket in buckets.iter() {
        threshold = f32::max(threshold, bucket.magnitude);
    }
    threshold *= threshold_coef;
    let mut peaks = vec!();
    let mut valleys = vec!();
    let buckets = buckets.iter();
    let mut high : Option<IndexedMagnitude> = None;
    let mut low : Option<IndexedMagnitude> = None;
    let mut pre_peak_low : Option<IndexedMagnitude> = None;
    for bucket in buckets {
        if let Some(low_val) = low.clone() {
           if bucket.magnitude < low_val.magnitude {
               low = Some(bucket.clone());
           }
        } else {
            low = Some(bucket.clone());
        }
        if let Some(high_val) = high.clone() {
           if bucket.magnitude > high_val.magnitude {
               high = Some(bucket.clone());
               pre_peak_low = low.clone();
           }
        } else {
            high = Some(bucket.clone());
            pre_peak_low = low.clone();
        }
        if let Some(high_val) = high.clone() {
            if high_val.magnitude - bucket.magnitude > threshold / 2.
                && bucket.magnitude - low.clone().unwrap().magnitude > threshold / 2. {
                    peaks.push(high_val.clone());
                    valleys.push(pre_peak_low.clone());
                    high = None;
                    low = None;
                    pre_peak_low = None;
            }
        }
    }
    (peaks, valleys)
}

fn first_peak(buckets : &Vec<IndexedMagnitude>, threshold_coef : f32) -> Option<IndexedMagnitude> {
    let (peaks, _) = find_peaks(buckets, threshold_coef);
    if peaks.len() >= 1usize {
        return Some(peaks[0].clone());
    }
    None
}

fn zero_padded_fft_norm(buf : &Vec<kiss_fft_cpx>, zeros : usize) -> Vec<f32>{
    let mut zero_vec = vec!();
    for _ in 0..zeros {
        zero_vec.push(kiss_fft_cpx{r : 0f32, i : 0f32});
    }
    let mut fft_buf = vec!();
    fft_buf.push_all(&zero_vec[..]);
    fft_buf.push_all(&buf[..]);
    let mut fft = KissFFT::new(buf.len() + zeros, false);
    let mut fft_out = fft.transform_norm_to_vec(&fft_buf[..]);
    let n = fft_out.len();
    fft_out.split_off(n / 2usize);
    Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()))
}

use std::iter::FromIterator;
pub fn meter_fft(
    sampling_frequency : usize,
    active_channels : Vec<String>,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String,
    display_buckets : Arc<Mutex<Vec<f32>>>,
    display_lines : Arc<Mutex<Vec<([f32; 4], usize)>>>,
    display_chan_index : Option<i32>,
    ) -> JoinHandle<()> {
        let mut chan_index = 0;
        let fft_buckets = 512;
        let zero_pad_coef = 8192 / 4 / fft_buckets;
        let n = fft_buckets * zero_pad_coef;
        let mut samples = 0usize;
        let mut last_sent_time = 0usize;
        let mut bufs_by_channel = Vec::new();
        let mut pitch_by_chan : Vec<f32> = Vec::new();
        let mut last_pitch_by_chan : Vec<f32> = Vec::new();
        let mut dissonance_by_chan : Vec<f32> = Vec::new();
        let mut num_peaks_by_chan : Vec<usize> = Vec::new();
        for _ in 0..active_channels.len() {
            bufs_by_channel.push(vec!());
            pitch_by_chan.push(0.);
            last_pitch_by_chan.push(0.);
            dissonance_by_chan.push(0.);
            num_peaks_by_chan.push(0);
        }
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let buf = &mut bufs_by_channel[chan_index];
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let fft_norm = zero_padded_fft_norm(&buf, n - fft_buckets);
                        let (peaks, valleys) = find_peaks(&index_magnitudes(&fft_norm), 1./10.);
                        let (mtns, _) = find_peaks(&peaks, 1./10.);
                        num_peaks_by_chan[chan_index] = mtns.len();
                        if let Some(detected_pitch) = pitch_detect(&fft_norm, sampling_frequency) {
                            if detected_pitch == last_pitch_by_chan[chan_index] {
                                pitch_by_chan[chan_index] = detected_pitch;
                            }
                            last_pitch_by_chan[chan_index] = detected_pitch;
                        }
                        let dissonance = compute_dissonance(&fft_norm, sampling_frequency);
                        dissonance_by_chan[chan_index] = dissonance;
                        if let Some(display_chan_index) = display_chan_index {
                            if display_chan_index == chan_index as i32 {
                                let mut display_buckets = display_buckets.lock().unwrap();
                                display_buckets.clear();
                                display_buckets.push_all(&fft_norm[..]);
                                let yellow = [243./255., 232./255., 51./255., 0.5];
                                let red = [239./255., 101./255., 68./255., 1.];
                                let mut display_lines = display_lines.lock().unwrap();
                                display_lines.clear();
                                for mtn in mtns.iter() {
                                    display_lines.push((red.clone(), mtn.index.clone()));
                                }
                                for valley in valleys.iter() {
                                    if let &Some(ref valley) = valley {
                                        display_lines.push((yellow.clone(), valley.index.clone()));
                                    }
                                }
                                display_buckets.push_all(&fft_norm[..]);
                            }
                        }
                        if samples > last_sent_time + sampling_frequency * active_channels.len() / OSC_PER_SEC {
                            last_sent_time = samples;
                            let mut sender = osc_sender.lock().unwrap();
                            for i in 0..active_channels.len() {
                                let track_title = &active_channels[i];
                                let detected_pitch = pitch_by_chan[i];
                                let pitch_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/detectedPitch", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(detected_pitch))
                                    };
                                if let Err(e) = sender.send(pitch_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let num_peaks = num_peaks_by_chan[i];
                                let peaks_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/numPeaks", track_title, osc_prefix).to_string(),
                                        args : vec!(OscInt(num_peaks as i32))
                                    };
                                if let Err(e) = sender.send(peaks_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let dissonance = dissonance_by_chan[i];
                                let diss_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/dissonance", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(dissonance))
                                    };
                                if let Err(e) = sender.send(diss_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }

                            }
                        }
                        buf.clear();
                    }
                    samples += 1usize;
                    chan_index = (chan_index + 1) % active_channels.len();
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
<commit_msg>rolling fft<commit_after>use bounded_spsc_queue::{Consumer};
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;
use osc::osc_sender::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::thread;
use std::thread::{JoinHandle};
use std::sync::{Arc, Mutex};
use itertools::Itertools;

const OSC_PER_SEC : usize = 30usize;

#[derive(Clone, Debug)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}

fn index_magnitudes(mags : &Vec<f32>) -> Vec<IndexedMagnitude> {
    let mut indexed = vec!();
    let mut i = 0usize;
    for mag in mags {
        indexed.push(IndexedMagnitude{index : i, magnitude : *mag});
        i += 1usize;
    }
    indexed
}

fn pitch_detect(buckets : &Vec<f32>, fs : usize) -> Option<f32> {
    //  1 indexed
    //  filter to peaks
    if let Some(peak) = first_peak(&find_peaks(&index_magnitudes(buckets), 1./10.).0, 1./5.) {
        return Some((peak.index * fs) as f32 / (buckets.len() as f32 * 2.0));
    }
    None
}

fn idx_to_freq(idx : usize, n : usize, fs : usize) -> f32 {
    (idx * fs) as f32 / n as f32
}

fn bkt_to_freq(bkt : &IndexedMagnitude, buckets : usize, fs : usize) -> f32 {
    idx_to_freq(bkt.index, buckets, fs)
}

fn compute_dissonance(buckets : &Vec<f32>, fs : usize) -> f32{
    let (mut peaks, _) = find_peaks(&find_peaks(&index_magnitudes(buckets), 1./12.).0, 1./12.);
    peaks.sort_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
    if peaks.len() < 3 {
        return 0.;
    }
    let f1 = bkt_to_freq(&peaks[0], buckets.len() * 2, fs);
    let f2 = bkt_to_freq(&peaks[1], buckets.len() * 2, fs);
    let f3 = bkt_to_freq(&peaks[2], buckets.len() * 2, fs);
    let d1 = f2 / f1;
    let d2 = f3 / f1;

    let fd1 = (d1 - d1.floor() - 0.5).abs() * 2.;
    let fd2 = (d2 - d2.floor() - 0.5).abs() * 2.;
    return (fd1 - fd2).abs();
}

/// Return peaks of the signal considering values above threshold * the maximum
/// Expects a vector of magnitudes
/// Also returns the valleys
fn find_peaks(buckets : &Vec<IndexedMagnitude>,
              threshold_coef : f32) -> (Vec<IndexedMagnitude>,
                                        Vec<Option<IndexedMagnitude>>) {
    let mut threshold = 0.0;
    for bucket in buckets.iter() {
        threshold = f32::max(threshold, bucket.magnitude);
    }
    threshold *= threshold_coef;
    let mut peaks = vec!();
    let mut valleys = vec!();
    let buckets = buckets.iter();
    let mut high : Option<IndexedMagnitude> = None;
    let mut low : Option<IndexedMagnitude> = None;
    let mut pre_peak_low : Option<IndexedMagnitude> = None;
    for bucket in buckets {
        if let Some(low_val) = low.clone() {
           if bucket.magnitude < low_val.magnitude {
               low = Some(bucket.clone());
           }
        } else {
            low = Some(bucket.clone());
        }
        if let Some(high_val) = high.clone() {
           if bucket.magnitude > high_val.magnitude {
               high = Some(bucket.clone());
               pre_peak_low = low.clone();
           }
        } else {
            high = Some(bucket.clone());
            pre_peak_low = low.clone();
        }
        if let Some(high_val) = high.clone() {
            if high_val.magnitude - bucket.magnitude > threshold / 2.
                && bucket.magnitude - low.clone().unwrap().magnitude > threshold / 2. {
                    peaks.push(high_val.clone());
                    valleys.push(pre_peak_low.clone());
                    high = None;
                    low = None;
                    pre_peak_low = None;
            }
        }
    }
    (peaks, valleys)
}

fn first_peak(buckets : &Vec<IndexedMagnitude>, threshold_coef : f32) -> Option<IndexedMagnitude> {
    let (peaks, _) = find_peaks(buckets, threshold_coef);
    if peaks.len() >= 1usize {
        return Some(peaks[0].clone());
    }
    None
}

fn zero_padded_fft_norm(buf : &Vec<kiss_fft_cpx>, zeros : usize) -> Vec<f32>{
    let mut zero_vec = vec!();
    for _ in 0..zeros {
        zero_vec.push(kiss_fft_cpx{r : 0f32, i : 0f32});
    }
    let mut fft_buf = vec!();
    fft_buf.push_all(&zero_vec[..]);
    fft_buf.push_all(&buf[..]);
    let mut fft = KissFFT::new(buf.len() + zeros, false);
    let mut fft_out = fft.transform_norm_to_vec(&fft_buf[..]);
    let n = fft_out.len();
    fft_out.split_off(n / 2usize);
    Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()))
}

use std::iter::FromIterator;
pub fn meter_fft(
    sampling_frequency : usize,
    active_channels : Vec<String>,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String,
    display_buckets : Arc<Mutex<Vec<f32>>>,
    display_lines : Arc<Mutex<Vec<([f32; 4], usize)>>>,
    display_chan_index : Option<i32>,
    ) -> JoinHandle<()> {
        let mut chan_index = 0;
        let fft_buckets = 512;
        let zero_pad_coef = 8192 / 2 / fft_buckets;
        let n = fft_buckets * zero_pad_coef;
        let mut samples = 0usize;
        let mut last_sent_time = 0usize;
        let mut bufs_by_channel = Vec::new();
        let mut pitch_by_chan : Vec<f32> = Vec::new();
        let mut last_pitch_by_chan : Vec<(f32, usize)> = Vec::new();
        let mut dissonance_by_chan : Vec<f32> = Vec::new();
        let mut num_peaks_by_chan : Vec<usize> = Vec::new();
        for _ in 0..active_channels.len() {
            bufs_by_channel.push(vec!());
            pitch_by_chan.push(0.);
            last_pitch_by_chan.push((0., 0));
            dissonance_by_chan.push(0.);
            num_peaks_by_chan.push(0);
        }
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let buf = &mut bufs_by_channel[chan_index];
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let fft_norm = zero_padded_fft_norm(&buf, n - fft_buckets);
                        let (peaks, valleys) = find_peaks(&index_magnitudes(&fft_norm), 1./10.);
                        let (mtns, _) = find_peaks(&peaks, 1./5.);
                        num_peaks_by_chan[chan_index] = mtns.len();
                        if let Some(detected_pitch) = pitch_detect(&fft_norm, sampling_frequency) {
                            pitch_by_chan[chan_index] = detected_pitch;
                        }
                        let dissonance = compute_dissonance(&fft_norm, sampling_frequency);
                        dissonance_by_chan[chan_index] = dissonance;
                        if let Some(display_chan_index) = display_chan_index {
                            if display_chan_index == chan_index as i32 {
                                let mut display_buckets = display_buckets.lock().unwrap();
                                display_buckets.clear();
                                display_buckets.push_all(&fft_norm[..]);
                                let yellow = [243./255., 232./255., 51./255., 0.5];
                                let red = [239./255., 101./255., 68./255., 1.];
                                let mut display_lines = display_lines.lock().unwrap();
                                display_lines.clear();
                                for mtn in mtns.iter() {
                                    display_lines.push((red.clone(), mtn.index.clone()));
                                }
                                for valley in valleys.iter() {
                                    if let &Some(ref valley) = valley {
                                        display_lines.push((yellow.clone(), valley.index.clone()));
                                    }
                                }
                                display_buckets.push_all(&fft_norm[..]);
                            }
                        }
                        if samples > last_sent_time + sampling_frequency * active_channels.len() / OSC_PER_SEC {
                            last_sent_time = samples;
                            let mut sender = osc_sender.lock().unwrap();
                            for i in 0..active_channels.len() {
                                let track_title = &active_channels[i];
                                let detected_pitch = pitch_by_chan[i];
                                let pitch_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/detectedPitch", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(detected_pitch))
                                    };
                                if let Err(e) = sender.send(pitch_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let num_peaks = num_peaks_by_chan[i];
                                let peaks_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/numPeaks", track_title, osc_prefix).to_string(),
                                        args : vec!(OscInt(num_peaks as i32))
                                    };
                                if let Err(e) = sender.send(peaks_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let dissonance = dissonance_by_chan[i];
                                let diss_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/dissonance", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(dissonance))
                                    };
                                if let Err(e) = sender.send(diss_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }

                            }
                        }
                        let drain = buf.len() / 2;
                        for _ in 0..drain {
                            buf.remove(0);
                        }
                        //buf.clear();
                    }
                    samples += 1usize;
                    chan_index = (chan_index + 1) % active_channels.len();
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lanta;

use lanta::{cmd, Lanta, ModKey};
use lanta::errors::*;
use lanta::layout::*;

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn run() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Control;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("chrome")),
        ([modkey], XK_v, spawn!("code")),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        ([], XF86XK_MonBrightnessUp, spawn!("xbacklight", "-inc", "10")),
        ([], XF86XK_MonBrightnessDown, spawn!("xbacklight", "-dec", "10")),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        ([], XF86XK_AudioRaiseVolume, spawn!("amixer", "-q", "set", "Master", "5%+")),
        ([], XF86XK_AudioLowerVolume, spawn!("amixer", "-q", "set", "Master", "5%-")),
        ([], XF86XK_AudioMute, spawn!("amixer", "-q", "set", "Master", "toggle")),
    ];

    let padding = 20;
    let layouts = vec![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups!{
        keys,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, layouts)?.run();

    Ok(())
}

quick_main!(run);
<commit_msg>Spotify shortcut.<commit_after>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lanta;

use lanta::{cmd, Lanta, ModKey};
use lanta::errors::*;
use lanta::layout::*;

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn run() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Control;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("chrome")),
        ([modkey], XK_v, spawn!("code")),
        ([modkey], XK_b, spawn!("spotify --force-device-scale-factor=2")),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        ([], XF86XK_MonBrightnessUp, spawn!("xbacklight", "-inc", "10")),
        ([], XF86XK_MonBrightnessDown, spawn!("xbacklight", "-dec", "10")),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        ([], XF86XK_AudioRaiseVolume, spawn!("amixer", "-q", "set", "Master", "5%+")),
        ([], XF86XK_AudioLowerVolume, spawn!("amixer", "-q", "set", "Master", "5%-")),
        ([], XF86XK_AudioMute, spawn!("amixer", "-q", "set", "Master", "toggle")),
    ];

    let padding = 20;
    let layouts = vec![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups!{
        keys,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, layouts)?.run();

    Ok(())
}

quick_main!(run);
<|endoftext|>


<commit_before>//! A buffer backed by a contiguous region of memory.

use {Buf, BufMut};
use std::fmt;

/*
 *
 * ===== SliceBuf =====
 *
 */

/// A `Buf` backed by a contiguous region of memory.
///
/// This `Buf` is better suited for cases where there is a clear delineation
/// between reading and writing.
pub struct SliceBuf<T = Box<[u8]>> {
    // Contiguous memory
    mem: T,
    // Current read position
    rd: usize,
    // Current write position
    wr: usize,
}

impl<T: AsRef<[u8]>> SliceBuf<T> {
    /// Creates a new `SliceBuf` wrapping the provided slice
    pub fn new(mem: T) -> SliceBuf<T> {
        SliceBuf {
            mem: mem,
            rd: 0,
            wr: 0,
        }
    }

    /// Return the number of bytes the buffer can contain
    pub fn capacity(&self) -> usize {
        self.mem.as_ref().len()
    }

    /// Return the read cursor position
    pub fn position(&self) -> usize {
        self.rd
    }

    /// Set the read cursor position
    pub fn set_position(&mut self, position: usize) {
        assert!(position <= self.wr, "position out of bounds");
        self.rd = position
    }

    /// Return the number of buffered bytes
    pub fn len(&self) -> usize {
        self.wr
    }

    /// Returns `true` if the buffer contains no unread bytes
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Clears the buffer, removing any written data
    pub fn clear(&mut self) {
        self.rd = 0;
        self.wr = 0;
    }}

impl<T> Buf for SliceBuf<T>
    where T: AsRef<[u8]>,
{
    fn remaining(&self) -> usize {
        self.wr - self.rd
    }

    fn bytes(&self) -> &[u8] {
        &self.mem.as_ref()[self.rd..self.wr]
    }

    fn advance(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining(), "buffer overflow");
        self.rd += cnt;
    }

    fn copy_to_slice(&mut self, dst: &mut [u8]) {
        assert!(self.remaining() >= dst.len());

        let len = dst.len();
        dst.copy_from_slice(&self.mem.as_ref()[self.rd..self.rd+len]);
        self.rd += len;
    }
}

impl<T> BufMut for SliceBuf<T>
    where T: AsRef<[u8]> + AsMut<[u8]>,
{
    fn remaining_mut(&self) -> usize {
        self.capacity() - self.wr
    }

    unsafe fn advance_mut(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining_mut());
        self.wr += cnt;
    }

    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
        &mut self.mem.as_mut()[self.wr..]
    }

    fn copy_from_slice(&mut self, src: &[u8]) {
        assert!(self.remaining_mut() >= src.len());

        let wr = self.wr;

        self.mem.as_mut()[wr..wr+src.len()]
            .copy_from_slice(src);

        self.wr += src.len();
    }
}

impl<T> fmt::Debug for SliceBuf<T>
    where T: AsRef<[u8]>,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.bytes().fmt(fmt)
    }
}

impl<T> fmt::Write for SliceBuf<T>
    where T: AsRef<[u8]> + AsMut<[u8]>
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        BufMut::put_str(self, s);
        Ok(())
    }

    fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
        fmt::write(self, args)
    }
}
<commit_msg>Remove default for SliceBuf<T><commit_after>//! A buffer backed by a contiguous region of memory.

use {Buf, BufMut};
use std::fmt;

/*
 *
 * ===== SliceBuf =====
 *
 */

/// A `Buf` backed by a contiguous region of memory.
///
/// This `Buf` is better suited for cases where there is a clear delineation
/// between reading and writing.
pub struct SliceBuf<T> {
    // Contiguous memory
    mem: T,
    // Current read position
    rd: usize,
    // Current write position
    wr: usize,
}

impl<T: AsRef<[u8]>> SliceBuf<T> {
    /// Creates a new `SliceBuf` wrapping the provided slice
    pub fn new(mem: T) -> SliceBuf<T> {
        SliceBuf {
            mem: mem,
            rd: 0,
            wr: 0,
        }
    }

    /// Return the number of bytes the buffer can contain
    pub fn capacity(&self) -> usize {
        self.mem.as_ref().len()
    }

    /// Return the read cursor position
    pub fn position(&self) -> usize {
        self.rd
    }

    /// Set the read cursor position
    pub fn set_position(&mut self, position: usize) {
        assert!(position <= self.wr, "position out of bounds");
        self.rd = position
    }

    /// Return the number of buffered bytes
    pub fn len(&self) -> usize {
        self.wr
    }

    /// Returns `true` if the buffer contains no unread bytes
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Clears the buffer, removing any written data
    pub fn clear(&mut self) {
        self.rd = 0;
        self.wr = 0;
    }}

impl<T> Buf for SliceBuf<T>
    where T: AsRef<[u8]>,
{
    fn remaining(&self) -> usize {
        self.wr - self.rd
    }

    fn bytes(&self) -> &[u8] {
        &self.mem.as_ref()[self.rd..self.wr]
    }

    fn advance(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining(), "buffer overflow");
        self.rd += cnt;
    }

    fn copy_to_slice(&mut self, dst: &mut [u8]) {
        assert!(self.remaining() >= dst.len());

        let len = dst.len();
        dst.copy_from_slice(&self.mem.as_ref()[self.rd..self.rd+len]);
        self.rd += len;
    }
}

impl<T> BufMut for SliceBuf<T>
    where T: AsRef<[u8]> + AsMut<[u8]>,
{
    fn remaining_mut(&self) -> usize {
        self.capacity() - self.wr
    }

    unsafe fn advance_mut(&mut self, cnt: usize) {
        assert!(cnt <= self.remaining_mut());
        self.wr += cnt;
    }

    unsafe fn bytes_mut(&mut self) -> &mut [u8] {
        &mut self.mem.as_mut()[self.wr..]
    }

    fn copy_from_slice(&mut self, src: &[u8]) {
        assert!(self.remaining_mut() >= src.len());

        let wr = self.wr;

        self.mem.as_mut()[wr..wr+src.len()]
            .copy_from_slice(src);

        self.wr += src.len();
    }
}

impl<T> fmt::Debug for SliceBuf<T>
    where T: AsRef<[u8]>,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.bytes().fmt(fmt)
    }
}

impl<T> fmt::Write for SliceBuf<T>
    where T: AsRef<[u8]> + AsMut<[u8]>
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        BufMut::put_str(self, s);
        Ok(())
    }

    fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
        fmt::write(self, args)
    }
}
<|endoftext|>


<commit_before>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<commit_msg>Can click to focus on views outside of the tree<commit_after>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).unwrap_or_else(|_| {
                    // still focus on view, even if not in tree.
                    view.focus();
                });
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<|endoftext|>


<commit_before>extern crate byteorder;

use std::fmt;
use std::fmt::{Debug, Display, Formatter};

use self::byteorder::{BigEndian, ByteOrder};

use crate::{CodePairValue, DxfError, DxfResult, Handle};

use crate::helper_functions::parse_hex_string;

/// The basic primitive of a DXF file; a code indicating the type of the data contained, and the
/// data itself.
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CodePair {
    pub code: i32,
    pub value: CodePairValue,
    pub offset: usize,
}

impl CodePair {
    pub fn new(code: i32, value: CodePairValue, offset: usize) -> Self {
        CodePair {
            code,
            value,
            offset,
        }
    }
    pub fn new_str(code: i32, val: &str) -> Self {
        CodePair::new(code, CodePairValue::Str(val.to_string()), 0)
    }
    pub fn new_string(code: i32, val: &str) -> Self {
        CodePair::new(code, CodePairValue::Str(val.to_string()), 0)
    }
    pub fn new_binary(code: i32, val: Vec<u8>) -> Self {
        CodePair::new(code, CodePairValue::Binary(val), 0)
    }
    pub fn new_i16(code: i32, val: i16) -> Self {
        CodePair::new(code, CodePairValue::Short(val), 0)
    }
    pub fn new_f64(code: i32, val: f64) -> Self {
        CodePair::new(code, CodePairValue::Double(val), 0)
    }
    pub fn new_i64(code: i32, val: i64) -> Self {
        CodePair::new(code, CodePairValue::Long(val), 0)
    }
    pub fn new_i32(code: i32, val: i32) -> Self {
        CodePair::new(code, CodePairValue::Integer(val), 0)
    }
    pub fn new_bool(code: i32, val: bool) -> Self {
        CodePair::new(code, CodePairValue::Boolean(if val { 1 } else { 0 }), 0)
    }
    pub fn assert_bool(&self) -> DxfResult<bool> {
        match self.value {
            CodePairValue::Boolean(s) => Ok(s != 0),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i64(&self) -> DxfResult<i64> {
        match self.value {
            CodePairValue::Long(l) => Ok(l),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i32(&self) -> DxfResult<i32> {
        match self.value {
            CodePairValue::Integer(i) => Ok(i),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_f64(&self) -> DxfResult<f64> {
        match self.value {
            CodePairValue::Double(f) => Ok(f),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_string(&self) -> DxfResult<String> {
        match self.value {
            CodePairValue::Str(ref s) => Ok(s.clone()),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_binary(&self) -> DxfResult<Vec<u8>> {
        match self.value {
            CodePairValue::Binary(ref b) => Ok(b.clone()),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i16(&self) -> DxfResult<i16> {
        match self.value {
            CodePairValue::Boolean(s) => Ok(s),
            CodePairValue::Short(s) => Ok(s),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
}

impl CodePair {
    pub(crate) fn as_handle(&self) -> DxfResult<Handle> {
        let mut bytes = vec![];
        parse_hex_string(&self.assert_string()?, &mut bytes, self.offset)?;
        while bytes.len() < 8 {
            bytes.insert(0, 0);
        }
        Ok(Handle(BigEndian::read_u64(&bytes)))
    }
}

impl Debug for CodePair {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[@{}]{}/{:?}", self.offset, self.code, &self.value)
    }
}

impl Display for CodePair {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}/{}", self.code, &self.value)
    }
}

impl PartialEq for CodePair {
    fn eq(&self, other: &CodePair) -> bool {
        // not comparing offsets
        self.code == other.code && self.value == other.value
    }
}

#[cfg(test)]
mod tests {
    use crate::{CodePair, Handle};

    #[test]
    fn as_handle() {
        assert_eq!(Handle(0x00), CodePair::new_str(0, "0").as_handle().unwrap());
        assert_eq!(Handle(0x01), CodePair::new_str(0, "1").as_handle().unwrap());
        assert_eq!(
            Handle(0xABCD),
            CodePair::new_str(0, "ABCD").as_handle().unwrap()
        );
        assert_eq!(
            Handle(0xABCDABCD),
            CodePair::new_str(0, "ABCDABCD").as_handle().unwrap()
        );
        assert_eq!(
            Handle(0xABCDABCDABCDABCD),
            CodePair::new_str(0, "ABCDABCDABCDABCD")
                .as_handle()
                .unwrap()
        );
    }

    #[test]
    fn impl_debug() {
        assert_eq!("[@0]0/str", format!("{:?}", CodePair::new_str(0, "str")));
    }

    #[test]
    fn impl_display() {
        assert_eq!("0/str", format!("{}", CodePair::new_str(0, "str")));
    }
}
<commit_msg>trim whitespace when parsing handles<commit_after>extern crate byteorder;

use std::fmt;
use std::fmt::{Debug, Display, Formatter};

use self::byteorder::{BigEndian, ByteOrder};

use crate::{CodePairValue, DxfError, DxfResult, Handle};

use crate::helper_functions::parse_hex_string;

/// The basic primitive of a DXF file; a code indicating the type of the data contained, and the
/// data itself.
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CodePair {
    pub code: i32,
    pub value: CodePairValue,
    pub offset: usize,
}

impl CodePair {
    pub fn new(code: i32, value: CodePairValue, offset: usize) -> Self {
        CodePair {
            code,
            value,
            offset,
        }
    }
    pub fn new_str(code: i32, val: &str) -> Self {
        CodePair::new(code, CodePairValue::Str(val.to_string()), 0)
    }
    pub fn new_string(code: i32, val: &str) -> Self {
        CodePair::new(code, CodePairValue::Str(val.to_string()), 0)
    }
    pub fn new_binary(code: i32, val: Vec<u8>) -> Self {
        CodePair::new(code, CodePairValue::Binary(val), 0)
    }
    pub fn new_i16(code: i32, val: i16) -> Self {
        CodePair::new(code, CodePairValue::Short(val), 0)
    }
    pub fn new_f64(code: i32, val: f64) -> Self {
        CodePair::new(code, CodePairValue::Double(val), 0)
    }
    pub fn new_i64(code: i32, val: i64) -> Self {
        CodePair::new(code, CodePairValue::Long(val), 0)
    }
    pub fn new_i32(code: i32, val: i32) -> Self {
        CodePair::new(code, CodePairValue::Integer(val), 0)
    }
    pub fn new_bool(code: i32, val: bool) -> Self {
        CodePair::new(code, CodePairValue::Boolean(if val { 1 } else { 0 }), 0)
    }
    pub fn assert_bool(&self) -> DxfResult<bool> {
        match self.value {
            CodePairValue::Boolean(s) => Ok(s != 0),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i64(&self) -> DxfResult<i64> {
        match self.value {
            CodePairValue::Long(l) => Ok(l),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i32(&self) -> DxfResult<i32> {
        match self.value {
            CodePairValue::Integer(i) => Ok(i),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_f64(&self) -> DxfResult<f64> {
        match self.value {
            CodePairValue::Double(f) => Ok(f),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_string(&self) -> DxfResult<String> {
        match self.value {
            CodePairValue::Str(ref s) => Ok(s.clone()),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_binary(&self) -> DxfResult<Vec<u8>> {
        match self.value {
            CodePairValue::Binary(ref b) => Ok(b.clone()),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
    pub fn assert_i16(&self) -> DxfResult<i16> {
        match self.value {
            CodePairValue::Boolean(s) => Ok(s),
            CodePairValue::Short(s) => Ok(s),
            _ => Err(DxfError::WrongValueType(self.offset)),
        }
    }
}

impl CodePair {
    pub(crate) fn as_handle(&self) -> DxfResult<Handle> {
        let mut bytes = vec![];
        parse_hex_string(&self.assert_string()?.trim(), &mut bytes, self.offset)?;
        while bytes.len() < 8 {
            bytes.insert(0, 0);
        }
        Ok(Handle(BigEndian::read_u64(&bytes)))
    }
}

impl Debug for CodePair {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "[@{}]{}/{:?}", self.offset, self.code, &self.value)
    }
}

impl Display for CodePair {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}/{}", self.code, &self.value)
    }
}

impl PartialEq for CodePair {
    fn eq(&self, other: &CodePair) -> bool {
        // not comparing offsets
        self.code == other.code && self.value == other.value
    }
}

#[cfg(test)]
mod tests {
    use crate::{CodePair, Handle};

    #[test]
    fn as_handle() {
        assert_eq!(Handle(0x00), CodePair::new_str(0, "0").as_handle().unwrap());
        assert_eq!(Handle(0x01), CodePair::new_str(0, "1").as_handle().unwrap());
        assert_eq!(
            Handle(0xABCD),
            CodePair::new_str(0, "ABCD").as_handle().unwrap()
        );
        assert_eq!(
            Handle(0xABCDABCD),
            CodePair::new_str(0, "ABCDABCD").as_handle().unwrap()
        );
        assert_eq!(
            Handle(0xABCDABCDABCDABCD),
            CodePair::new_str(0, "ABCDABCDABCDABCD")
                .as_handle()
                .unwrap()
        );
        assert_eq!(
            Handle(0xAB),
            CodePair::new_str(0, "  AB  ").as_handle().unwrap()
        );
    }

    #[test]
    fn impl_debug() {
        assert_eq!("[@0]0/str", format!("{:?}", CodePair::new_str(0, "str")));
    }

    #[test]
    fn impl_display() {
        assert_eq!("0/str", format!("{}", CodePair::new_str(0, "str")));
    }
}
<|endoftext|>


<commit_before>//! A macro for writing HTML templates.
//!
//! This documentation only describes the runtime API. For a general
//! guide, check out the [book] instead.
//!
//! [book]: http://lfairy.gitbooks.io/maud/content/

use std::fmt;
use std::io;

/// Escapes an HTML value.
pub fn escape(s: &str) -> String {
    use std::fmt::Write;
    let mut buf = String::new();
    rt::Escaper { inner: &mut buf }.write_str(s).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
///
/// Use `.to_string()` to convert it to a `String`, or `.render()` to
/// write it directly to a handle.
pub struct Markup<F> {
    callback: F,
}

impl<F> Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
    /// Renders the markup to a `std::io::Write`.
    pub fn render<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        struct Adaptor<'a, W: ?Sized + 'a> {
            inner: &'a mut W,
            error: io::Result<()>,
        }

        impl<'a, W: ?Sized + io::Write> fmt::Write for Adaptor<'a, W> {
            fn write_str(&mut self, s: &str) -> fmt::Result {
                match self.inner.write_all(s.as_bytes()) {
                    Ok(()) => Ok(()),
                    Err(e) => {
                        self.error = Err(e);
                        Err(fmt::Error)
                    },
                }
            }
        }

        let mut output = Adaptor { inner: w, error: Ok(()) };
        match self.render_fmt(&mut output) {
            Ok(()) => Ok(()),
            Err(_) => output.error,
        }
    }

    /// Renders the markup to a `std::fmt::Write`.
    pub fn render_fmt(&self, w: &mut fmt::Write) -> fmt::Result {
        (self.callback)(w)
    }
}

impl<F> ToString for Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
    fn to_string(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[doc(hidden)]
pub mod rt {
    use std::fmt;
    use super::Markup;

    #[inline]
    pub fn make_markup<F>(f: F) -> Markup<F>
        where F: Fn(&mut fmt::Write) -> fmt::Result
    {
        Markup { callback: f }
    }

    /// rustc is a butt and doesn't let us quote macro invocations
    /// directly. So we factor the `write!` call into a separate
    /// function and use that instead.
    ///
    /// See <https://github.com/rust-lang/rust/issues/16617>
    #[inline]
    pub fn write_fmt<T: fmt::Display>(w: &mut fmt::Write, value: &T) -> fmt::Result {
        write!(w, "{}", *value)
    }

    pub struct Escaper<'a, 'b: 'a> {
        pub inner: &'a mut (fmt::Write + 'b),
    }

    impl<'a, 'b> fmt::Write for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }
}
<commit_msg>Fix formatting<commit_after>//! A macro for writing HTML templates.
//!
//! This documentation only describes the runtime API. For a general
//! guide, check out the [book] instead.
//!
//! [book]: http://lfairy.gitbooks.io/maud/content/

use std::fmt;
use std::io;

/// Escapes an HTML value.
pub fn escape(s: &str) -> String {
    use std::fmt::Write;
    let mut buf = String::new();
    rt::Escaper { inner: &mut buf }.write_str(s).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
///
/// Use `.to_string()` to convert it to a `String`, or `.render()` to
/// write it directly to a handle.
pub struct Markup<F> {
    callback: F,
}

impl<F> Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
    /// Renders the markup to a `std::io::Write`.
    pub fn render<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        struct Adaptor<'a, W: ?Sized + 'a> {
            inner: &'a mut W,
            error: io::Result<()>,
        }

        impl<'a, W: ?Sized + io::Write> fmt::Write for Adaptor<'a, W> {
            fn write_str(&mut self, s: &str) -> fmt::Result {
                match self.inner.write_all(s.as_bytes()) {
                    Ok(()) => Ok(()),
                    Err(e) => {
                        self.error = Err(e);
                        Err(fmt::Error)
                    },
                }
            }
        }

        let mut output = Adaptor { inner: w, error: Ok(()) };
        match self.render_fmt(&mut output) {
            Ok(()) => Ok(()),
            Err(_) => output.error,
        }
    }

    /// Renders the markup to a `std::fmt::Write`.
    pub fn render_fmt(&self, w: &mut fmt::Write) -> fmt::Result {
        (self.callback)(w)
    }
}

impl<F> ToString for Markup<F> where F: Fn(&mut fmt::Write) -> fmt::Result {
    fn to_string(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[doc(hidden)]
pub mod rt {
    use std::fmt;
    use super::Markup;

    #[inline]
    pub fn make_markup<F>(f: F) -> Markup<F> where
        F: Fn(&mut fmt::Write) -> fmt::Result
    {
        Markup { callback: f }
    }

    /// rustc is a butt and doesn't let us quote macro invocations
    /// directly. So we factor the `write!` call into a separate
    /// function and use that instead.
    ///
    /// See <https://github.com/rust-lang/rust/issues/16617>
    #[inline]
    pub fn write_fmt<T: fmt::Display>(w: &mut fmt::Write, value: &T) -> fmt::Result {
        write!(w, "{}", *value)
    }

    pub struct Escaper<'a, 'b: 'a> {
        pub inner: &'a mut (fmt::Write + 'b),
    }

    impl<'a, 'b> fmt::Write for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }
}
<|endoftext|>