<commit_before>#[cfg(feature = "profile")]
macro_rules! decl_profile_globals {
    ($v:ident) => {
        mod $v {
            use std;
            pub use fnv::FnvHashMap;

            pub struct ProfileBlock {
                pub name: &'static str,
                pub start: std::time::SystemTime,
                pub total_time: f64
            }

            pub static mut PROFILE_ACCUM:
                Option<FnvHashMap<&'static str, ProfileBlock>> = None;
            pub static mut PROFILE_SUMMARY_T: Option<std::time::SystemTime> = None;
        }
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! decl_profile_globals { ($v:ident) => {} }

#[cfg(feature = "profile")]
macro_rules! profile_start {
    ($modn:ident, $v:ident) => {

        let $v = unsafe {
            let name = stringify!($v);
            if $modn::PROFILE_ACCUM.is_none() {
                $modn::PROFILE_ACCUM = Some(
                    $modn::FnvHashMap::with_capacity_and_hasher((100) as usize,
                    Default::default()));
            }

            let accum = $modn::PROFILE_ACCUM
                        .as_mut().unwrap();
            let $v = accum.entry(name).or_insert({
                            $modn::ProfileBlock {
                                name: name,
                                start: std::time::UNIX_EPOCH,
                                total_time: 0.0,
                            }
                        });

            $v.start = std::time::SystemTime::now();
            $v
        }
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! profile_start { ($modn:ident, $v:ident) => {} }

#[cfg(feature = "profile")]
macro_rules! profile_end {
    ($modn:ident, $v:ident) => {
        let elapsed = std::time::SystemTime::now().duration_since($v.start).unwrap();

        let secs = elapsed.as_secs() as f64
                    elapsed.subsec_nanos() as f64 * 1e-9;
        $v.total_time += secs;
    }
}
#[cfg(not(feature = "profile"))]
macro_rules! profile_end {
    ($modn:ident, $v:ident) => {
    }
}

#[cfg(feature = "profile")]
macro_rules! profile_summarize {
    ($modn:ident) => {
        unsafe {
            if $modn::PROFILE_SUMMARY_T.is_none() {
                $modn::PROFILE_SUMMARY_T = Some(SystemTime::now());
            }

            // report stats every 10 seconds
            let now = SystemTime::now();
            let selapsed = now.duration_since(*$modn::PROFILE_SUMMARY_T.as_ref().unwrap()).unwrap();
            let secs = selapsed.as_secs() as f64 + selapsed.subsec_nanos() as f64 * 1e-9;
            if secs > 10.0 {
                let mut out = String::new();

                let modn = stringify!($modn);
                out.push_str(&format!("[Profiler {}] {} secs elapsed since last profile\r\n",
                    modn, secs));
                for (name,block) in $modn::PROFILE_ACCUM.as_mut().unwrap().iter_mut() {
                    let pct = block.total_time / secs * 100.0;

                    let s = format!("   {}: {} secs ({}%)\r\n", name, block.total_time, pct );
                    out.push_str(&s);

                    block.total_time = 0.0; // reset for next round
                }

                write_log_file(&out);

                $modn::PROFILE_SUMMARY_T = Some(now);
            }
        };
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! profile_summarize {
    ($modn:ident) => {
    }
}
<commit_msg>Native: fix profiler<commit_after>#[cfg(feature = "profile")]
macro_rules! decl_profile_globals {
    ($v:ident) => {
        mod $v {
            use std;
            pub use fnv::FnvHashMap;

            pub struct ProfileBlock {
                pub name: &'static str,
                pub start: std::time::SystemTime,
                pub total_time: f64,
                pub count: u64,
            }

            pub static mut PROFILE_ACCUM:
                Option<FnvHashMap<&'static str, ProfileBlock>> = None;
            pub static mut PROFILE_SUMMARY_T: Option<std::time::SystemTime> = None;
        }
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! decl_profile_globals { ($v:ident) => {} }

#[cfg(feature = "profile")]
macro_rules! profile_start {
    ($modn:ident, $v:ident) => {

        let $v = unsafe {
            let name = stringify!($v);
            if $modn::PROFILE_ACCUM.is_none() {
                $modn::PROFILE_ACCUM = Some(
                    $modn::FnvHashMap::with_capacity_and_hasher((100) as usize,
                    Default::default()));
            }

            let accum = $modn::PROFILE_ACCUM
                        .as_mut().unwrap();
            let $v = accum.entry(name).or_insert({
                            $modn::ProfileBlock {
                                name: name,
                                start: std::time::UNIX_EPOCH,
                                total_time: 0.0,
                                count: 0,
                            }
                        });

            $v.start = std::time::SystemTime::now();
            $v.count += 1;
            $v
        }
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! profile_start { ($modn:ident, $v:ident) => {} }

#[cfg(feature = "profile")]
macro_rules! profile_end {
    ($modn:ident, $v:ident) => {
        let now = std::time::SystemTime::now();
        let elapsed = now.duration_since($v.start).unwrap();

        let secs = elapsed.as_secs() as f64
            + elapsed.subsec_nanos() as f64 * 1e-9;

        $v.total_time += secs;
    }
}
#[cfg(not(feature = "profile"))]
macro_rules! profile_end {
    ($modn:ident, $v:ident) => {
    }
}

#[cfg(feature = "profile")]
macro_rules! profile_summarize {
    ($modn:ident) => {
        unsafe {
            if $modn::PROFILE_SUMMARY_T.is_none() {
                $modn::PROFILE_SUMMARY_T = Some(SystemTime::now());
            }

            // report stats every 10 seconds
            let now = SystemTime::now();
            let selapsed = now.duration_since(*$modn::PROFILE_SUMMARY_T.as_ref().unwrap()).unwrap();
            let secs = selapsed.as_secs() as f64 + selapsed.subsec_nanos() as f64 * 1e-9;
            if secs > 10.0 {
                let mut out = String::new();

                let modn = stringify!($modn);
                out.push_str(&format!("[Profiler {}] {} secs elapsed since last profile\r\n",
                    modn, secs));
                for (name,block) in $modn::PROFILE_ACCUM.as_mut().unwrap().iter_mut() {
                    let pct = block.total_time / secs * 100.0;

                    let s = format!("   {}: {} secs ({}%) (count: {})\r\n",
                        name, block.total_time, pct, block.count);
                    out.push_str(&s);

                    block.total_time = 0.0; // reset for next round
                }

                write_log_file(&out);

                $modn::PROFILE_SUMMARY_T = Some(now);
            }
        };
    }
}

#[cfg(not(feature = "profile"))]
macro_rules! profile_summarize {
    ($modn:ident) => {
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use util::*;
    use std::time::SystemTime;
    use std;

    decl_profile_globals!(test_profiler);

    #[test]
    fn profile_works() {
        set_log_file_path("", "testlog.txt");
        const sleeptime:u32 = 250;
        let secs = 1000/sleeptime;
        let itersec = 16;
        for _i in 0..(itersec*secs) {
            profile_start!(test_profiler, main);
            std::thread::sleep_ms(sleeptime);
            profile_end!(test_profiler, main);

            profile_summarize!(test_profiler);
        }
    }
}<|endoftext|>


<commit_before>//! simple model-checking tools for rust.
//!
//! aims to reduce the boiler plate required
//! to write model-based and linearizability tests.
//!
//! it can find linearizability violations in
//! implementations without having any knowledge
//! of their inner-workings, by running sequential
//! operations on different commands and then
//! trying to find a sequential ordering that results
//! in the same return values.
//!
//! model-based testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! model! {
//!     Model => let m = AtomicUsize::new(0),
//!     Implementation => let mut i: usize = 0,
//!     Add(usize)(v in 0usize..4) => {
//!         let expected = m.fetch_add(v, Ordering::SeqCst) + v;
//!         i += v;
//!         assert_eq!(expected, i);
//!     },
//!     Set(usize)(v in 0usize..4) => {
//!         m.store(v, Ordering::SeqCst);
//!         i = v;
//!     },
//!     Eq(usize)(v in 0usize..4) => {
//!         let expected = m.load(Ordering::SeqCst) == v;
//!         let actual = i == v;
//!         assert_eq!(expected, actual);
//!     },
//!     Cas((usize, usize))((old, new) in (0usize..4, 0usize..4)) => {
//!         let expected =
//!             m.compare_and_swap(old, new, Ordering::SeqCst);
//!         let actual = if i == old {
//!             i = new;
//!             old
//!         } else {
//!             i
//!         };
//!         assert_eq!(expected, actual);
//!     }
//! }
//! ```
//!
//! linearizability testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! linearizable! {
//!     Implementation => let i = Shared::new(AtomicUsize::new(0)),
//!     BuggyAdd(usize)(v in 0usize..4) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         i.store(current + v, Ordering::SeqCst);
//!         current + v
//!     },
//!     Set(usize)(v in 0usize..4) -> () {
//!         i.store(v, Ordering::SeqCst)
//!     },
//!     BuggyCas((usize, usize))((old, new) in (0usize..4, 0usize..4)) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         if current == old {
//!             i.store(new, Ordering::SeqCst);
//!             new
//!         } else {
//!             current
//!         }
//!     }
//! }
//! ```
extern crate permutohedron;

use std::ops::Deref;

pub struct Shared<T>(*mut T);

impl<T> Clone for Shared<T> {
    fn clone(&self) -> Shared<T> {
        *self
    }
}

impl<T> Copy for Shared<T> {}

unsafe impl<T> Sync for Shared<T> {}

unsafe impl<T> Send for Shared<T> {}

impl<T> Deref for Shared<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Shared<T> {
    pub fn new(inner: T) -> Shared<T> {
        Shared(Box::into_raw(Box::new(inner)))
    }
}

#[macro_export]
macro_rules! model {
    (
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        model! {
            Config => Config::with_cases(1000).clone_with_source_file(file!()),
            Model => $model,
            Implementation => $implementation,
            $($op ($($type),*) ($parm in $strategy) => $body),*
        }
    };
    (
        Config => $config:expr,
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        fn arb() -> BoxedStrategy<Vec<Op>> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                0..40,
            ).boxed()
        }

        let config = $config;
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |ops| {
            $model;
            $implementation;

            for op in ops {
                match *op {
                    $(Op::$op($parm) => $body),*
                };
            };
            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

#[macro_export]
macro_rules! linearizable {
    (
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) -> $ret:ty $body:block),*
    ) => {
        use std::thread;

        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug, Clone)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        #[derive(Debug, PartialEq)]
        enum Ret {
            $(
                $op($ret)
            ),*
        }

        fn arb() -> BoxedStrategy<(usize, Vec<Op>)> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                1..4,
            )
                .prop_flat_map(|ops| (0..ops.len(), Just(ops)))
                .boxed()
        }

        let config = Config::with_cases(10000).clone_with_source_file(file!());
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |&(split_point, ref ops)| {
            $implementation;

            let ops1 = ops[0..split_point].to_vec();
            let ops2 = ops[split_point..].to_vec();

            let t1 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops1 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let t2 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops2 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let r1 = t1.join().expect("thread should not panic");
            let r2 = t2.join().expect("thread should not panic");

            // try to find sequential walk through ops
            let o1 = ops[0..split_point].to_vec();
            let o2 = ops[split_point..].to_vec();

            let calls1: Vec<(Op, Ret)> = o1.into_iter().zip(r1.into_iter()).collect();
            let calls2: Vec<(Op, Ret)> = o2.into_iter().zip(r2.into_iter()).collect();
            let mut indexes = vec![0; calls1.len()];
            indexes.resize(calls1.len() + calls2.len(), 1);
            let calls = vec![calls1, calls2];

            let mut linearizable = false;

            let call_permutations = model::permutohedron_heap(&mut indexes);

            'outer: for walk in call_permutations {
                $implementation;

                let mut indexes = vec![0, 0];
                // println!("trying walk {:?}", walk);

                for idx in walk {
                    let (ref op, ref expected) = calls[idx][indexes[idx]];
                    indexes[idx] += 1;

                    match *op {
                        $(
                            Op::$op($parm) => {
                                let ret = Ret::$op($body);
                                if ret != *expected {
                                    continue 'outer;
                                }
                            }
                        ),*
                    }
                }

                linearizable = true;
                break;
            }

            assert!(linearizable, "operations are not linearizable: {:?}", calls);

            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

pub fn permutohedron_heap<'a, Data, T>(
    orig: &'a mut Data,
) -> permutohedron::Heap<'a, Data, T>
    where Data: 'a + Sized + AsMut<[T]>,
          T: 'a
{
    permutohedron::Heap::new(orig)
}
<commit_msg>Added helpful notice regarding proptest versions.<commit_after>//! simple model-checking tools for rust.
//!
//! aims to reduce the boiler plate required
//! to write model-based and linearizability tests.
//!
//! it can find linearizability violations in
//! implementations without having any knowledge
//! of their inner-workings, by running sequential
//! operations on different commands and then
//! trying to find a sequential ordering that results
//! in the same return values.
//!
//! **important**: the crate makes use of
//! [proptest](https://crates.io/crates/proptest) via
//! macros. ensure that you are using the same version
//! of `proptest` that `model` lists in `Cargo.toml`,
//! otherwise mismatched API change will manifest as
//! strange compile-time errors hidden in macros.
//!
//! model-based testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! model! {
//!     Model => let m = AtomicUsize::new(0),
//!     Implementation => let mut i: usize = 0,
//!     Add(usize)(v in 0usize..4) => {
//!         let expected = m.fetch_add(v, Ordering::SeqCst) + v;
//!         i += v;
//!         assert_eq!(expected, i);
//!     },
//!     Set(usize)(v in 0usize..4) => {
//!         m.store(v, Ordering::SeqCst);
//!         i = v;
//!     },
//!     Eq(usize)(v in 0usize..4) => {
//!         let expected = m.load(Ordering::SeqCst) == v;
//!         let actual = i == v;
//!         assert_eq!(expected, actual);
//!     },
//!     Cas((usize, usize))((old, new) in (0usize..4, 0usize..4)) => {
//!         let expected =
//!             m.compare_and_swap(old, new, Ordering::SeqCst);
//!         let actual = if i == old {
//!             i = new;
//!             old
//!         } else {
//!             i
//!         };
//!         assert_eq!(expected, actual);
//!     }
//! }
//! ```
//!
//! linearizability testing:
//!
//! ```rust,noexecute
//! #[macro_use]
//! extern crate model;
//! #[macro_use]
//! extern crate proptest;
//!
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! linearizable! {
//!     Implementation => let i = Shared::new(AtomicUsize::new(0)),
//!     BuggyAdd(usize)(v in 0usize..4) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         i.store(current + v, Ordering::SeqCst);
//!         current + v
//!     },
//!     Set(usize)(v in 0usize..4) -> () {
//!         i.store(v, Ordering::SeqCst)
//!     },
//!     BuggyCas((usize, usize))((old, new) in (0usize..4, 0usize..4)) -> usize {
//!         let current = i.load(Ordering::SeqCst);
//!         thread::yield_now();
//!         if current == old {
//!             i.store(new, Ordering::SeqCst);
//!             new
//!         } else {
//!             current
//!         }
//!     }
//! }
//! ```
extern crate permutohedron;

use std::ops::Deref;

pub struct Shared<T>(*mut T);

impl<T> Clone for Shared<T> {
    fn clone(&self) -> Shared<T> {
        *self
    }
}

impl<T> Copy for Shared<T> {}

unsafe impl<T> Sync for Shared<T> {}

unsafe impl<T> Send for Shared<T> {}

impl<T> Deref for Shared<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Shared<T> {
    pub fn new(inner: T) -> Shared<T> {
        Shared(Box::into_raw(Box::new(inner)))
    }
}

#[macro_export]
macro_rules! model {
    (
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        model! {
            Config => Config::with_cases(1000).clone_with_source_file(file!()),
            Model => $model,
            Implementation => $implementation,
            $($op ($($type),*) ($parm in $strategy) => $body),*
        }
    };
    (
        Config => $config:expr,
        Model => $model:stmt,
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) => $body:expr),*
    ) => {
        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        fn arb() -> BoxedStrategy<Vec<Op>> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                0..40,
            ).boxed()
        }

        let config = $config;
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |ops| {
            $model;
            $implementation;

            for op in ops {
                match *op {
                    $(Op::$op($parm) => $body),*
                };
            };
            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

#[macro_export]
macro_rules! linearizable {
    (
        Implementation => $implementation:stmt,
        $($op:ident ($($type:ty),*) ($parm:pat in $strategy:expr) -> $ret:ty $body:block),*
    ) => {
        use std::thread;

        use proptest::collection::vec as prop_vec;
        use proptest::prelude::*;
        use proptest::test_runner::{Config, TestRunner};

        #[derive(Debug, Clone)]
        enum Op {
            $(
                $op($($type),*)
            ),*
        }

        #[derive(Debug, PartialEq)]
        enum Ret {
            $(
                $op($ret)
            ),*
        }

        fn arb() -> BoxedStrategy<(usize, Vec<Op>)> {
            prop_vec(
                prop_oneof![
                    $(
                        $strategy.prop_map(Op::$op)
                    ),*
                ],
                1..4,
            )
                .prop_flat_map(|ops| (0..ops.len(), Just(ops)))
                .boxed()
        }

        let config = Config::with_cases(10000).clone_with_source_file(file!());
        let mut runner = TestRunner::new(config);

        match runner.run(&arb(), |&(split_point, ref ops)| {
            $implementation;

            let ops1 = ops[0..split_point].to_vec();
            let ops2 = ops[split_point..].to_vec();

            let t1 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops1 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let t2 = thread::spawn(move || {
                    let mut ret = vec![];
                    for op in ops2 {
                        ret.push(match op {
                            $(
                                Op::$op($parm) => Ret::$op($body)
                            ),*
                        });
                    }
                    ret
                });

            let r1 = t1.join().expect("thread should not panic");
            let r2 = t2.join().expect("thread should not panic");

            // try to find sequential walk through ops
            let o1 = ops[0..split_point].to_vec();
            let o2 = ops[split_point..].to_vec();

            let calls1: Vec<(Op, Ret)> = o1.into_iter().zip(r1.into_iter()).collect();
            let calls2: Vec<(Op, Ret)> = o2.into_iter().zip(r2.into_iter()).collect();
            let mut indexes = vec![0; calls1.len()];
            indexes.resize(calls1.len() + calls2.len(), 1);
            let calls = vec![calls1, calls2];

            let mut linearizable = false;

            let call_permutations = model::permutohedron_heap(&mut indexes);

            'outer: for walk in call_permutations {
                $implementation;

                let mut indexes = vec![0, 0];
                // println!("trying walk {:?}", walk);

                for idx in walk {
                    let (ref op, ref expected) = calls[idx][indexes[idx]];
                    indexes[idx] += 1;

                    match *op {
                        $(
                            Op::$op($parm) => {
                                let ret = Ret::$op($body);
                                if ret != *expected {
                                    continue 'outer;
                                }
                            }
                        ),*
                    }
                }

                linearizable = true;
                break;
            }

            assert!(linearizable, "operations are not linearizable: {:?}", calls);

            Ok(())
        }) {
            Ok(_) => {}
            Err(e) =>  panic!("{}\n{}", e, runner),
        }
    }
}

pub fn permutohedron_heap<'a, Data, T>(
    orig: &'a mut Data,
) -> permutohedron::Heap<'a, Data, T>
    where Data: 'a + Sized + AsMut<[T]>,
          T: 'a
{
    permutohedron::Heap::new(orig)
}
<|endoftext|>


<commit_before>use bytes::{BufMut, BytesMut};
use std::io::{Error, ErrorKind};
use tokio::codec::{Decoder, Encoder};

// 5 MiB limit
const MAX_MSG_LEN: u32 = 5_242_880;
// 512 bits should be way more than enough
const MAX_ID_LEN: u8 = 64;

#[derive(Debug)]
pub struct Payload {
    id: BytesMut,
    msg: BytesMut,
}

#[derive(Default, Debug)]
pub struct Codec {
    id_len: u8,
    msg_len: u32,
}

impl Codec {
    pub fn new() -> Codec {
        Codec::default()
    }
}

impl Encoder for Codec {
    type Item = Payload;
    type Error = Error;

    fn encode(&mut self, item: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        assert!(item.id.len() < usize::from(MAX_ID_LEN));
        assert!((item.msg.len() as u32) < MAX_MSG_LEN);
        {
            let total_len = item.id.len() + item.msg.len() + 5;
            buf.reserve(total_len + 5);
        }
        buf.put_u8(item.id.len() as u8);
        buf.put_u32_be(item.msg.len() as u32);
        buf.put(item.id);
        buf.put(item.msg);
        Ok(())
    }
}

impl Decoder for Codec {
    type Item = Payload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.id_len == 0 && self.msg_len == 0 && buf.len() >= 5 {
            let buf = buf.split_to(5);
            self.id_len = buf[0];
            self.msg_len = u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]);
            if self.id_len > MAX_ID_LEN {
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("id must be <={} bytes", MAX_ID_LEN),
                ));
            } else if self.msg_len > MAX_MSG_LEN {
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("msg must be <={} bytes", MAX_MSG_LEN),
                ));
            }
        }
        if self.id_len != 0
            && self.msg_len != 0
            && buf.len() >= usize::from(self.id_len) + (self.msg_len as usize)
        {
            let id_len = self.id_len;
            self.id_len = 0;

            let msg_len = self.msg_len;
            self.msg_len = 0;

            let id = buf.split_to(id_len as usize);
            let msg = buf.split_to(msg_len as usize);
            Ok(Some(Payload { id, msg }))
        } else {
            Ok(None)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    macro_rules! assert_decode {
        ($codec:expr, $bytes:expr, $id:expr, $msg:expr) => {{
            let res = $codec.decode(&mut $bytes).unwrap();
            assert!(res.is_some(), "decoding failure, expected Ok");
            let res = res.expect("decoding failure, expected payload");
            assert_eq!(res.id, $id, "id mismatch");
            assert_eq!(res.msg, $msg, "msg mismatch");
        }};
    }

    #[test]
    fn test_max_id_len() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![MAX_ID_LEN + 1, 0, 0, 0, 0]);
        let err = codec.decode(&mut bytes).unwrap_err();
        assert_eq!(
            err.description(),
            format!("id must be <={} bytes", MAX_ID_LEN)
        );
    }

    #[test]
    fn test_max_msg_len() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![1, 255, 255, 255, 255]);
        let err = codec.decode(&mut bytes).unwrap_err();
        assert_eq!(
            err.description(),
            format!("msg must be <={} bytes", MAX_MSG_LEN)
        );
    }

    #[test]
    fn test_encode_full_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::new();
        codec
            .encode(
                Payload {
                    id: vec![0, 1, 2, 3, 4, 5].into(),
                    msg: vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245].into(),
                },
                &mut bytes,
            )
            .unwrap();
        assert_eq!(
            bytes,
            vec![
                6, // ID len
                0, 0, 0, 11, // Msg len
                0, 1, 2, 3, 4, 5, // ID
                255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245 // Msg
            ]
        );
    }

    #[test]
    fn test_decode_full_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
        ]);

        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );
    }

    #[test]
    fn test_decode_multipart_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, // Msg
        ]);
        let res = codec.decode(&mut bytes).unwrap();
        assert!(res.is_none());

        bytes.reserve(3);
        bytes.put_slice(&vec![247, 246, 245]);
        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );
    }

    #[test]
    fn test_decode_multiple_multipart_frames() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
            3,   // ID len
        ]);
        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );

        // Ensure the codec data is correct
        assert_eq!(bytes.len(), 1);
        assert_eq!(codec.id_len, 0);
        assert_eq!(codec.msg_len, 0);

        bytes.reserve(4);
        bytes.put_slice(&vec![0, 0, 0, 5]); // Write msg len
        let res = codec.decode(&mut bytes).unwrap();
        assert!(res.is_none());

        assert_eq!(bytes.len(), 0);
        assert_eq!(codec.id_len, 3);
        assert_eq!(codec.msg_len, 5);

        bytes.reserve(8);
        bytes.put_slice(&vec![
            1, 1, 1, // ID
            2, 2, 2, 2, 2, // Msg
        ]);
        assert_decode!(codec, bytes, vec![1, 1, 1], vec![2, 2, 2, 2, 2]);
    }

    #[test]
    fn test_decode_multiple_full_frames() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            // First payload
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
            // Second payload
            3, 0, 0, 0, 4, 1, 1, 1, 2, 2, 2, 2, // Third payload
            4, 0, 0, 0, 5, 3, 3, 3, 3, 4, 4, 4, 4, 4,
        ]);

        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );

        assert_decode!(codec, bytes, vec![1, 1, 1], vec![2, 2, 2, 2]);

        assert_decode!(codec, bytes, vec![3, 3, 3, 3], vec![4, 4, 4, 4, 4]);

        assert_eq!(bytes.len(), 0);
        assert_eq!(codec.id_len, 0);
        assert_eq!(codec.msg_len, 0);
    }
}
<commit_msg>Minor cleanup<commit_after>use bytes::{BufMut, BytesMut};
use std::io::{Error, ErrorKind};
use tokio::codec::{Decoder, Encoder};

// 5 MiB limit
const MAX_MSG_LEN: u32 = 5_242_880;
// 512 bits should be way more than enough
const MAX_ID_LEN: u8 = 64;

#[derive(Debug)]
pub struct Payload {
    id: BytesMut,
    msg: BytesMut,
}

#[derive(Default, Debug)]
pub struct Codec {
    id_len: u8,
    msg_len: u32,
}

impl Codec {
    pub fn new() -> Codec {
        Codec::default()
    }
}

impl Encoder for Codec {
    type Item = Payload;
    type Error = Error;

    fn encode(&mut self, item: Self::Item, buf: &mut BytesMut) -> Result<(), Error> {
        assert!(item.id.len() < usize::from(MAX_ID_LEN));
        assert!((item.msg.len() as u32) < MAX_MSG_LEN);
        buf.reserve(item.id.len() + item.msg.len() + 5);
        buf.put_u8(item.id.len() as u8);
        buf.put_u32_be(item.msg.len() as u32);
        buf.put(item.id);
        buf.put(item.msg);
        Ok(())
    }
}

impl Decoder for Codec {
    type Item = Payload;
    type Error = Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Error> {
        if self.id_len == 0 && self.msg_len == 0 && buf.len() >= 5 {
            let buf = buf.split_to(5);
            self.id_len = buf[0];
            self.msg_len = u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]);
            if self.id_len > MAX_ID_LEN {
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("id must be <={} bytes", MAX_ID_LEN),
                ));
            } else if self.msg_len > MAX_MSG_LEN {
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("msg must be <={} bytes", MAX_MSG_LEN),
                ));
            }
        }
        if self.id_len != 0
            && self.msg_len != 0
            && buf.len() >= usize::from(self.id_len) + (self.msg_len as usize)
        {
            let id_len = self.id_len;
            self.id_len = 0;

            let msg_len = self.msg_len;
            self.msg_len = 0;

            let id = buf.split_to(id_len as usize);
            let msg = buf.split_to(msg_len as usize);
            Ok(Some(Payload { id, msg }))
        } else {
            Ok(None)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    macro_rules! assert_decode {
        ($codec:expr, $bytes:expr, $id:expr, $msg:expr) => {{
            let res = $codec.decode(&mut $bytes).unwrap();
            assert!(res.is_some(), "decoding failure, expected Ok");
            let res = res.expect("decoding failure, expected payload");
            assert_eq!(res.id, $id, "id mismatch");
            assert_eq!(res.msg, $msg, "msg mismatch");
        }};
    }

    #[test]
    fn test_max_id_len() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![MAX_ID_LEN + 1, 0, 0, 0, 0]);
        let err = codec.decode(&mut bytes).unwrap_err();
        assert_eq!(
            err.description(),
            format!("id must be <={} bytes", MAX_ID_LEN)
        );
    }

    #[test]
    fn test_max_msg_len() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![1, 255, 255, 255, 255]);
        let err = codec.decode(&mut bytes).unwrap_err();
        assert_eq!(
            err.description(),
            format!("msg must be <={} bytes", MAX_MSG_LEN)
        );
    }

    #[test]
    fn test_encode_full_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::new();
        codec
            .encode(
                Payload {
                    id: vec![0, 1, 2, 3, 4, 5].into(),
                    msg: vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245].into(),
                },
                &mut bytes,
            )
            .unwrap();
        assert_eq!(
            bytes,
            vec![
                6, // ID len
                0, 0, 0, 11, // Msg len
                0, 1, 2, 3, 4, 5, // ID
                255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245 // Msg
            ]
        );
    }

    #[test]
    fn test_decode_full_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
        ]);

        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );
    }

    #[test]
    fn test_decode_multipart_frame() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, // Msg
        ]);
        let res = codec.decode(&mut bytes).unwrap();
        assert!(res.is_none());

        bytes.reserve(3);
        bytes.put_slice(&vec![247, 246, 245]);
        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );
    }

    #[test]
    fn test_decode_multiple_multipart_frames() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
            3,   // ID len
        ]);
        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );

        // Ensure the codec data is correct
        assert_eq!(bytes.len(), 1);
        assert_eq!(codec.id_len, 0);
        assert_eq!(codec.msg_len, 0);

        bytes.reserve(4);
        bytes.put_slice(&vec![0, 0, 0, 5]); // Write msg len
        let res = codec.decode(&mut bytes).unwrap();
        assert!(res.is_none());

        assert_eq!(bytes.len(), 0);
        assert_eq!(codec.id_len, 3);
        assert_eq!(codec.msg_len, 5);

        bytes.reserve(8);
        bytes.put_slice(&vec![
            1, 1, 1, // ID
            2, 2, 2, 2, 2, // Msg
        ]);
        assert_decode!(codec, bytes, vec![1, 1, 1], vec![2, 2, 2, 2, 2]);
    }

    #[test]
    fn test_decode_multiple_full_frames() {
        let mut codec = Codec::new();
        let mut bytes = BytesMut::from(vec![
            // First payload
            6, // ID len
            0, 0, 0, 11, // Msg len
            0, 1, 2, 3, 4, 5, // ID
            255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, // Msg
            // Second payload
            3, 0, 0, 0, 4, 1, 1, 1, 2, 2, 2, 2, // Third payload
            4, 0, 0, 0, 5, 3, 3, 3, 3, 4, 4, 4, 4, 4,
        ]);

        assert_decode!(
            codec,
            bytes,
            vec![0, 1, 2, 3, 4, 5],
            vec![255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245]
        );

        assert_decode!(codec, bytes, vec![1, 1, 1], vec![2, 2, 2, 2]);

        assert_decode!(codec, bytes, vec![3, 3, 3, 3], vec![4, 4, 4, 4, 4]);

        assert_eq!(bytes.len(), 0);
        assert_eq!(codec.id_len, 0);
        assert_eq!(codec.msg_len, 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::adjustment;
use util::nodemap::FxHashMap;
use lint::{LateContext, EarlyContext, LintContext, LintArray};
use lint::{LintPass, EarlyLintPass, LateLintPass};

use std::collections::hash_map::Entry::{Occupied, Vacant};

use syntax::ast;
use syntax::attr;
use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
use syntax::symbol::keywords;
use syntax::ptr::P;
use syntax::util::parser;
use syntax_pos::Span;

use rustc_back::slice;
use rustc::hir;
use rustc::hir::intravisit::FnKind;

declare_lint! {
    pub UNUSED_MUT,
    Warn,
    "detect mut variables which don't need to be mutable"
}

#[derive(Copy, Clone)]
pub struct UnusedMut;

impl UnusedMut {
    fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
        // collect all mutable pattern and group their NodeIDs by their Identifier to
        // avoid false warnings in match arms with multiple patterns

        let mut mutables = FxHashMap();
        for p in pats {
            p.each_binding(|_, id, span, path1| {
                let hir_id = cx.tcx.hir.node_to_hir_id(id);
                let bm = match cx.tables.pat_binding_modes().get(hir_id) {
                    Some(&bm) => bm,
                    None => span_bug!(span, "missing binding mode"),
                };
                let name = path1.node;
                if let ty::BindByValue(hir::MutMutable) = bm {
                    if !name.as_str().starts_with("_") {
                        match mutables.entry(name) {
                            Vacant(entry) => {
                                entry.insert(vec![id]);
                            }
                            Occupied(mut entry) => {
                                entry.get_mut().push(id);
                            }
                        }
                    }
                }
            });
        }

        let used_mutables = cx.tcx.used_mut_nodes.borrow();
        for (_, v) in &mutables {
            if !v.iter().any(|e| used_mutables.contains(e)) {
                cx.span_lint(UNUSED_MUT,
                             cx.tcx.hir.span(v[0]),
                             "variable does not need to be mutable");
            }
        }
    }
}

impl LintPass for UnusedMut {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_MUT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
    fn check_arm(&mut self, cx: &LateContext, a: &hir::Arm) {
        self.check_unused_mut_pat(cx, &a.pats)
    }

    fn check_local(&mut self, cx: &LateContext, l: &hir::Local) {
        self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
    }

    fn check_fn(&mut self,
                cx: &LateContext,
                _: FnKind,
                _: &hir::FnDecl,
                body: &hir::Body,
                _: Span,
                _: ast::NodeId) {
        for a in &body.arguments {
            self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
        }
    }
}

declare_lint! {
    pub UNUSED_MUST_USE,
    Warn,
    "unused result of a type flagged as #[must_use]"
}

declare_lint! {
    pub UNUSED_RESULTS,
    Allow,
    "unused result of an expression in a statement"
}

#[derive(Copy, Clone)]
pub struct UnusedResults;

impl LintPass for UnusedResults {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
    fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
        let expr = match s.node {
            hir::StmtSemi(ref expr, _) => &**expr,
            _ => return,
        };

        if let hir::ExprRet(..) = expr.node {
            return;
        }

        let t = cx.tables.expr_ty(&expr);
        let ty_warned = match t.sty {
            ty::TyTuple(ref tys, _) if tys.is_empty() => return,
            ty::TyNever => return,
            ty::TyAdt(def, _) => {
                if def.variants.is_empty() {
                    return;
                } else {
                    check_must_use(cx, def.did, s.span, "")
                }
            },
            _ => false,
        };

        let mut fn_warned = false;
        let mut op_warned = false;
        if cx.tcx.sess.features.borrow().fn_must_use {
            let maybe_def = match expr.node {
                hir::ExprCall(ref callee, _) => {
                    match callee.node {
                        hir::ExprPath(ref qpath) => {
                            Some(cx.tables.qpath_def(qpath, callee.hir_id))
                        },
                        _ => None
                    }
                },
                hir::ExprMethodCall(..) => {
                    cx.tables.type_dependent_defs().get(expr.hir_id).cloned()
                },
                _ => None
            };
            if let Some(def) = maybe_def {
                let def_id = def.def_id();
                fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
            }

            if let hir::ExprBinary(bin_op, ..) = expr.node {
                match bin_op.node {
                    // Hardcoding the comparison operators here seemed more
                    // expedient than the refactoring that would be needed to
                    // look up the `#[must_use]` attribute which does exist on
                    // the comparison trait methods
                    hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => {
                        let msg = "unused comparison which must be used";
                        cx.span_lint(UNUSED_MUST_USE, expr.span, msg);
                        op_warned = true;
                    },
                    _ => {},
                }
            }
        }

        if !(ty_warned || fn_warned || op_warned) {
            cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
        }

        fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str) -> bool {
            for attr in cx.tcx.get_attrs(def_id).iter() {
                if attr.check_name("must_use") {
                    let mut msg = format!("unused {}`{}` which must be used",
                                          describe_path, cx.tcx.item_path_str(def_id));
                    // check for #[must_use="..."]
                    if let Some(s) = attr.value_str() {
                        msg.push_str(": ");
                        msg.push_str(&s.as_str());
                    }
                    cx.span_lint(UNUSED_MUST_USE, sp, &msg);
                    return true;
                }
            }
            false
        }
    }
}

declare_lint! {
    pub PATH_STATEMENTS,
    Warn,
    "path statements with no effect"
}

#[derive(Copy, Clone)]
pub struct PathStatements;

impl LintPass for PathStatements {
    fn get_lints(&self) -> LintArray {
        lint_array!(PATH_STATEMENTS)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
    fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
        if let hir::StmtSemi(ref expr, _) = s.node {
            if let hir::ExprPath(_) = expr.node {
                cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
            }
        }
    }
}

declare_lint! {
    pub UNUSED_ATTRIBUTES,
    Warn,
    "detects attributes that were not used by the compiler"
}

#[derive(Copy, Clone)]
pub struct UnusedAttributes;

impl LintPass for UnusedAttributes {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_ATTRIBUTES)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
    fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
        debug!("checking attribute: {:?}", attr);
        let name = unwrap_or!(attr.name(), return);

        // Note that check_name() marks the attribute as used if it matches.
        for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
            match ty {
                AttributeType::Whitelisted if attr.check_name(name) => {
                    debug!("{:?} is Whitelisted", name);
                    break;
                }
                _ => (),
            }
        }

        let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
        for &(ref name, ty) in plugin_attributes.iter() {
            if ty == AttributeType::Whitelisted && attr.check_name(&name) {
                debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
                break;
            }
        }

        if !attr::is_used(attr) {
            debug!("Emitting warning for: {:?}", attr);
            cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
            // Is it a builtin attribute that must be used at the crate level?
            let known_crate = BUILTIN_ATTRIBUTES.iter()
                .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
                .is_some();

            // Has a plugin registered this attribute as one which must be used at
            // the crate level?
            let plugin_crate = plugin_attributes.iter()
                .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
                .is_some();
            if known_crate || plugin_crate {
                let msg = match attr.style {
                    ast::AttrStyle::Outer => {
                        "crate-level attribute should be an inner attribute: add an exclamation \
                         mark: #![foo]"
                    }
                    ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
                };
                cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
            }
        } else {
            debug!("Attr was used: {:?}", attr);
        }
    }
}

declare_lint! {
    UNUSED_PARENS,
    Warn,
    "`if`, `match`, `while` and `return` do not need parentheses"
}

#[derive(Copy, Clone)]
pub struct UnusedParens;

impl UnusedParens {
    fn check_unused_parens_core(&self,
                                cx: &EarlyContext,
                                value: &ast::Expr,
                                msg: &str,
                                struct_lit_needs_parens: bool) {
        if let ast::ExprKind::Paren(ref inner) = value.node {
            let necessary = struct_lit_needs_parens &&
                            parser::contains_exterior_struct_lit(&inner);
            if !necessary {
                cx.span_lint(UNUSED_PARENS,
                             value.span,
                             &format!("unnecessary parentheses around {}", msg))
            }
        }
    }
}

impl LintPass for UnusedParens {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_PARENS)
    }
}

impl EarlyLintPass for UnusedParens {
    fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
        use syntax::ast::ExprKind::*;
        let (value, msg, struct_lit_needs_parens) = match e.node {
            If(ref cond, ..) => (cond, "`if` condition", true),
            While(ref cond, ..) => (cond, "`while` condition", true),
            IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
            WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
            ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
            Match(ref head, _) => (head, "`match` head expression", true),
            Ret(Some(ref value)) => (value, "`return` value", false),
            Assign(_, ref value) => (value, "assigned value", false),
            AssignOp(.., ref value) => (value, "assigned value", false),
            InPlace(_, ref value) => (value, "emplacement value", false),
            _ => return,
        };
        self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
    }

    fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
        let (value, msg) = match s.node {
            ast::StmtKind::Local(ref local) => {
                match local.init {
                    Some(ref value) => (value, "assigned value"),
                    None => return,
                }
            }
            _ => return,
        };
        self.check_unused_parens_core(cx, &value, msg, false);
    }
}

declare_lint! {
    UNUSED_IMPORT_BRACES,
    Allow,
    "unnecessary braces around an imported item"
}

#[derive(Copy, Clone)]
pub struct UnusedImportBraces;

impl LintPass for UnusedImportBraces {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_IMPORT_BRACES)
    }
}

impl EarlyLintPass for UnusedImportBraces {
    fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
        if let ast::ItemKind::Use(ref view_path) = item.node {
            if let ast::ViewPathList(_, ref items) = view_path.node {
                if items.len() == 1 && items[0].node.name.name != keywords::SelfValue.name() {
                    let msg = format!("braces around {} is unnecessary", items[0].node.name);
                    cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
                }
            }
        }
    }
}

declare_lint! {
    UNUSED_ALLOCATION,
    Warn,
    "detects unnecessary allocations that can be eliminated"
}

#[derive(Copy, Clone)]
pub struct UnusedAllocation;

impl LintPass for UnusedAllocation {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_ALLOCATION)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
    fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
        match e.node {
            hir::ExprBox(_) => {}
            _ => return,
        }

        for adj in cx.tables.expr_adjustments(e) {
            if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                let msg = match m {
                    hir::MutImmutable => "unnecessary allocation, use & instead",
                    hir::MutMutable => "unnecessary allocation, use &mut instead"
                };
                cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
            }
        }
    }
}
<commit_msg>code suggestion for unused-parentheses lint<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::adjustment;
use util::nodemap::FxHashMap;
use lint::{LateContext, EarlyContext, LintContext, LintArray};
use lint::{LintPass, EarlyLintPass, LateLintPass};

use std::collections::hash_map::Entry::{Occupied, Vacant};

use syntax::ast;
use syntax::attr;
use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
use syntax::symbol::keywords;
use syntax::ptr::P;
use syntax::print::pprust;
use syntax::util::parser;
use syntax_pos::Span;

use rustc_back::slice;
use rustc::hir;
use rustc::hir::intravisit::FnKind;

declare_lint! {
    pub UNUSED_MUT,
    Warn,
    "detect mut variables which don't need to be mutable"
}

#[derive(Copy, Clone)]
pub struct UnusedMut;

impl UnusedMut {
    fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
        // collect all mutable pattern and group their NodeIDs by their Identifier to
        // avoid false warnings in match arms with multiple patterns

        let mut mutables = FxHashMap();
        for p in pats {
            p.each_binding(|_, id, span, path1| {
                let hir_id = cx.tcx.hir.node_to_hir_id(id);
                let bm = match cx.tables.pat_binding_modes().get(hir_id) {
                    Some(&bm) => bm,
                    None => span_bug!(span, "missing binding mode"),
                };
                let name = path1.node;
                if let ty::BindByValue(hir::MutMutable) = bm {
                    if !name.as_str().starts_with("_") {
                        match mutables.entry(name) {
                            Vacant(entry) => {
                                entry.insert(vec![id]);
                            }
                            Occupied(mut entry) => {
                                entry.get_mut().push(id);
                            }
                        }
                    }
                }
            });
        }

        let used_mutables = cx.tcx.used_mut_nodes.borrow();
        for (_, v) in &mutables {
            if !v.iter().any(|e| used_mutables.contains(e)) {
                cx.span_lint(UNUSED_MUT,
                             cx.tcx.hir.span(v[0]),
                             "variable does not need to be mutable");
            }
        }
    }
}

impl LintPass for UnusedMut {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_MUT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
    fn check_arm(&mut self, cx: &LateContext, a: &hir::Arm) {
        self.check_unused_mut_pat(cx, &a.pats)
    }

    fn check_local(&mut self, cx: &LateContext, l: &hir::Local) {
        self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
    }

    fn check_fn(&mut self,
                cx: &LateContext,
                _: FnKind,
                _: &hir::FnDecl,
                body: &hir::Body,
                _: Span,
                _: ast::NodeId) {
        for a in &body.arguments {
            self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
        }
    }
}

declare_lint! {
    pub UNUSED_MUST_USE,
    Warn,
    "unused result of a type flagged as #[must_use]"
}

declare_lint! {
    pub UNUSED_RESULTS,
    Allow,
    "unused result of an expression in a statement"
}

#[derive(Copy, Clone)]
pub struct UnusedResults;

impl LintPass for UnusedResults {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
    fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
        let expr = match s.node {
            hir::StmtSemi(ref expr, _) => &**expr,
            _ => return,
        };

        if let hir::ExprRet(..) = expr.node {
            return;
        }

        let t = cx.tables.expr_ty(&expr);
        let ty_warned = match t.sty {
            ty::TyTuple(ref tys, _) if tys.is_empty() => return,
            ty::TyNever => return,
            ty::TyAdt(def, _) => {
                if def.variants.is_empty() {
                    return;
                } else {
                    check_must_use(cx, def.did, s.span, "")
                }
            },
            _ => false,
        };

        let mut fn_warned = false;
        let mut op_warned = false;
        if cx.tcx.sess.features.borrow().fn_must_use {
            let maybe_def = match expr.node {
                hir::ExprCall(ref callee, _) => {
                    match callee.node {
                        hir::ExprPath(ref qpath) => {
                            Some(cx.tables.qpath_def(qpath, callee.hir_id))
                        },
                        _ => None
                    }
                },
                hir::ExprMethodCall(..) => {
                    cx.tables.type_dependent_defs().get(expr.hir_id).cloned()
                },
                _ => None
            };
            if let Some(def) = maybe_def {
                let def_id = def.def_id();
                fn_warned = check_must_use(cx, def_id, s.span, "return value of ");
            }

            if let hir::ExprBinary(bin_op, ..) = expr.node {
                match bin_op.node {
                    // Hardcoding the comparison operators here seemed more
                    // expedient than the refactoring that would be needed to
                    // look up the `#[must_use]` attribute which does exist on
                    // the comparison trait methods
                    hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => {
                        let msg = "unused comparison which must be used";
                        cx.span_lint(UNUSED_MUST_USE, expr.span, msg);
                        op_warned = true;
                    },
                    _ => {},
                }
            }
        }

        if !(ty_warned || fn_warned || op_warned) {
            cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
        }

        fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str) -> bool {
            for attr in cx.tcx.get_attrs(def_id).iter() {
                if attr.check_name("must_use") {
                    let mut msg = format!("unused {}`{}` which must be used",
                                          describe_path, cx.tcx.item_path_str(def_id));
                    // check for #[must_use="..."]
                    if let Some(s) = attr.value_str() {
                        msg.push_str(": ");
                        msg.push_str(&s.as_str());
                    }
                    cx.span_lint(UNUSED_MUST_USE, sp, &msg);
                    return true;
                }
            }
            false
        }
    }
}

declare_lint! {
    pub PATH_STATEMENTS,
    Warn,
    "path statements with no effect"
}

#[derive(Copy, Clone)]
pub struct PathStatements;

impl LintPass for PathStatements {
    fn get_lints(&self) -> LintArray {
        lint_array!(PATH_STATEMENTS)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
    fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
        if let hir::StmtSemi(ref expr, _) = s.node {
            if let hir::ExprPath(_) = expr.node {
                cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
            }
        }
    }
}

declare_lint! {
    pub UNUSED_ATTRIBUTES,
    Warn,
    "detects attributes that were not used by the compiler"
}

#[derive(Copy, Clone)]
pub struct UnusedAttributes;

impl LintPass for UnusedAttributes {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_ATTRIBUTES)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
    fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
        debug!("checking attribute: {:?}", attr);
        let name = unwrap_or!(attr.name(), return);

        // Note that check_name() marks the attribute as used if it matches.
        for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
            match ty {
                AttributeType::Whitelisted if attr.check_name(name) => {
                    debug!("{:?} is Whitelisted", name);
                    break;
                }
                _ => (),
            }
        }

        let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
        for &(ref name, ty) in plugin_attributes.iter() {
            if ty == AttributeType::Whitelisted && attr.check_name(&name) {
                debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
                break;
            }
        }

        if !attr::is_used(attr) {
            debug!("Emitting warning for: {:?}", attr);
            cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
            // Is it a builtin attribute that must be used at the crate level?
            let known_crate = BUILTIN_ATTRIBUTES.iter()
                .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
                .is_some();

            // Has a plugin registered this attribute as one which must be used at
            // the crate level?
            let plugin_crate = plugin_attributes.iter()
                .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
                .is_some();
            if known_crate || plugin_crate {
                let msg = match attr.style {
                    ast::AttrStyle::Outer => {
                        "crate-level attribute should be an inner attribute: add an exclamation \
                         mark: #![foo]"
                    }
                    ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
                };
                cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
            }
        } else {
            debug!("Attr was used: {:?}", attr);
        }
    }
}

declare_lint! {
    UNUSED_PARENS,
    Warn,
    "`if`, `match`, `while` and `return` do not need parentheses"
}

#[derive(Copy, Clone)]
pub struct UnusedParens;

impl UnusedParens {
    fn check_unused_parens_core(&self,
                                cx: &EarlyContext,
                                value: &ast::Expr,
                                msg: &str,
                                struct_lit_needs_parens: bool) {
        if let ast::ExprKind::Paren(ref inner) = value.node {
            let necessary = struct_lit_needs_parens &&
                            parser::contains_exterior_struct_lit(&inner);
            if !necessary {
                let span_msg = format!("unnecessary parentheses around {}", msg);
                let mut err = cx.struct_span_lint(UNUSED_PARENS,
                                                  value.span,
                                                  &span_msg);
                let parens_removed = pprust::expr_to_string(value)
                    .trim_matches(|c| c == '(' || c == ')').to_owned();
                err.span_suggestion_short(value.span,
                                          "remove these parentheses",
                                          parens_removed);
                err.emit();
            }
        }
    }
}

impl LintPass for UnusedParens {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_PARENS)
    }
}

impl EarlyLintPass for UnusedParens {
    fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
        use syntax::ast::ExprKind::*;
        let (value, msg, struct_lit_needs_parens) = match e.node {
            If(ref cond, ..) => (cond, "`if` condition", true),
            While(ref cond, ..) => (cond, "`while` condition", true),
            IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
            WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
            ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
            Match(ref head, _) => (head, "`match` head expression", true),
            Ret(Some(ref value)) => (value, "`return` value", false),
            Assign(_, ref value) => (value, "assigned value", false),
            AssignOp(.., ref value) => (value, "assigned value", false),
            InPlace(_, ref value) => (value, "emplacement value", false),
            _ => return,
        };
        self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
    }

    fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
        let (value, msg) = match s.node {
            ast::StmtKind::Local(ref local) => {
                match local.init {
                    Some(ref value) => (value, "assigned value"),
                    None => return,
                }
            }
            _ => return,
        };
        self.check_unused_parens_core(cx, &value, msg, false);
    }
}

declare_lint! {
    UNUSED_IMPORT_BRACES,
    Allow,
    "unnecessary braces around an imported item"
}

#[derive(Copy, Clone)]
pub struct UnusedImportBraces;

impl LintPass for UnusedImportBraces {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_IMPORT_BRACES)
    }
}

impl EarlyLintPass for UnusedImportBraces {
    fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
        if let ast::ItemKind::Use(ref view_path) = item.node {
            if let ast::ViewPathList(_, ref items) = view_path.node {
                if items.len() == 1 && items[0].node.name.name != keywords::SelfValue.name() {
                    let msg = format!("braces around {} is unnecessary", items[0].node.name);
                    cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
                }
            }
        }
    }
}

declare_lint! {
    UNUSED_ALLOCATION,
    Warn,
    "detects unnecessary allocations that can be eliminated"
}

#[derive(Copy, Clone)]
pub struct UnusedAllocation;

impl LintPass for UnusedAllocation {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNUSED_ALLOCATION)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
    fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
        match e.node {
            hir::ExprBox(_) => {}
            _ => return,
        }

        for adj in cx.tables.expr_adjustments(e) {
            if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                let msg = match m {
                    hir::MutImmutable => "unnecessary allocation, use & instead",
                    hir::MutMutable => "unnecessary allocation, use &mut instead"
                };
                cx.span_lint(UNUSED_ALLOCATION, e.span, msg);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! [PUT /_matrix/federation/v1/send/{txnId}](https://matrix.org/docs/spec/server_server/r0.1.3#put-matrix-federation-v1-send-txnid)

use std::{collections::BTreeMap, time::SystemTime};

use ruma_api::ruma_api;
use ruma_events::pdu::Pdu;
use ruma_identifiers::{EventId, ServerName};
use ruma_serde::Raw;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

ruma_api! {
    metadata: {
        description: "Send transaction messages to another server",
        name: "send_transaction_message",
        method: PUT,
        path: "/_matrix/federation/v1/send/:transaction_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// A transaction ID unique between sending and receiving homeservers.
        #[ruma_api(path)]
        pub transaction_id: &'a str,

        /// The server_name of the homeserver sending this transaction.
        pub origin: &'a ServerName,

        /// POSIX timestamp in milliseconds on the originating homeserver when this transaction
        /// started.
        #[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
        pub origin_server_ts: SystemTime,

        /// List of persistent updates to rooms.
        ///
        /// Must not be more than 50 items.
        pub pdus: &'a [Raw<Pdu>],

        /// List of ephemeral messages.
        ///
        /// Must not be more than 100 items.
        #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
        pub edus: &'a [Raw<Edu>],
    }

    #[derive(Default)]
    response: {
        /// Map of event IDs and response for each PDU given in the request.
        #[serde(with = "crate::serde::pdu_process_response")]
        pub pdus: BTreeMap<EventId, Result<(), String>>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID, origin, timestamp.
    ///
    /// The PDU and EDU lists will start off empty.
    pub fn new(
        transaction_id: &'a str,
        origin: &'a ServerName,
        origin_server_ts: SystemTime,
    ) -> Self {
        Self { transaction_id, origin, origin_server_ts, pdus: &[], edus: &[] }
    }
}

impl Response {
    /// Creates a new `Response` with the given PDUs.
    pub fn new(pdus: BTreeMap<EventId, Result<(), String>>) -> Self {
        Self { pdus }
    }
}

/// Type for passing ephemeral data to homeservers.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Edu {
    /// Type of the ephemeral message.
    pub edu_type: String,

    /// Content of ephemeral message
    pub content: JsonValue,
}
<commit_msg>federation-api: Make pdus of transactions optional under `unstable-pre-spec`<commit_after>//! [PUT /_matrix/federation/v1/send/{txnId}](https://matrix.org/docs/spec/server_server/r0.1.3#put-matrix-federation-v1-send-txnid)

use std::{collections::BTreeMap, time::SystemTime};

use ruma_api::ruma_api;
use ruma_events::pdu::Pdu;
use ruma_identifiers::{EventId, ServerName};
use ruma_serde::Raw;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

ruma_api! {
    metadata: {
        description: "Send transaction messages to another server",
        name: "send_transaction_message",
        method: PUT,
        path: "/_matrix/federation/v1/send/:transaction_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// A transaction ID unique between sending and receiving homeservers.
        #[ruma_api(path)]
        pub transaction_id: &'a str,

        /// The server_name of the homeserver sending this transaction.
        pub origin: &'a ServerName,

        /// POSIX timestamp in milliseconds on the originating homeserver when this transaction
        /// started.
        #[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
        pub origin_server_ts: SystemTime,

        /// List of persistent updates to rooms.
        ///
        /// Must not be more than 50 items.
        #[cfg_attr(feature = "unstable-pre-spec", serde(default, skip_serializing_if = "<[_]>::is_empty"))]
        pub pdus: &'a [Raw<Pdu>],

        /// List of ephemeral messages.
        ///
        /// Must not be more than 100 items.
        #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
        pub edus: &'a [Raw<Edu>],
    }

    #[derive(Default)]
    response: {
        /// Map of event IDs and response for each PDU given in the request.
        #[serde(with = "crate::serde::pdu_process_response")]
        pub pdus: BTreeMap<EventId, Result<(), String>>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID, origin, timestamp.
    ///
    /// The PDU and EDU lists will start off empty.
    pub fn new(
        transaction_id: &'a str,
        origin: &'a ServerName,
        origin_server_ts: SystemTime,
    ) -> Self {
        Self { transaction_id, origin, origin_server_ts, pdus: &[], edus: &[] }
    }
}

impl Response {
    /// Creates a new `Response` with the given PDUs.
    pub fn new(pdus: BTreeMap<EventId, Result<(), String>>) -> Self {
        Self { pdus }
    }
}

/// Type for passing ephemeral data to homeservers.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Edu {
    /// Type of the ephemeral message.
    pub edu_type: String,

    /// Content of ephemeral message
    pub content: JsonValue,
}
<|endoftext|>


<commit_before>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

use libc;

use ffi::CString;
use marker;
use mem;
use sync::atomic::{AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            ::sys::weak::Weak::new(stringify!($name));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak {
            name,
            addr: AtomicUsize::new(1),
            _marker: marker::PhantomData,
        }
    }

    pub fn get(&self) -> Option<&F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            if self.addr.load(Ordering::SeqCst) == 1 {
                self.addr.store(fetch(self.name), Ordering::SeqCst);
            }
            if self.addr.load(Ordering::SeqCst) == 0 {
                None
            } else {
                mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
            }
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CString::new(name) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(target_os = "linux"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use libc;
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(target_os = "linux")]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            syscall(
                concat_idents!(SYS_, $name),
                $($arg_name as c_long),*
            ) as $ret
        }
    )
}
<commit_msg>Rollup merge of #58442 - cuviper:unix-weak, r=alexcrichton<commit_after>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

use libc;

use ffi::CStr;
use marker;
use mem;
use sync::atomic::{AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            ::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak {
            name,
            addr: AtomicUsize::new(1),
            _marker: marker::PhantomData,
        }
    }

    pub fn get(&self) -> Option<F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            if self.addr.load(Ordering::SeqCst) == 1 {
                self.addr.store(fetch(self.name), Ordering::SeqCst);
            }
            match self.addr.load(Ordering::SeqCst) {
                0 => None,
                addr => Some(mem::transmute_copy::<usize, F>(&addr)),
            }
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(target_os = "linux"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use libc;
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(target_os = "linux")]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            syscall(
                concat_idents!(SYS_, $name),
                $($arg_name as c_long),*
            ) as $ret
        }
    )
}
<|endoftext|>


<commit_before>// Farbfeld filter that applies a cool blurring effect over images
// Usage: png2ff < greyscale.png | blur | ff2png > false-colored.png

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate byteorder;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

#[derive (Clone, Copy)]
struct FfPixel {
	pub r: u16,
	pub g: u16,
	pub b: u16,
	pub a: u16,
}

#[derive (Clone, Copy, Debug, PartialEq)]
struct PlaneCoord {
	pub x: i32,
	pub y: i32,
}

impl PlaneCoord {
	pub fn contains_x (&self, x: i32) -> bool {
		x >= 0 && x < self.x
	}

	pub fn contains_y (&self, y: i32) -> bool {
		y >= 0 && y < self.y
	}

	pub fn contains (&self, x: i32, y: i32) -> bool {
		self.contains_x (x) &&
		self.contains_y (y)
	}

	pub fn clamp_x (&self, x: i32) -> i32 {
		return if x < 0 {
			0
		}
		else if x >= self.x {
			self.x - 1
		}
		else {
			x
		}
	}

	pub fn clamp_y (&self, y: i32) -> i32 {
		return if y < 0 {
			0
		}
		else if y >= self.y {
			self.y - 1
		}
		else {
			y
		}
	}

	pub fn clamp (&self, pc: &PlaneCoord) -> PlaneCoord {
		PlaneCoord {
			x: self.clamp_x (pc.x),
			y: self.clamp_y (pc.y),
		}
	}

	pub fn index (&self, pc: &PlaneCoord) -> i32 {
		let pc = self.clamp (pc);

		pc.y * self.x + pc.x
	}

	pub fn clamped_index (&self, pc: &PlaneCoord) -> i32 {
		self.index (&self.clamp (pc))
	}
}

struct HdrPlane {
	pub size: PlaneCoord,
	pub pixels: Vec <f64>,
}

impl HdrPlane {
	pub fn new (size: PlaneCoord) -> HdrPlane {
		HdrPlane {
			size: size,
			pixels: vec! [0.0; (size.x * size.y) as usize],
		}
	}
}

fn read_pixel <T> (reader: &mut T) -> FfPixel where T: ReadBytesExt {
	FfPixel {
		r: reader.read_u16::<BigEndian> ().unwrap (),
		g: reader.read_u16::<BigEndian> ().unwrap (),
		b: reader.read_u16::<BigEndian> ().unwrap (),
		a: reader.read_u16::<BigEndian> ().unwrap (),
	}
}

fn write_pixel <T> (writer: &mut T, pix: &FfPixel) where T: WriteBytesExt {
	writer.write_u16::<BigEndian> (pix.r).unwrap ();
	writer.write_u16::<BigEndian> (pix.g).unwrap ();
	writer.write_u16::<BigEndian> (pix.b).unwrap ();
	writer.write_u16::<BigEndian> (pix.a).unwrap ();
}

fn pascal (n: u32) -> Vec <u64> {
	match n {
		0 => {
			vec! []
		}
		1 => {
			vec! [1]
		},
		2 => {
			vec! [1, 1]
		},
		3 => {
			vec! [1, 2, 1]
		},
		4 => {
			vec! [1, 3, 3, 1]
		}
		5 => {
			vec! [1, 4, 6, 4, 1]
		},
		_ => {
			let step = 5;
			let prev_row = pascal (n - step + 1);
			let step_row = pascal (step);

			let mut output = vec! [];
			for _ in 0..n {
				output.push (0);
			}

			for a in 0..prev_row.len () {
				for b in 0..step_row.len () {
					output [a + b] += prev_row [a] * step_row [b];
				}
			}

			output
		}
	}
}

fn blur_hor (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![0.0; (sz.x * sz.y) as usize];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			for src_x in sz.clamp_x (x + 0 + offset)..sz.clamp_x (x + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: src_x,
					y: y
				});

				pixels [dest_index as usize] += filter_f [(src_x - x - offset) as usize] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn blur_vert (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			pixels.push (0.0f64);

			for src_y in sz.clamp_y (y + 0 + offset)..sz.clamp_y (y + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: x,
					y: src_y,
				});

				pixels [dest_index as usize] += filter_f [(src_y - y - offset) as usize] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn read_farbfeld_grey <T> (reader: &mut T) -> HdrPlane where T: ReadBytesExt {
	let mut magic = [0; 8];
	reader.read (&mut magic [..]).unwrap ();

	// TODO: Assert that magic == 'farbfeld'
	//assert_eq! (magic, &"farbfeld");

	let width = reader.read_u32::<BigEndian>().unwrap() as i32;
	let height = reader.read_u32::<BigEndian>().unwrap() as i32;

	writeln!(&mut io::stderr(), "{} x {}", width, height).expect("failed printing to stderr");

	let mut pixels = vec![0.0; (width * height) as usize];

	for i in 0 .. width * height {
		let gamma = read_pixel (reader).g as f64 / 65536.0;
		pixels [i as usize] = gamma * gamma;
	}

	HdrPlane {
		size: PlaneCoord {
			x: width,
			y: height,
		},
		pixels: pixels,
	}
}

fn write_farbfeld_plane <T> (writer: &mut T, plane: &HdrPlane) where T: WriteBytesExt
{
	write_farbfeld (writer, &plane.size, plane.pixels.iter ().map (|x| {
		let val = (x.sqrt ().min (1.0) * 65535.0) as u16;

		FfPixel {
			r: val,
			g: val,
			b: val,
			a: 65535,
		}
	}));
}

fn double_to_ff (val: f64) -> u16 {
	(val.sqrt ().min (1.0) * 65535.0) as u16
}

fn write_farbfeld <T, I> (writer: &mut T, size: &PlaneCoord, pixels: I ) where T: WriteBytesExt, I: Iterator <Item = FfPixel>
{
	writer.write ("farbfeld".as_bytes ()).expect ("printing farbfeld");

	writer.write_u32::<BigEndian> (size.x as u32).unwrap ();
	writer.write_u32::<BigEndian> (size.y as u32).unwrap ();

	for pixel in pixels.take ((size.x * size.y) as usize) {
		write_pixel (writer, &pixel);
	}
}

fn blur (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	blur_vert (&blur_hor (input_plane, filter), filter)
}

fn blur_n (input_plane: &HdrPlane, filter: &Vec <u64>, n: u32) -> HdrPlane {
	match n {
		0 => {
			// I know this is dumb
			panic! ("Can't blur an image 0 times")
		},
		1 => {
			blur (input_plane, filter)
		},
		_ => {
			blur (&blur_n (input_plane, filter, n - 1), filter)
		},
	}
}

fn main () {
	// Reader
	let mut reader = BufReader::new (io::stdin ());

	let filter = pascal (41);

	let input_plane = read_farbfeld_grey (&mut reader);
	let blurry_1 = blur_n (&input_plane, &filter, 1);
	let blurry_10 = blur_n (&blurry_1, &filter, 9);
	let blurry_20 = blur_n (&blurry_10, &filter, 10);

	let sum_iter = (0..(input_plane.size.x * input_plane.size.y) as usize).map (|i| {
		let r = input_plane.pixels [i];
		let g = r;
		let b = r;

		let r = r + blurry_1.pixels [i] * 512.0 / 256.0;
		let g = g + blurry_1.pixels [i] * 256.0 / 256.0;

		let r = r + blurry_20.pixels [i] * 59.0 / 256.0;
		let b = b + blurry_20.pixels [i] * 60.0 / 256.0;

		FfPixel {
			r: double_to_ff (r),
			g: double_to_ff (g),
			b: double_to_ff (b),
			a: 65535,
		}
	});

	// Write
	{
		let mut writer = BufWriter::new (io::stdout ());

		write_farbfeld (&mut writer, &input_plane.size, sum_iter);
	}

	writeln!(&mut io::stderr(), "filter {:?}", filter).expect("failed printing to stderr");
}
<commit_msg>Trying to use more iterators in the blur<commit_after>// Farbfeld filter that applies a cool blurring effect over images
// Usage: png2ff < greyscale.png | blur | ff2png > false-colored.png

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate byteorder;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

#[derive (Clone, Copy)]
struct FfPixel {
	pub r: u16,
	pub g: u16,
	pub b: u16,
	pub a: u16,
}

#[derive (Clone, Copy, Debug, PartialEq)]
struct PlaneCoord {
	pub x: i32,
	pub y: i32,
}

impl PlaneCoord {
	pub fn contains_x (&self, x: i32) -> bool {
		x >= 0 && x < self.x
	}

	pub fn contains_y (&self, y: i32) -> bool {
		y >= 0 && y < self.y
	}

	pub fn contains (&self, x: i32, y: i32) -> bool {
		self.contains_x (x) &&
		self.contains_y (y)
	}

	pub fn clamp_x (&self, x: i32) -> i32 {
		return if x < 0 {
			0
		}
		else if x >= self.x {
			self.x - 1
		}
		else {
			x
		}
	}

	pub fn clamp_y (&self, y: i32) -> i32 {
		return if y < 0 {
			0
		}
		else if y >= self.y {
			self.y - 1
		}
		else {
			y
		}
	}

	pub fn clamp (&self, pc: &PlaneCoord) -> PlaneCoord {
		PlaneCoord {
			x: self.clamp_x (pc.x),
			y: self.clamp_y (pc.y),
		}
	}

	pub fn index (&self, pc: &PlaneCoord) -> i32 {
		let pc = self.clamp (pc);

		pc.y * self.x + pc.x
	}

	pub fn clamped_index (&self, pc: &PlaneCoord) -> i32 {
		self.index (&self.clamp (pc))
	}
}

struct HdrPlane {
	pub size: PlaneCoord,
	pub pixels: Vec <f64>,
}

impl HdrPlane {
	pub fn new (size: PlaneCoord) -> HdrPlane {
		HdrPlane {
			size: size,
			pixels: vec! [0.0; (size.x * size.y) as usize],
		}
	}
}

fn read_pixel <T> (reader: &mut T) -> FfPixel where T: ReadBytesExt {
	FfPixel {
		r: reader.read_u16::<BigEndian> ().unwrap (),
		g: reader.read_u16::<BigEndian> ().unwrap (),
		b: reader.read_u16::<BigEndian> ().unwrap (),
		a: reader.read_u16::<BigEndian> ().unwrap (),
	}
}

fn write_pixel <T> (writer: &mut T, pix: &FfPixel) where T: WriteBytesExt {
	writer.write_u16::<BigEndian> (pix.r).unwrap ();
	writer.write_u16::<BigEndian> (pix.g).unwrap ();
	writer.write_u16::<BigEndian> (pix.b).unwrap ();
	writer.write_u16::<BigEndian> (pix.a).unwrap ();
}

fn pascal (n: u32) -> Vec <u64> {
	match n {
		0 => {
			vec! []
		}
		1 => {
			vec! [1]
		},
		2 => {
			vec! [1, 1]
		},
		3 => {
			vec! [1, 2, 1]
		},
		4 => {
			vec! [1, 3, 3, 1]
		}
		5 => {
			vec! [1, 4, 6, 4, 1]
		},
		_ => {
			let step = 5;
			let prev_row = pascal (n - step + 1);
			let step_row = pascal (step);

			let mut output = vec! [];
			for _ in 0..n {
				output.push (0);
			}

			for a in 0..prev_row.len () {
				for b in 0..step_row.len () {
					output [a + b] += prev_row [a] * step_row [b];
				}
			}

			output
		}
	}
}

fn blur_hor (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![0.0; (sz.x * sz.y) as usize];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});
			/*
			for src_x in sz.clamp_x (x + 0 + offset)..sz.clamp_x (x + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: src_x,
					y: y
				});

				pixels [dest_index as usize] += filter_f [(src_x - x - offset) as usize] * input_plane.pixels [src_index as usize];
			}
			*/
			pixels [dest_index as usize] = filter_f.iter ().zip ((sz.clamp_x (x + 0 + offset)..sz.clamp_x (x + filter_f.len () as i32)).map (|src_x| input_plane.pixels [sz.index (&PlaneCoord { x: src_x, y: y}) as usize])).map (|(f, px)| f * px).sum ();
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn blur_vert (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			pixels.push (0.0f64);

			for src_y in sz.clamp_y (y + 0 + offset)..sz.clamp_y (y + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: x,
					y: src_y,
				});

				pixels [dest_index as usize] += filter_f [(src_y - y - offset) as usize] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn read_farbfeld_grey <T> (reader: &mut T) -> HdrPlane where T: ReadBytesExt {
	let mut magic = [0; 8];
	reader.read (&mut magic [..]).unwrap ();

	// TODO: Assert that magic == 'farbfeld'
	//assert_eq! (magic, &"farbfeld");

	let width = reader.read_u32::<BigEndian>().unwrap() as i32;
	let height = reader.read_u32::<BigEndian>().unwrap() as i32;

	writeln!(&mut io::stderr(), "{} x {}", width, height).expect("failed printing to stderr");

	let mut pixels = vec![0.0; (width * height) as usize];

	for i in 0 .. width * height {
		let gamma = read_pixel (reader).g as f64 / 65536.0;
		pixels [i as usize] = gamma * gamma;
	}

	HdrPlane {
		size: PlaneCoord {
			x: width,
			y: height,
		},
		pixels: pixels,
	}
}

fn write_farbfeld_plane <T> (writer: &mut T, plane: &HdrPlane) where T: WriteBytesExt
{
	write_farbfeld (writer, &plane.size, plane.pixels.iter ().map (|x| {
		let val = (x.sqrt ().min (1.0) * 65535.0) as u16;

		FfPixel {
			r: val,
			g: val,
			b: val,
			a: 65535,
		}
	}));
}

fn double_to_ff (val: f64) -> u16 {
	(val.sqrt ().min (1.0) * 65535.0) as u16
}

fn write_farbfeld <T, I> (writer: &mut T, size: &PlaneCoord, pixels: I ) where T: WriteBytesExt, I: Iterator <Item = FfPixel>
{
	writer.write ("farbfeld".as_bytes ()).expect ("printing farbfeld");

	writer.write_u32::<BigEndian> (size.x as u32).unwrap ();
	writer.write_u32::<BigEndian> (size.y as u32).unwrap ();

	for pixel in pixels.take ((size.x * size.y) as usize) {
		write_pixel (writer, &pixel);
	}
}

fn blur (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	blur_vert (&blur_hor (input_plane, filter), filter)
}

fn blur_n (input_plane: &HdrPlane, filter: &Vec <u64>, n: u32) -> HdrPlane {
	match n {
		0 => {
			// I know this is dumb
			panic! ("Can't blur an image 0 times")
		},
		1 => {
			blur (input_plane, filter)
		},
		_ => {
			blur (&blur_n (input_plane, filter, n - 1), filter)
		},
	}
}

fn main () {
	// Reader
	let mut reader = BufReader::new (io::stdin ());

	let filter = pascal (41);

	let input_plane = read_farbfeld_grey (&mut reader);
	let blurry_1 = blur_n (&input_plane, &filter, 1);
	let blurry_10 = blur_n (&blurry_1, &filter, 9);
	let blurry_20 = blur_n (&blurry_10, &filter, 10);

	let sum_iter = (0..(input_plane.size.x * input_plane.size.y) as usize).map (|i| {
		let r = input_plane.pixels [i];
		let g = r;
		let b = r;

		let r = r + blurry_1.pixels [i] * 512.0 / 256.0;
		let g = g + blurry_1.pixels [i] * 256.0 / 256.0;

		let r = r + blurry_20.pixels [i] * 59.0 / 256.0;
		let b = b + blurry_20.pixels [i] * 60.0 / 256.0;

		FfPixel {
			r: double_to_ff (r),
			g: double_to_ff (g),
			b: double_to_ff (b),
			a: 65535,
		}
	});

	// Write
	{
		let mut writer = BufWriter::new (io::stdout ());

		write_farbfeld (&mut writer, &input_plane.size, sum_iter);
	}

	writeln!(&mut io::stderr(), "filter {:?}", filter).expect("failed printing to stderr");
}
<|endoftext|>