<commit_before>/// A simple static assertion macro.
#[macro_export]
#[allow_internal_unstable(type_ascription)]
macro_rules! static_assert {
    ($test:expr) => {
        // Use the bool to access an array such that if the bool is false, the access
        // is out-of-bounds.
        #[allow(dead_code)]
        const _: () = [()][!($test: bool) as usize];
    };
}

/// Type size assertion. The first argument is a type and the second argument is its expected size.
#[macro_export]
macro_rules! static_assert_size {
    ($ty:ty, $size:expr) => {
        const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
    };
}

#[macro_export]
macro_rules! enum_from_u32 {
    ($(#[$attr:meta])* pub enum $name:ident {
        $($variant:ident = $e:expr,)*
    }) => {
        $(#[$attr])*
        pub enum $name {
            $($variant = $e),*
        }

        impl $name {
            pub fn from_u32(u: u32) -> Option<$name> {
                $(if u == $name::$variant as u32 {
                    return Some($name::$variant)
                })*
                None
            }
        }
    };
    ($(#[$attr:meta])* pub enum $name:ident {
        $($variant:ident,)*
    }) => {
        $(#[$attr])*
        pub enum $name {
            $($variant,)*
        }

        impl $name {
            pub fn from_u32(u: u32) -> Option<$name> {
                $(if u == $name::$variant as u32 {
                    return Some($name::$variant)
                })*
                None
            }
        }
    }
}
<commit_msg>Rollup merge of #76963 - est31:remove_static_assert, r=oli-obk<commit_after>/// Type size assertion. The first argument is a type and the second argument is its expected size.
#[macro_export]
macro_rules! static_assert_size {
    ($ty:ty, $size:expr) => {
        const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
    };
}

#[macro_export]
macro_rules! enum_from_u32 {
    ($(#[$attr:meta])* pub enum $name:ident {
        $($variant:ident = $e:expr,)*
    }) => {
        $(#[$attr])*
        pub enum $name {
            $($variant = $e),*
        }

        impl $name {
            pub fn from_u32(u: u32) -> Option<$name> {
                $(if u == $name::$variant as u32 {
                    return Some($name::$variant)
                })*
                None
            }
        }
    };
    ($(#[$attr:meta])* pub enum $name:ident {
        $($variant:ident,)*
    }) => {
        $(#[$attr])*
        pub enum $name {
            $($variant,)*
        }

        impl $name {
            pub fn from_u32(u: u32) -> Option<$name> {
                $(if u == $name::$variant as u32 {
                    return Some($name::$variant)
                })*
                None
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    time::{Duration, Instant},
    mem,
    io::{stderr, Write},
    iter::repeat,
    collections::HashSet,
    sync::{RwLock, atomic::{AtomicBool, Ordering}},
};

use once_cell::sync::Lazy;
use itertools::Itertools;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::{set_filter, Filter};
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// ```
pub fn set_filter(f: Filter) {
    PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
    let set: HashSet<_> = f.allowed.iter().cloned().collect();
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData {
        depth: f.depth,
        allowed: set,
        longer_than: f.longer_than,
        version: old.version + 1,
    };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// #Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(desc: &str) -> Profiler {
    assert!(!desc.is_empty());
    if !PROFILING_ENABLED.load(Ordering::Relaxed) {
        return Profiler { desc: None };
    }

    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > stack.filter_data.version {
                    stack.filter_data = f.clone();
                }
            };
        }
        if stack.starts.len() > stack.filter_data.depth {
            return Profiler { desc: None };
        }
        let allowed = &stack.filter_data.allowed;
        if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(desc) {
            return Profiler { desc: None };
        }

        stack.starts.push(Instant::now());
        Profiler { desc: Some(desc.to_string()) }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
    longer_than: Duration,
}

impl Filter {
    // Filtering syntax
    // env RA_PROFILE=*             // dump everything
    // env RA_PROFILE=foo|bar|baz   // enabled only selected entries
    // env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
    pub fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { Vec::new() } else { spec.split('|').map(String::from).collect() };
        Filter::new(depth, allowed, longer_than)
    }

    pub fn disabled() -> Filter {
        Filter::new(0, Vec::new(), Duration::new(0, 0))
    }

    pub fn new(depth: usize, allowed: Vec<String>, longer_than: Duration) -> Filter {
        Filter { depth, allowed, longer_than }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);

static FILTER: Lazy<RwLock<FilterData>> = Lazy::new(Default::default);

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        let longer_than = stack.filter_data.longer_than;
                        if duration >= longer_than {
                            print(0, &stack.messages, &mut stdout.lock(), longer_than);
                        }
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(lvl: usize, msgs: &[Message], out: &mut impl Write, longer_than: Duration) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl + 1).collect::<String>();
    // We output hierarchy for long calls, but sum up all short calls
    let mut short = Vec::new();
    for (i, &Message { level, duration, message: ref msg }) in msgs.iter().enumerate() {
        if level != lvl {
            continue;
        }
        if duration >= longer_than {
            writeln!(out, "{} {:6}ms - {}", indent, duration.as_millis(), msg)
                .expect("printing profiling info to stdout");

            print(lvl + 1, &msgs[last..i], out, longer_than);
        } else {
            short.push((msg, duration))
        }

        last = i;
    }
    short.sort_by_key(|(msg, _time)| *msg);
    for (msg, entires) in short.iter().group_by(|(msg, _time)| msg).into_iter() {
        let mut count = 0;
        let mut total_duration = Duration::default();
        entires.for_each(|(_msg, time)| {
            count += 1;
            total_duration += *time;
        });
        writeln!(out, "{} {:6}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
            .expect("printing profiling info to stdout");
    }
}

/// Prints backtrace to stderr, useful for debugging.
pub fn print_backtrace() {
    let bt = backtrace::Backtrace::new();
    eprintln!("{:?}", bt);
}

thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));

/// Allows to check if the current code is withing some dynamic scope, can be
/// useful during debugging to figure out why a function is called.
pub struct Scope {
    _hidden: (),
}

impl Scope {
    pub fn enter() -> Scope {
        IN_SCOPE.with(|slot| *slot.borrow_mut() = true);
        Scope { _hidden: () }
    }
    pub fn is_active() -> bool {
        IN_SCOPE.with(|slot| *slot.borrow())
    }
}

impl Drop for Scope {
    fn drop(&mut self) {
        IN_SCOPE.with(|slot| *slot.borrow_mut() = false);
    }
}

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

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s, Duration::new(0, 0));
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }
}
<commit_msg>fix debug scopes<commit_after>use std::{
    cell::RefCell,
    time::{Duration, Instant},
    mem,
    io::{stderr, Write},
    iter::repeat,
    collections::HashSet,
    sync::{RwLock, atomic::{AtomicBool, Ordering}},
};

use once_cell::sync::Lazy;
use itertools::Itertools;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::{set_filter, Filter};
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// ```
pub fn set_filter(f: Filter) {
    PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
    let set: HashSet<_> = f.allowed.iter().cloned().collect();
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData {
        depth: f.depth,
        allowed: set,
        longer_than: f.longer_than,
        version: old.version + 1,
    };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// #Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(desc: &str) -> Profiler {
    assert!(!desc.is_empty());
    if !PROFILING_ENABLED.load(Ordering::Relaxed) {
        return Profiler { desc: None };
    }

    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > stack.filter_data.version {
                    stack.filter_data = f.clone();
                }
            };
        }
        if stack.starts.len() > stack.filter_data.depth {
            return Profiler { desc: None };
        }
        let allowed = &stack.filter_data.allowed;
        if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(desc) {
            return Profiler { desc: None };
        }

        stack.starts.push(Instant::now());
        Profiler { desc: Some(desc.to_string()) }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
    longer_than: Duration,
}

impl Filter {
    // Filtering syntax
    // env RA_PROFILE=*             // dump everything
    // env RA_PROFILE=foo|bar|baz   // enabled only selected entries
    // env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
    pub fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { Vec::new() } else { spec.split('|').map(String::from).collect() };
        Filter::new(depth, allowed, longer_than)
    }

    pub fn disabled() -> Filter {
        Filter::new(0, Vec::new(), Duration::new(0, 0))
    }

    pub fn new(depth: usize, allowed: Vec<String>, longer_than: Duration) -> Filter {
        Filter { depth, allowed, longer_than }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);

static FILTER: Lazy<RwLock<FilterData>> = Lazy::new(Default::default);

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        let longer_than = stack.filter_data.longer_than;
                        if duration >= longer_than {
                            print(0, &stack.messages, &mut stdout.lock(), longer_than);
                        }
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(lvl: usize, msgs: &[Message], out: &mut impl Write, longer_than: Duration) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl + 1).collect::<String>();
    // We output hierarchy for long calls, but sum up all short calls
    let mut short = Vec::new();
    for (i, &Message { level, duration, message: ref msg }) in msgs.iter().enumerate() {
        if level != lvl {
            continue;
        }
        if duration >= longer_than {
            writeln!(out, "{} {:6}ms - {}", indent, duration.as_millis(), msg)
                .expect("printing profiling info to stdout");

            print(lvl + 1, &msgs[last..i], out, longer_than);
        } else {
            short.push((msg, duration))
        }

        last = i;
    }
    short.sort_by_key(|(msg, _time)| *msg);
    for (msg, entires) in short.iter().group_by(|(msg, _time)| msg).into_iter() {
        let mut count = 0;
        let mut total_duration = Duration::default();
        entires.for_each(|(_msg, time)| {
            count += 1;
            total_duration += *time;
        });
        writeln!(out, "{} {:6}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
            .expect("printing profiling info to stdout");
    }
}

/// Prints backtrace to stderr, useful for debugging.
pub fn print_backtrace() {
    let bt = backtrace::Backtrace::new();
    eprintln!("{:?}", bt);
}

thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));

/// Allows to check if the current code is withing some dynamic scope, can be
/// useful during debugging to figure out why a function is called.
pub struct Scope {
    prev: bool,
}

impl Scope {
    pub fn enter() -> Scope {
        let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
        Scope { prev }
    }
    pub fn is_active() -> bool {
        IN_SCOPE.with(|slot| *slot.borrow())
    }
}

impl Drop for Scope {
    fn drop(&mut self) {
        IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev);
    }
}

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

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s, Duration::new(0, 0));
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }
}
<|endoftext|>


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

use base::{error, Event};

use crate::{BusAccessInfo, BusDevice};

/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
pub struct I8042Device {
    reset_evt: Event,
}

impl I8042Device {
    /// Constructs a i8042 device that will signal the given event when the guest requests it.
    pub fn new(reset_evt: Event) -> I8042Device {
        I8042Device { reset_evt }
    }
}

// i8042 device is mapped I/O address 0x61. We partially implement two 8-bit
// registers: port 0x61 (I8042_PORT_B_REG), and port 0x64 (I8042_COMMAND_REG).
impl BusDevice for I8042Device {
    fn debug_label(&self) -> String {
        "i8042".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        if data.len() == 1 && info.offset == 0x64 {
            data[0] = 0x0;
        } else if data.len() == 1 && info.offset == 0x61 {
            // Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
            // avoid hang in pit_calibrate_tsc() in Linux kernel.
            data[0] = 0x20;
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        if data.len() == 1 && data[0] == 0xfe && info.offset == 0x64 {
            if let Err(e) = self.reset_evt.write(1) {
                error!("failed to trigger i8042 reset event: {}", e);
            }
        }
    }
}
<commit_msg>i8042: use address instead of offset for read and write<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::{error, Event};

use crate::{BusAccessInfo, BusDevice};

/// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
pub struct I8042Device {
    reset_evt: Event,
}

impl I8042Device {
    /// Constructs a i8042 device that will signal the given event when the guest requests it.
    pub fn new(reset_evt: Event) -> I8042Device {
        I8042Device { reset_evt }
    }
}

// i8042 device is mapped I/O address 0x61. We partially implement two 8-bit
// registers: port 0x61 (I8042_PORT_B_REG), and port 0x64 (I8042_COMMAND_REG).
impl BusDevice for I8042Device {
    fn debug_label(&self) -> String {
        "i8042".to_owned()
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        if data.len() == 1 && info.address == 0x64 {
            data[0] = 0x0;
        } else if data.len() == 1 && info.address == 0x61 {
            // Like kvmtool, we return bit 5 set in I8042_PORT_B_REG to
            // avoid hang in pit_calibrate_tsc() in Linux kernel.
            data[0] = 0x20;
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        if data.len() == 1 && data[0] == 0xfe && info.address == 0x64 {
            if let Err(e) = self.reset_evt.write(1) {
                error!("failed to trigger i8042 reset event: {}", e);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Write};
use std::iter;

use partial_io::{PartialOp, PartialWrite};

use stream::decode_all;
use stream::write::{Decoder, Encoder};

#[test]
fn test_cycle() {
    let input = b"Abcdefghabcdefgh";

    let buffer = Cursor::new(Vec::new());
    let mut encoder = Encoder::new(buffer, 1).unwrap();
    encoder.write_all(input).unwrap();
    let encoded = encoder.finish().unwrap().into_inner();

    // println!("Encoded: {:?}", encoded);

    let buffer = Cursor::new(Vec::new());
    let mut decoder = Decoder::new(buffer).unwrap();
    decoder.write_all(&encoded).unwrap();
    decoder.flush().unwrap();
    let decoded = decoder.into_inner().into_inner();

    assert_eq!(input, &decoded[..]);
}

/// Test that flush after a partial write works successfully without
/// corrupting the frame. This test is in this module because it checks
/// internal implementation details.
#[test]
fn test_partial_write_flush() {
    use std::io::Write;

    let input = vec![b'b'; 128 * 1024];
    let mut z = setup_partial_write(&input);

    // flush shouldn't corrupt the stream
    z.flush().unwrap();

    let buf = z.finish().unwrap().into_inner();
    assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
}

/// Test that finish after a partial write works successfully without
/// corrupting the frame. This test is in this module because it checks
/// internal implementation details.
#[test]
fn test_partial_write_finish() {
    let input = vec![b'b'; 128 * 1024];
    let z = setup_partial_write(&input);

    // finish shouldn't corrupt the stream
    let buf = z.finish().unwrap().into_inner();
    assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
}

fn setup_partial_write(input_data: &[u8]) -> Encoder<PartialWrite<Vec<u8>>> {
    use std::io::Write;

    let buf =
        PartialWrite::new(Vec::new(), iter::repeat(PartialOp::Limited(1)));
    let mut z = Encoder::new(buf, 1).unwrap();

    // Fill in enough data to make sure the buffer gets written out.
    z.write(input_data).unwrap();

    {
        let inner = &mut z.writer;
        // At this point, the internal buffer in z should have some data.
        assert_ne!(inner.offset(), inner.buffer().len());
    }

    z
}
<commit_msg>Remove unused imports<commit_after>use std::io::{Cursor, Write};
use std::iter;

use partial_io::{PartialOp, PartialWrite};

use stream::decode_all;
use stream::write::{Decoder, Encoder};

#[test]
fn test_cycle() {
    let input = b"Abcdefghabcdefgh";

    let buffer = Cursor::new(Vec::new());
    let mut encoder = Encoder::new(buffer, 1).unwrap();
    encoder.write_all(input).unwrap();
    let encoded = encoder.finish().unwrap().into_inner();

    // println!("Encoded: {:?}", encoded);

    let buffer = Cursor::new(Vec::new());
    let mut decoder = Decoder::new(buffer).unwrap();
    decoder.write_all(&encoded).unwrap();
    decoder.flush().unwrap();
    let decoded = decoder.into_inner().into_inner();

    assert_eq!(input, &decoded[..]);
}

/// Test that flush after a partial write works successfully without
/// corrupting the frame. This test is in this module because it checks
/// internal implementation details.
#[test]
fn test_partial_write_flush() {
    let input = vec![b'b'; 128 * 1024];
    let mut z = setup_partial_write(&input);

    // flush shouldn't corrupt the stream
    z.flush().unwrap();

    let buf = z.finish().unwrap().into_inner();
    assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
}

/// Test that finish after a partial write works successfully without
/// corrupting the frame. This test is in this module because it checks
/// internal implementation details.
#[test]
fn test_partial_write_finish() {
    let input = vec![b'b'; 128 * 1024];
    let z = setup_partial_write(&input);

    // finish shouldn't corrupt the stream
    let buf = z.finish().unwrap().into_inner();
    assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
}

fn setup_partial_write(input_data: &[u8]) -> Encoder<PartialWrite<Vec<u8>>> {
    let buf =
        PartialWrite::new(Vec::new(), iter::repeat(PartialOp::Limited(1)));
    let mut z = Encoder::new(buf, 1).unwrap();

    // Fill in enough data to make sure the buffer gets written out.
    z.write(input_data).unwrap();

    {
        let inner = &mut z.writer;
        // At this point, the internal buffer in z should have some data.
        assert_ne!(inner.offset(), inner.buffer().len());
    }

    z
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

const LIBMODBUS_DIR: &'static str = "libmodbus";

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    let build_dir = Path::new(LIBMODBUS_DIR);
    let prefix    = Path::new(&out_dir).join("libmodbus-root");
    let include   = Path::new(&prefix).join("include")
                                      .join("modbus");

    // if `pkg-config` is present and the libmodbus headers are found
    // we use `pkg-config` to find the include_path and call bindgen with it.
    //
    if let Ok(library) = pkg_config::find_library("libmodbus") {
        if let Some(include) = library.include_paths.get(0) {
            run_bindgen(&include);
        }

        return
    }

    // pkg-config is not found. We build libmodbus from source (source are in a git submodule)
    // and run bindgen with that folder as include path set.
    //

    // If autogen.sh is not present, initalize git submodules
    if !Path::new("libmodbus/autogen.sh").exists() {
        run_command("", Command::new("git").args(&["submodule", "update", "--init"]));
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    // Generate configure, run configure, make, make install
    run_command("Generating configure",
        Command::new("autoreconf")
            .arg("--install")
            .arg("--symlink")
            .arg("--force")
            .current_dir(&build_dir));

    run_command("Configuring libmodbus",
        Command::new("./configure")
            .arg("--prefix")
            .arg(prefix)
            .current_dir(&build_dir));

    run_command("Building libmodbus",
        Command::new("make")
            .arg("install")
            .current_dir(&build_dir));

    println!("cargo:rustc-link-lib=modbus");
    println!("cargo:rustc-link-search=native={}/libmodbus-root/lib", out_dir);

    run_bindgen(&include);
}

fn run_bindgen(include: &PathBuf) {
    let include_path = format!("-I{}", include.display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // Do not generate unstable Rust code that
        // requires a nightly rustc and enabling
        // unstable features.
        .no_unstable_rust()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        .clang_arg(include_path)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

// Helper which run a given command, and check it's success
fn run_command(which: &'static str, cmd: &mut Command) {
    assert!(cmd.status().expect(which).success(), which);
}
<commit_msg>Add --target and --host configure parameters<commit_after>extern crate bindgen;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e{
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

const LIBMODBUS_DIR: &'static str = "libmodbus";

fn main() {
    let dst = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();

    let build_dir = Path::new(LIBMODBUS_DIR);
    let prefix    = Path::new(&dst).join("libmodbus-root");
    let include   = Path::new(&prefix).join("include")
                                      .join("modbus");

    // if `pkg-config` is present and the libmodbus headers are found
    // we use `pkg-config` to find the include_path and call bindgen with it.
    //
    if let Ok(library) = pkg_config::find_library("libmodbus") {
        if let Some(include) = library.include_paths.get(0) {
            run_bindgen(&include);
        }

        return
    }

    // pkg-config is not found. We build libmodbus from source (source are in a git submodule)
    // and run bindgen with that folder as include path set.
    //

    // If autogen.sh is not present, initalize git submodules
    if !Path::new("libmodbus/autogen.sh").exists() {
        run_command("", Command::new("git").args(&["submodule", "update", "--init"]));
    }

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    // Generate configure, run configure, make, make install
    run_command("Generating configure",
        Command::new("autoreconf")
            .arg("--install")
            .arg("--symlink")
            .arg("--force")
            .current_dir(&build_dir));

    run_command("Configuring libmodbus",
        Command::new("./configure")
            .arg("--prefix")
            .arg(prefix)
            .arg(format!("--target={}", target))
            .arg(format!("--host={}", host))
            .current_dir(&build_dir));

    run_command("Building libmodbus",
        Command::new("make")
            .arg("install")
            .current_dir(&build_dir));

    println!("cargo:rustc-link-lib=modbus");
    println!("cargo:rustc-link-search=native={}/libmodbus-root/lib", dst);

    run_bindgen(&include);
}

fn run_bindgen(include: &PathBuf) {
    let include_path = format!("-I{}", include.display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // Do not generate unstable Rust code that
        // requires a nightly rustc and enabling
        // unstable features.
        .no_unstable_rust()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        .clang_arg(include_path)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

// Helper which run a given command, and check it's success
fn run_command(which: &'static str, cmd: &mut Command) {
    assert!(cmd.status().expect(which).success(), which);
}
<|endoftext|>


<commit_before>use slack::{Event, RtmClient, EventHandler, Message};
use router::{Router,Rule};

pub struct TelescreenHandler {
    router: Router,
}

impl TelescreenHandler {
    pub fn new(router: Router) -> TelescreenHandler {
        TelescreenHandler { router: router }
    }

    pub fn send_message(&self, cli: &RtmClient, source_channel_id: &str, source_user_id: &str, source_text: &str) {
        let channel_name = self.get_channel_name_from_id(cli, source_channel_id);
        let unwrapped_channel_name = match channel_name {
            None => { warn!("No channel: {:?}", source_channel_id); return },
            Some(c) => c,
        };

        let user_name = self.get_user_name_from_id(cli, source_user_id);
        let unwrapped_user_name = match user_name {
            None => { warn!("No user: {:?}", user_name); return },
            Some(t) => t,
        };

        let rules: &Vec<Rule> = self.router.rules.as_ref();
        for rule in rules {
            if rule.regex.is_match(unwrapped_channel_name) {
                let dest_channel_id = cli.start_response().channels.as_ref()
                    .and_then(|channels| {
                        channels.iter().find(|chan| match chan.name {
                            None => false,
                            Some(ref name) => name == &(rule.destination),
                        })
                    })
                    .and_then(|chan| chan.id.as_ref());

                let dest_channel_id_unwrap = match dest_channel_id {
                    None => { warn!("No channel: {:?}", dest_channel_id); return },
                    Some(c) => c,
                };

                if unwrapped_channel_name != &(rule.destination) {
                    let message = format!("@{:} [ <#{}> ]:\n{:}", unwrapped_user_name, source_channel_id, source_text);
                    info!("MESSAGE: {:?}", message);
                    let _ = cli.sender().send_message(&dest_channel_id_unwrap, &message);
                }
            }
        }
    }

    fn get_channel_name_from_id<'a>(&self, cli: &'a RtmClient, channel_id: &str) -> Option<&'a String> {
        cli.start_response().channels.as_ref()
            .and_then(|channels| {
                channels.iter().find(|chan| match chan.id {
                    None => false,
                    Some(ref id) => { id == channel_id },
                })
            })
            .and_then(|chan| chan.name.as_ref())
    }

    fn get_user_name_from_id<'a>(&self, cli: &'a RtmClient, user_id: &str) -> Option<&'a String> {
        cli.start_response().users.as_ref()
            .and_then(|users| {
                users.iter().find(|user| match user.id {
                    None => false,
                    Some(ref name) => { name.to_string() == user_id },
                })
            })
            .and_then(|user| user.name.as_ref())
    }
}

#[allow(unused_variables)]
impl EventHandler for TelescreenHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        debug!("EVENT: {:?}", event);

        match event {
            Event::Message(event) => {
                match *event {
                    Message::Standard(message) => {
                        let source_channel_id = match message.channel {
                            None => { warn!("No channel: {:?}", message.channel); return },
                            Some(c) => c,
                        };
                        let source_user_id = match message.user {
                            None => { warn!("No user: {:?}", message.user); return },
                            Some(u) => u,
                        };
                        let source_text = match message.text {
                            None => { warn!("No text: {:?}", message.text); return },
                            Some(t) => t,
                        };

                        self.send_message(cli, &source_channel_id, &source_user_id, &source_text);
                    },
                    _ => { /* noop */ },
                }
            },
            _ => { /* noop */ },
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        info!("Disconnected");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        info!("Connected");
    }
}
<commit_msg>Do not mention in telescreen's post<commit_after>use slack::{Event,RtmClient,EventHandler,Message};
use router::{Router,Rule};
use regex::{Regex,Captures};

pub struct TelescreenHandler {
    router: Router,
    username_regex: Regex,
}

impl TelescreenHandler {
    pub fn new(router: Router) -> TelescreenHandler {
        TelescreenHandler { router: router, username_regex: Regex::new(r"<@(.+)>").unwrap() }
    }

    pub fn send_message(&self, cli: &RtmClient, source_channel_id: &str, source_user_id: &str, source_text: &str) {
        let channel_name = self.get_channel_name_from_id(cli, source_channel_id);
        let unwrapped_channel_name = match channel_name {
            None => { warn!("No channel: {:?}", source_channel_id); return },
            Some(c) => c,
        };

        let user_name = self.get_user_name_from_id(cli, source_user_id);
        let unwrapped_user_name = match user_name {
            None => { warn!("No user: {:?}", user_name); return },
            Some(t) => t,
        };

        let rules: &Vec<Rule> = self.router.rules.as_ref();
        for rule in rules {
            if rule.regex.is_match(unwrapped_channel_name) {
                let dest_channel_id = cli.start_response().channels.as_ref()
                    .and_then(|channels| {
                        channels.iter().find(|chan| match chan.name {
                            None => false,
                            Some(ref name) => name == &(rule.destination),
                        })
                    })
                    .and_then(|chan| chan.id.as_ref());

                let dest_channel_id_unwrap = match dest_channel_id {
                    None => { warn!("No channel: {:?}", dest_channel_id); return },
                    Some(c) => c,
                };

                if unwrapped_channel_name != &(rule.destination) {
                    let replaced_source_text = self.username_regex.replace_all(source_text, |caps: &Captures| {
                        format!("@{}", self.get_user_name_from_id(cli, &caps[1]).unwrap_or(&String::from("unknown")))
                    });
                    let message = format!("@{:} [ <#{}> ]:\n{:}", unwrapped_user_name, source_channel_id, replaced_source_text);
                    info!("MESSAGE: {:?}", message);
                    let _ = cli.sender().send_message(&dest_channel_id_unwrap, &message);
                }
            }
        }
    }

    fn get_channel_name_from_id<'a>(&self, cli: &'a RtmClient, channel_id: &str) -> Option<&'a String> {
        cli.start_response().channels.as_ref()
            .and_then(|channels| {
                channels.iter().find(|chan| match chan.id {
                    None => false,
                    Some(ref id) => { id == channel_id },
                })
            })
            .and_then(|chan| chan.name.as_ref())
    }

    fn get_user_name_from_id<'a>(&self, cli: &'a RtmClient, user_id: &str) -> Option<&'a String> {
        cli.start_response().users.as_ref()
            .and_then(|users| {
                users.iter().find(|user| match user.id {
                    None => false,
                    Some(ref name) => { name.to_string() == user_id },
                })
            })
            .and_then(|user| user.name.as_ref())
    }
}

#[allow(unused_variables)]
impl EventHandler for TelescreenHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        debug!("EVENT: {:?}", event);

        match event {
            Event::Message(event) => {
                match *event {
                    Message::Standard(message) => {
                        let source_channel_id = match message.channel {
                            None => { warn!("No channel: {:?}", message.channel); return },
                            Some(c) => c,
                        };
                        let source_user_id = match message.user {
                            None => { warn!("No user: {:?}", message.user); return },
                            Some(u) => u,
                        };
                        let source_text = match message.text {
                            None => { warn!("No text: {:?}", message.text); return },
                            Some(t) => t,
                        };

                        self.send_message(cli, &source_channel_id, &source_user_id, &source_text);
                    },
                    _ => { /* noop */ },
                }
            },
            _ => { /* noop */ },
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        info!("Disconnected");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        info!("Connected");
    }
}
<|endoftext|>


<commit_before>
use syn::parse::{Parse, ParseStream, Result};

/// An empty type that cannot be parsed.
///
/// Used especially with attributes that don't take positional arguments.
#[derive(Debug)]
pub enum NoParams {}
impl Parse for NoParams {
    fn parse( input: ParseStream ) -> Result<Self> {
        Err( input.error( "Attribute does not accept positional parameters" ) )
    }
}

/// Literal string or 'None' if there should be no value.
#[derive(Debug)]
pub enum StrOption {
    Str( ::syn::LitStr ),
    None
}

impl Parse for StrOption {
    fn parse( input: ParseStream ) -> Result<Self> {

        if input.peek( ::syn::LitStr ) {
            return Ok( StrOption::Str( input.parse()? ) );
        }

        let ident : ::syn::Ident = input.parse()?;
        if ident == "None" {
            return Ok( StrOption::None );
        }

        Err( input.error( "Expected string or `None`" ) )
    }
}

/// Defines intercom attribute parameter parsing.
///
/// ```
/// intercom_attribute!(
///     SomeAttr< SomeAttrParam, Ident > {
///         param1: Ident,
///         param2: LitStr,
///         param3: Expr,
///     }
/// );
/// ```
///
/// Will define structures to parse attribute params such as:
///
/// ```
/// #[some_attr( Ident1, Ident2, Ident3 )]
/// #[some_attr( param1 = SomeIdent, List, Idents )]
/// #[some_attr( param2 = "literal", param3 = expression() + 1 )]
/// ```
macro_rules! intercom_attribute {

    ( $attr:ident < $attr_param:ident, $params:ident > { $( $name:ident : $type:ident, )* } ) => {

        #[allow(non_camel_case_types)]
        #[derive(Debug)]
        enum $attr_param {
            $( $name ( $type ), )*
            args( $params ),
        }

        impl ::syn::parse::Parse for $attr_param {
            fn parse( input : ::syn::parse::ParseStream ) -> ::syn::parse::Result<Self> {

                if ! input.peek2( Token![=] ) {
                    return Ok( $attr_param::args( input.parse()? ) );
                }

                let ident : ::syn::Ident = input.parse()?;
                let _punct : Token![=] = input.parse()?;
                Ok( match ident.to_string().as_ref() {
                    $(
                        stringify!( $name ) => $attr_param::$name( input.parse()? ),
                    )*
                    other => return Err( input.error( format!( "Unexpected parameter: `{}`", other ) ) )
                } )
            }
        }

        struct $attr( Vec<$attr_param> );
        impl ::syn::parse::Parse for $attr {
            fn parse( input : ::syn::parse::ParseStream ) -> ::syn::parse::Result<Self> {

                // When parsing #[foo(bar)] attributes with syn, syn will include
                // the parenthess in the tts:
                // > ( bar )
                let params = match ::syn::group::parse_parens( &input ) {
                    Ok( parens ) => parens.content.call(
                        ::syn::punctuated::Punctuated::<$attr_param, ::syn::token::Comma>::parse_terminated )?,
                    Err( _ ) => input.call(
                        ::syn::punctuated::Punctuated::<$attr_param, ::syn::token::Comma>::parse_terminated )?,
                };

                Ok( $attr( params.into_iter().collect() ) )
            }
        }

        #[allow(dead_code)]
        impl $attr {
            $(
                pub fn $name( &self ) -> Result< Option< &$type >, String >
                {
                    let v = self.0.iter().filter_map( |p| match p {
                        $attr_param::$name( v ) => Some( v ),
                        _ => None
                    } ).take( 2 ).collect::<Vec<_>>();

                    match v.len() {
                        0 => Ok( None ),
                        1 => Ok( Some( &v[0] ) ),
                        _ => Err( format!(
                                "Multiple {} arguments", stringify!( $name ) ) )
                    }
                }
            )*

            pub fn args<'a>( &'a self ) -> Vec<&'a $params>
            {
                self.0.iter().filter_map( |p| match p {
                    $attr_param::args( v ) => Some( v ),
                    _ => None
                } ).collect()
            }
        }
    }
}

<commit_msg>Document/improve intercom_attribute macro<commit_after>
use syn::parse::{Parse, ParseStream, Result};

/// An empty type that cannot be parsed.
///
/// Used especially with attributes that don't take positional arguments.
#[derive(Debug)]
pub enum NoParams {}
impl Parse for NoParams {
    fn parse( input: ParseStream ) -> Result<Self> {
        Err( input.error( "Attribute does not accept positional parameters" ) )
    }
}

/// Literal string or 'None' if there should be no value.
#[derive(Debug)]
pub enum StrOption {
    Str( ::syn::LitStr ),
    None
}

impl Parse for StrOption {
    fn parse( input: ParseStream ) -> Result<Self> {

        if input.peek( ::syn::LitStr ) {
            return Ok( StrOption::Str( input.parse()? ) );
        }

        let ident : ::syn::Ident = input.parse()?;
        if ident == "None" {
            return Ok( StrOption::None );
        }

        Err( input.error( "Expected string or `None`" ) )
    }
}

/// Defines intercom attribute parameter parsing.
///
/// ```
/// intercom_attribute!(
///     SomeAttr< SomeAttrParam, Ident > {
///         param1: Ident,
///         param2: LitStr,
///         param3: Expr,
///     }
/// );
/// ```
///
/// Will define structures to parse attribute params such as:
///
/// ```
/// #[some_attr( Ident1, Ident2, Ident3 )]
/// #[some_attr( param1 = SomeIdent, List, Idents )]
/// #[some_attr( param2 = "literal", param3 = expression() + 1 )]
/// ```
///
/// If the attribute should accept no positional arguments, use the `NoParams` type as the
/// positional parameter type.
macro_rules! intercom_attribute {

    // Match the top level invocation
    //
    // # Params
    //
    // * `$attr` - Attribute name.
    // * `$attr_param` - Name for the attribute parameter enum generated by the macro.
    // * `$params` - Type for the positional arguments
    // * `( $name, $type )*` - Name/type pairs for the optional named arguments.
    ( $attr:ident < $attr_param:ident, $params:ident > { $( $name:ident : $type:ident, )* } ) => {

        // Recurse into the attribute with stringified name parameters.
        //
        // These are needed for the #[doc..] attributes.
        intercom_attribute!( INTERNAL
                $attr,
                stringify!( $attr ),
                $attr_param,
                $params,
                $( $name : $type : stringify!( $name), )* );
    };

    // Attribute invocation with the stringified attributes.
    ( INTERNAL
            $attr:ident,
            $sattr:expr,
            $attr_param:ident,
            $params:ident,
            $( $name:ident : $type:ident : $sname:expr, )* ) => {

        // Define the enum that can represent the parameters.
        #[doc = "`" ]
        #[doc = $sattr ]
        #[doc = "` attribute parameter type." ]
        #[allow(non_camel_case_types)]
        #[derive(Debug)]
        enum $attr_param {
            $( $name ( $type ), )*
            args( $params ),
        }

        // Define the implementation for the syn parse function for the parameters.
        impl ::syn::parse::Parse for $attr_param {
            fn parse( input : ::syn::parse::ParseStream ) -> ::syn::parse::Result<Self> {

                // Check for the presence of equals sign (`=`) to figure out whether this is an
                // optional named parameter or a positional parameter.
                if ! input.peek2( Token![=] ) {

                    // Variable parameter. Emit it as such from the parse result.
                    return Ok( $attr_param::args( input.parse()? ) );
                }

                // Fetch the parameter ident and skip the punctuation (`=` as required above).
                let ident : ::syn::Ident = input.parse()?;
                let _punct : Token![=] = input.parse()?;

                // Match the ident to the name and parse the correct enum alternative from the
                // value.
                Ok( match ident.to_string().as_ref() {
                    $(
                        stringify!( $name ) => $attr_param::$name( input.parse()? ),
                    )*

                    // Ident wasn't a known string.
                    other => return Err( input.error( format!( "Unexpected parameter: `{}`", other ) ) )
                } )
            }
        }

        // Define the attribute data mdoel.
        //
        // The attribute is represented by a vector of arguments.
        #[doc = "`"]
        #[doc = $sattr ]
        #[doc = "` attribute data model"]
        struct $attr( Vec<$attr_param> );

        // Define the parse implementation for the full attribute.
        impl ::syn::parse::Parse for $attr {
            fn parse( input : ::syn::parse::ParseStream ) -> ::syn::parse::Result<Self> {

                // When parsing #[foo(bar)] attributes with syn, syn will include
                // the parenthess in the tts:
                // > ( bar )
                //
                // However these parentheses are not present when the parameters
                // are presented to us by rustc proc macros.
                //
                // As a result we'll need to support both.
                let params = match ::syn::group::parse_parens( &input ) {

                    // If the parens existed, call the parse for the paren content.
                    Ok( parens ) => parens.content.call(
                        ::syn::punctuated::Punctuated::<$attr_param, ::syn::token::Comma>::parse_terminated )?,

                    // If the parens were not present, call the parse for the whole input.
                    Err( _ ) => input.call(
                        ::syn::punctuated::Punctuated::<$attr_param, ::syn::token::Comma>::parse_terminated )?,
                };

                // Return the attribute.
                Ok( $attr( params.into_iter().collect() ) )
            }
        }

        #[allow(dead_code)]
        impl $attr {

            // Define getters for the various named arguments.
            $(
                #[doc = "Getter for the `"]
                #[doc = $sname ]
                #[doc = "` optional argument.\n\n"]
                #[doc = "Returns a failure if the parameter was defined multiple times. "]
                #[doc = "Otherwise results in an `Option` depending on whether the parameter"]
                #[doc = "was defined or not."]
                pub fn $name( &self ) -> Result< Option< &$type >, String >
                {
                    // Find the required parameters from the vector.
                    //
                    // We'll limit the filter into two items at max because there's no need to find
                    // more. Once we find two we'll know there are more than one and we'll result
                    // in an error.
                    let v = self.0.iter().filter_map( |p| match p {
                        $attr_param::$name( v ) => Some( v ),
                        _ => None
                    } ).take( 2 ).collect::<Vec<_>>();

                    // Decide on the return value based on how many times the parameter was
                    // defined.
                    match v.len() {
                        0 => Ok( None ),
                        1 => Ok( Some( &v[0] ) ),
                        _ => Err( format!(
                                "Multiple {} arguments", stringify!( $name ) ) )
                    }
                }
            )*

            #[doc = "Gets the positional arguments"]
            pub fn args<'a>( &'a self ) -> Vec<&'a $params>
            {
                // Return the positional arguments.
                self.0.iter().filter_map( |p| match p {
                    $attr_param::args( v ) => Some( v ),
                    _ => None
                } ).collect()
            }
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    errors::*,
    expansion::ast as E,
    parser::ast::ModuleIdent,
    shared::{unique_map::UniqueMap, *},
};
use move_ir_types::location::*;
use petgraph::{algo::toposort as petgraph_toposort, graphmap::DiGraphMap};
use std::collections::BTreeMap;

//**************************************************************************************************
// Entry
//**************************************************************************************************

pub fn verify(errors: &mut Errors, modules: &mut UniqueMap<ModuleIdent, E::ModuleDefinition>) {
    let imm_modules = &modules;
    let mut context = Context::new(imm_modules);
    module_defs(&mut context, modules);

    let Context { neighbors, .. } = context;
    let graph = dependency_graph(&neighbors);
    match petgraph_toposort(&graph, None) {
        Err(cycle_node) => {
            let cycle_ident = cycle_node.node_id().clone();
            let error = cycle_error(&neighbors, cycle_ident);
            errors.push(error);
        }
        Ok(ordered_ids) => {
            let ordered_ids = ordered_ids.into_iter().cloned().collect::<Vec<_>>();
            for (order, mident) in ordered_ids.into_iter().rev().enumerate() {
                modules.get_mut(&mident).unwrap().dependency_order = order;
            }
        }
    }
}

#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
enum DepType {
    Use,
    Friend,
}

struct Context<'a> {
    modules: &'a UniqueMap<ModuleIdent, E::ModuleDefinition>,
    // A union of uses and friends:
    // - if A uses B,    add edge A -> B
    // - if A friends B, add edge B -> A
    neighbors: BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    current_module: Option<ModuleIdent>,
}

impl<'a> Context<'a> {
    fn new(modules: &'a UniqueMap<ModuleIdent, E::ModuleDefinition>) -> Self {
        Context {
            modules,
            neighbors: BTreeMap::new(),
            current_module: None,
        }
    }

    fn add_neighbor(&mut self, mident: ModuleIdent, dep_type: DepType, loc: Loc) {
        let current_mident = self.current_module.clone().unwrap();
        if current_mident == mident || !self.modules.contains_key(&mident) {
            return;
        }
        let (node, new_neighbor) = match dep_type {
            DepType::Use => (current_mident, mident),
            DepType::Friend => (mident, current_mident),
        };

        let m = self
            .neighbors
            .entry(node)
            .or_insert_with(BTreeMap::new)
            .entry(new_neighbor)
            .or_insert_with(BTreeMap::new);
        if m.contains_key(&dep_type) {
            return;
        }
        m.insert(dep_type, loc);
    }

    fn add_usage(&mut self, mident: ModuleIdent, loc: Loc) {
        self.add_neighbor(mident, DepType::Use, loc);
    }

    fn add_friend(&mut self, mident: ModuleIdent, loc: Loc) {
        self.add_neighbor(mident, DepType::Friend, loc);
    }
}

fn dependency_graph(
    deps: &BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
) -> DiGraphMap<&ModuleIdent, ()> {
    let edges = deps
        .iter()
        .flat_map(|(parent, children)| children.iter().map(move |(child, _)| (parent, child)));
    DiGraphMap::from_edges(edges)
}

fn cycle_error(
    deps: &BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    cycle_ident: ModuleIdent,
) -> Error {
    let graph = dependency_graph(deps);
    let cycle = shortest_cycle(&graph, &cycle_ident);

    let mut cycle_strings: String = cycle
        .windows(2)
        .map(|pair| {
            let node = pair[0];
            let neighbor = pair[1];
            let relations = deps.get(node).unwrap().get(neighbor).unwrap();
            let verb = if relations.contains_key(&DepType::Use) {
                "uses"
            } else {
                assert!(relations.contains_key(&DepType::Friend));
                "is a friend of"
            };
            format!("'{}' {} ", node, verb)
        })
        .collect();
    cycle_strings.push_str(&format!("'{}'", cycle.last().unwrap()));

    // For printing uses, sort the cycle by location (earliest first)
    let (dep_type, cycle_loc, node, neighbor) = best_cycle_loc(deps, cycle);

    let (use_msg, cycle_msg) = match dep_type {
        DepType::Use => (
            format!("Invalid use of module '{}' in module '{}'.", neighbor, node),
            format!(
                "Using this module creates a dependency cycle: {}",
                cycle_strings
            ),
        ),
        DepType::Friend => (
            format!("Invalid friend '{}' in module '{}'", node, neighbor),
            format!(
                "This friend relationship creates a dependency cycle: {}",
                cycle_strings
            ),
        ),
    };
    vec![(cycle_loc, use_msg), (cycle_loc, cycle_msg)]
}

fn best_cycle_loc<'a>(
    deps: &'a BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    cycle: Vec<&'a ModuleIdent>,
) -> (DepType, Loc, &'a ModuleIdent, &'a ModuleIdent) {
    let len = cycle.len();
    assert!(len >= 3);
    let first = cycle[0];
    let node = cycle[len - 2];
    let neighbor = cycle[len - 1];
    assert_eq!(first, neighbor);
    let cycle_locs = deps.get(node).unwrap().get(neighbor).unwrap();
    let (dep_type, loc) = cycle_locs.iter().next().unwrap();
    (*dep_type, *loc, node, neighbor)
}

//**************************************************************************************************
// Modules
//**************************************************************************************************

fn module_defs(context: &mut Context, modules: &UniqueMap<ModuleIdent, E::ModuleDefinition>) {
    modules
        .key_cloned_iter()
        .for_each(|(mident, mdef)| module(context, mident, mdef))
}

fn module(context: &mut Context, mident: ModuleIdent, mdef: &E::ModuleDefinition) {
    context.current_module = Some(mident);
    mdef.friends
        .key_cloned_iter()
        .for_each(|(mident, loc)| context.add_friend(mident, *loc));
    mdef.structs
        .iter()
        .for_each(|(_, _, sdef)| struct_def(context, sdef));
    mdef.functions
        .iter()
        .for_each(|(_, _, fdef)| function(context, fdef));
}

fn struct_def(context: &mut Context, sdef: &E::StructDefinition) {
    if let E::StructFields::Defined(fields) = &sdef.fields {
        fields.iter().for_each(|(_, _, (_, bt))| type_(context, bt));
    }
}

fn function(context: &mut Context, fdef: &E::Function) {
    function_signature(context, &fdef.signature);
    function_acquires(context, &fdef.acquires);
    if let E::FunctionBody_::Defined(seq) = &fdef.body.value {
        sequence(context, seq)
    }
}

fn function_signature(context: &mut Context, sig: &E::FunctionSignature) {
    types(context, sig.parameters.iter().map(|(_, st)| st));
    type_(context, &sig.return_type)
}

fn function_acquires(context: &mut Context, acqs: &[E::ModuleAccess]) {
    for acq in acqs {
        module_access(context, acq);
    }
}

//**************************************************************************************************
// Types
//**************************************************************************************************

fn module_access(context: &mut Context, sp!(loc, ma_): &E::ModuleAccess) {
    if let E::ModuleAccess_::ModuleAccess(m, _) = ma_ {
        context.add_usage(m.clone(), *loc)
    }
}

fn types<'a>(context: &mut Context, tys: impl IntoIterator<Item = &'a E::Type>) {
    tys.into_iter().for_each(|ty| type_(context, ty))
}

fn types_opt(context: &mut Context, tys_opt: &Option<Vec<E::Type>>) {
    tys_opt.iter().for_each(|tys| types(context, tys))
}

fn type_(context: &mut Context, sp!(_, ty_): &E::Type) {
    use E::Type_ as T;
    match ty_ {
        T::Apply(tn, tys) => {
            module_access(context, tn);
            types(context, tys);
        }
        T::Multiple(tys) => types(context, tys),
        T::Fun(tys, ret_ty) => {
            types(context, tys);
            type_(context, ret_ty)
        }
        T::Ref(_, t) => type_(context, t),
        T::Unit | T::UnresolvedError => (),
    }
}

fn type_opt(context: &mut Context, t_opt: &Option<E::Type>) {
    t_opt.iter().for_each(|t| type_(context, t))
}

//**************************************************************************************************
// Expressions
//**************************************************************************************************

fn sequence(context: &mut Context, sequence: &E::Sequence) {
    use E::SequenceItem_ as SI;
    for sp!(_, item_) in sequence {
        match item_ {
            SI::Seq(e) => exp(context, e),
            SI::Declare(bl, ty_opt) => {
                lvalues(context, &bl.value);
                type_opt(context, ty_opt);
            }
            SI::Bind(bl, e) => {
                lvalues(context, &bl.value);
                exp(context, e)
            }
        }
    }
}

fn lvalues<'a>(context: &mut Context, al: impl IntoIterator<Item = &'a E::LValue>) {
    al.into_iter().for_each(|a| lvalue(context, a))
}

fn lvalues_with_range(context: &mut Context, sp!(_, ll): &E::LValueWithRangeList) {
    ll.iter().for_each(|lrange| {
        let sp!(_, (l, e)) = lrange;
        lvalue(context, l);
        exp(context, e);
    })
}

fn lvalue(context: &mut Context, sp!(_loc, a_): &E::LValue) {
    use E::LValue_ as L;
    if let L::Unpack(m, bs_opt, f) = a_ {
        module_access(context, m);
        types_opt(context, bs_opt);
        lvalues(context, f.iter().map(|(_, _, (_, b))| b));
    }
}

fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) {
    use E::Exp_ as E;
    match e_ {
        E::Unit { .. }
        | E::UnresolvedError
        | E::Break
        | E::Continue
        | E::Spec(_, _)
        | E::InferredNum(_)
        | E::Value(_)
        | E::Move(_)
        | E::Copy(_) => (),

        E::Name(ma, tys_opt) => {
            module_access(context, ma);
            types_opt(context, tys_opt)
        }
        E::Call(ma, tys_opt, args) => {
            module_access(context, ma);
            types_opt(context, tys_opt);
            args.value.iter().for_each(|e| exp(context, e))
        }
        E::Pack(ma, tys_opt, fields) => {
            module_access(context, ma);
            types_opt(context, tys_opt);
            fields.iter().for_each(|(_, _, (_, e))| exp(context, e))
        }

        E::IfElse(ec, et, ef) => {
            exp(context, ec);
            exp(context, et);
            exp(context, ef)
        }

        E::BinopExp(e1, _, e2) | E::Mutate(e1, e2) | E::While(e1, e2) | E::Index(e1, e2) => {
            exp(context, e1);
            exp(context, e2)
        }
        E::Block(seq) => sequence(context, seq),
        E::Assign(al, e) => {
            lvalues(context, &al.value);
            exp(context, e)
        }
        E::FieldMutate(edotted, e) => {
            exp_dotted(context, edotted);
            exp(context, e);
        }

        E::Loop(e)
        | E::Return(e)
        | E::Abort(e)
        | E::Dereference(e)
        | E::UnaryExp(_, e)
        | E::Borrow(_, e) => exp(context, e),

        E::ExpList(es) => es.iter().for_each(|e| exp(context, e)),

        E::ExpDotted(edotted) => exp_dotted(context, edotted),

        E::Cast(e, ty) | E::Annotate(e, ty) => {
            exp(context, e);
            type_(context, ty)
        }

        E::Lambda(ll, e) => {
            lvalues(context, &ll.value);
            exp(context, e)
        }
        E::Quant(_, binds, es_vec, eopt, e) => {
            lvalues_with_range(context, binds);
            es_vec
                .iter()
                .for_each(|es| es.iter().for_each(|e| exp(context, e)));
            eopt.iter().for_each(|e| exp(context, e));
            exp(context, e)
        }
    }
}

fn exp_dotted(context: &mut Context, sp!(_, ed_): &E::ExpDotted) {
    use E::ExpDotted_ as D;
    match ed_ {
        D::Exp(e) => exp(context, e),
        D::Dot(edotted, _) => exp_dotted(context, edotted),
    }
}
<commit_msg>[move-lang] Added specs to dependency ordering calculation<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    errors::*,
    expansion::ast as E,
    parser::ast::ModuleIdent,
    shared::{unique_map::UniqueMap, *},
};
use move_ir_types::location::*;
use petgraph::{algo::toposort as petgraph_toposort, graphmap::DiGraphMap};
use std::collections::BTreeMap;

//**************************************************************************************************
// Entry
//**************************************************************************************************

pub fn verify(errors: &mut Errors, modules: &mut UniqueMap<ModuleIdent, E::ModuleDefinition>) {
    let imm_modules = &modules;
    let mut context = Context::new(imm_modules);
    module_defs(&mut context, modules);

    let Context { neighbors, .. } = context;
    let graph = dependency_graph(&neighbors);
    match petgraph_toposort(&graph, None) {
        Err(cycle_node) => {
            let cycle_ident = cycle_node.node_id().clone();
            let error = cycle_error(&neighbors, cycle_ident);
            errors.push(error);
        }
        Ok(ordered_ids) => {
            let ordered_ids = ordered_ids.into_iter().cloned().collect::<Vec<_>>();
            for (order, mident) in ordered_ids.into_iter().rev().enumerate() {
                modules.get_mut(&mident).unwrap().dependency_order = order;
            }
        }
    }
}

#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
enum DepType {
    Use,
    Friend,
}

struct Context<'a> {
    modules: &'a UniqueMap<ModuleIdent, E::ModuleDefinition>,
    // A union of uses and friends:
    // - if A uses B,    add edge A -> B
    // - if A friends B, add edge B -> A
    neighbors: BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    current_module: Option<ModuleIdent>,
}

impl<'a> Context<'a> {
    fn new(modules: &'a UniqueMap<ModuleIdent, E::ModuleDefinition>) -> Self {
        Context {
            modules,
            neighbors: BTreeMap::new(),
            current_module: None,
        }
    }

    fn add_neighbor(&mut self, mident: ModuleIdent, dep_type: DepType, loc: Loc) {
        let current_mident = self.current_module.clone().unwrap();
        if current_mident == mident || !self.modules.contains_key(&mident) {
            return;
        }
        let (node, new_neighbor) = match dep_type {
            DepType::Use => (current_mident, mident),
            DepType::Friend => (mident, current_mident),
        };

        let m = self
            .neighbors
            .entry(node)
            .or_insert_with(BTreeMap::new)
            .entry(new_neighbor)
            .or_insert_with(BTreeMap::new);
        if m.contains_key(&dep_type) {
            return;
        }
        m.insert(dep_type, loc);
    }

    fn add_usage(&mut self, mident: ModuleIdent, loc: Loc) {
        self.add_neighbor(mident, DepType::Use, loc);
    }

    fn add_friend(&mut self, mident: ModuleIdent, loc: Loc) {
        self.add_neighbor(mident, DepType::Friend, loc);
    }
}

fn dependency_graph(
    deps: &BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
) -> DiGraphMap<&ModuleIdent, ()> {
    let edges = deps
        .iter()
        .flat_map(|(parent, children)| children.iter().map(move |(child, _)| (parent, child)));
    DiGraphMap::from_edges(edges)
}

fn cycle_error(
    deps: &BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    cycle_ident: ModuleIdent,
) -> Error {
    let graph = dependency_graph(deps);
    let cycle = shortest_cycle(&graph, &cycle_ident);

    let mut cycle_strings: String = cycle
        .windows(2)
        .map(|pair| {
            let node = pair[0];
            let neighbor = pair[1];
            let relations = deps.get(node).unwrap().get(neighbor).unwrap();
            let verb = if relations.contains_key(&DepType::Use) {
                "uses"
            } else {
                assert!(relations.contains_key(&DepType::Friend));
                "is a friend of"
            };
            format!("'{}' {} ", node, verb)
        })
        .collect();
    cycle_strings.push_str(&format!("'{}'", cycle.last().unwrap()));

    // For printing uses, sort the cycle by location (earliest first)
    let (dep_type, cycle_loc, node, neighbor) = best_cycle_loc(deps, cycle);

    let (use_msg, cycle_msg) = match dep_type {
        DepType::Use => (
            format!("Invalid use of module '{}' in module '{}'.", neighbor, node),
            format!(
                "Using this module creates a dependency cycle: {}",
                cycle_strings
            ),
        ),
        DepType::Friend => (
            format!("Invalid friend '{}' in module '{}'", node, neighbor),
            format!(
                "This friend relationship creates a dependency cycle: {}",
                cycle_strings
            ),
        ),
    };
    vec![(cycle_loc, use_msg), (cycle_loc, cycle_msg)]
}

fn best_cycle_loc<'a>(
    deps: &'a BTreeMap<ModuleIdent, BTreeMap<ModuleIdent, BTreeMap<DepType, Loc>>>,
    cycle: Vec<&'a ModuleIdent>,
) -> (DepType, Loc, &'a ModuleIdent, &'a ModuleIdent) {
    let len = cycle.len();
    assert!(len >= 3);
    let first = cycle[0];
    let node = cycle[len - 2];
    let neighbor = cycle[len - 1];
    assert_eq!(first, neighbor);
    let cycle_locs = deps.get(node).unwrap().get(neighbor).unwrap();
    let (dep_type, loc) = cycle_locs.iter().next().unwrap();
    (*dep_type, *loc, node, neighbor)
}

//**************************************************************************************************
// Modules
//**************************************************************************************************

fn module_defs(context: &mut Context, modules: &UniqueMap<ModuleIdent, E::ModuleDefinition>) {
    modules
        .key_cloned_iter()
        .for_each(|(mident, mdef)| module(context, mident, mdef))
}

fn module(context: &mut Context, mident: ModuleIdent, mdef: &E::ModuleDefinition) {
    context.current_module = Some(mident);
    mdef.friends
        .key_cloned_iter()
        .for_each(|(mident, loc)| context.add_friend(mident, *loc));
    mdef.structs
        .iter()
        .for_each(|(_, _, sdef)| struct_def(context, sdef));
    mdef.functions
        .iter()
        .for_each(|(_, _, fdef)| function(context, fdef));
    mdef.specs
        .iter()
        .for_each(|sblock| spec_block(context, sblock));
}

fn struct_def(context: &mut Context, sdef: &E::StructDefinition) {
    if let E::StructFields::Defined(fields) = &sdef.fields {
        fields.iter().for_each(|(_, _, (_, bt))| type_(context, bt));
    }
}

fn function(context: &mut Context, fdef: &E::Function) {
    function_signature(context, &fdef.signature);
    function_acquires(context, &fdef.acquires);
    if let E::FunctionBody_::Defined(seq) = &fdef.body.value {
        sequence(context, seq)
    }
    fdef.specs
        .values()
        .for_each(|sblock| spec_block(context, sblock));
}

fn function_signature(context: &mut Context, sig: &E::FunctionSignature) {
    types(context, sig.parameters.iter().map(|(_, st)| st));
    type_(context, &sig.return_type)
}

fn function_acquires(context: &mut Context, acqs: &[E::ModuleAccess]) {
    for acq in acqs {
        module_access(context, acq);
    }
}

//**************************************************************************************************
// Types
//**************************************************************************************************

fn module_access(context: &mut Context, sp!(loc, ma_): &E::ModuleAccess) {
    if let E::ModuleAccess_::ModuleAccess(m, _) = ma_ {
        context.add_usage(m.clone(), *loc)
    }
}

fn types<'a>(context: &mut Context, tys: impl IntoIterator<Item = &'a E::Type>) {
    tys.into_iter().for_each(|ty| type_(context, ty))
}

fn types_opt(context: &mut Context, tys_opt: &Option<Vec<E::Type>>) {
    tys_opt.iter().for_each(|tys| types(context, tys))
}

fn type_(context: &mut Context, sp!(_, ty_): &E::Type) {
    use E::Type_ as T;
    match ty_ {
        T::Apply(tn, tys) => {
            module_access(context, tn);
            types(context, tys);
        }
        T::Multiple(tys) => types(context, tys),
        T::Fun(tys, ret_ty) => {
            types(context, tys);
            type_(context, ret_ty)
        }
        T::Ref(_, t) => type_(context, t),
        T::Unit | T::UnresolvedError => (),
    }
}

fn type_opt(context: &mut Context, t_opt: &Option<E::Type>) {
    t_opt.iter().for_each(|t| type_(context, t))
}

//**************************************************************************************************
// Expressions
//**************************************************************************************************

fn sequence(context: &mut Context, sequence: &E::Sequence) {
    use E::SequenceItem_ as SI;
    for sp!(_, item_) in sequence {
        match item_ {
            SI::Seq(e) => exp(context, e),
            SI::Declare(bl, ty_opt) => {
                lvalues(context, &bl.value);
                type_opt(context, ty_opt);
            }
            SI::Bind(bl, e) => {
                lvalues(context, &bl.value);
                exp(context, e)
            }
        }
    }
}

fn lvalues<'a>(context: &mut Context, al: impl IntoIterator<Item = &'a E::LValue>) {
    al.into_iter().for_each(|a| lvalue(context, a))
}

fn lvalues_with_range(context: &mut Context, sp!(_, ll): &E::LValueWithRangeList) {
    ll.iter().for_each(|lrange| {
        let sp!(_, (l, e)) = lrange;
        lvalue(context, l);
        exp(context, e);
    })
}

fn lvalue(context: &mut Context, sp!(_loc, a_): &E::LValue) {
    use E::LValue_ as L;
    if let L::Unpack(m, bs_opt, f) = a_ {
        module_access(context, m);
        types_opt(context, bs_opt);
        lvalues(context, f.iter().map(|(_, _, (_, b))| b));
    }
}

fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) {
    use E::Exp_ as E;
    match e_ {
        E::Unit { .. }
        | E::UnresolvedError
        | E::Break
        | E::Continue
        | E::Spec(_, _)
        | E::InferredNum(_)
        | E::Value(_)
        | E::Move(_)
        | E::Copy(_) => (),

        E::Name(ma, tys_opt) => {
            module_access(context, ma);
            types_opt(context, tys_opt)
        }
        E::Call(ma, tys_opt, args) => {
            module_access(context, ma);
            types_opt(context, tys_opt);
            args.value.iter().for_each(|e| exp(context, e))
        }
        E::Pack(ma, tys_opt, fields) => {
            module_access(context, ma);
            types_opt(context, tys_opt);
            fields.iter().for_each(|(_, _, (_, e))| exp(context, e))
        }

        E::IfElse(ec, et, ef) => {
            exp(context, ec);
            exp(context, et);
            exp(context, ef)
        }

        E::BinopExp(e1, _, e2) | E::Mutate(e1, e2) | E::While(e1, e2) | E::Index(e1, e2) => {
            exp(context, e1);
            exp(context, e2)
        }
        E::Block(seq) => sequence(context, seq),
        E::Assign(al, e) => {
            lvalues(context, &al.value);
            exp(context, e)
        }
        E::FieldMutate(edotted, e) => {
            exp_dotted(context, edotted);
            exp(context, e);
        }

        E::Loop(e)
        | E::Return(e)
        | E::Abort(e)
        | E::Dereference(e)
        | E::UnaryExp(_, e)
        | E::Borrow(_, e) => exp(context, e),

        E::ExpList(es) => es.iter().for_each(|e| exp(context, e)),

        E::ExpDotted(edotted) => exp_dotted(context, edotted),

        E::Cast(e, ty) | E::Annotate(e, ty) => {
            exp(context, e);
            type_(context, ty)
        }

        E::Lambda(ll, e) => {
            lvalues(context, &ll.value);
            exp(context, e)
        }
        E::Quant(_, binds, es_vec, eopt, e) => {
            lvalues_with_range(context, binds);
            es_vec
                .iter()
                .for_each(|es| es.iter().for_each(|e| exp(context, e)));
            eopt.iter().for_each(|e| exp(context, e));
            exp(context, e)
        }
    }
}

fn exp_dotted(context: &mut Context, sp!(_, ed_): &E::ExpDotted) {
    use E::ExpDotted_ as D;
    match ed_ {
        D::Exp(e) => exp(context, e),
        D::Dot(edotted, _) => exp_dotted(context, edotted),
    }
}

//**************************************************************************************************
// Specs
//**************************************************************************************************

fn spec_block(context: &mut Context, sp!(_, sb_): &E::SpecBlock) {
    sb_.members
        .iter()
        .for_each(|sbm| spec_block_member(context, sbm))
}

fn spec_block_member(context: &mut Context, sp!(_, sbm_): &E::SpecBlockMember) {
    use E::SpecBlockMember_ as M;
    match sbm_ {
        M::Condition {
            exp: e,
            additional_exps: es,
            ..
        } => {
            exp(context, e);
            es.iter().for_each(|e| exp(context, e))
        }
        M::Function { body, .. } => {
            if let E::FunctionBody_::Defined(seq) = &body.value {
                sequence(context, seq)
            }
        }
        M::Let { def: e, .. } | M::Include { exp: e, .. } | M::Apply { exp: e, .. } => {
            exp(context, e)
        }
        M::Variable { .. } | M::Pragma { .. } => {}
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Nicholas Juszczak <juszczakn@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) ugoa cmode

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, AppSettings, Arg, ArgMatches, OsValues};
use std::fs;
use std::path::Path;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
#[cfg(not(windows))]
use uucore::mode;
use uucore::InvalidEncodingHandling;

static DEFAULT_PERM: u32 = 0o755;

static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
mod options {
    pub const MODE: &str = "mode";
    pub const PARENTS: &str = "parents";
    pub const VERBOSE: &str = "verbose";
    pub const DIRS: &str = "dirs";
}

fn usage() -> String {
    format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
}
fn get_long_usage() -> String {
    String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
}

#[cfg(windows)]
fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> {
    Ok(DEFAULT_PERM)
}

#[cfg(not(windows))]
fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result<u32, String> {
    let digits: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    // Translate a ~str in octal form to u16, default to 755
    // Not tested on Windows
    let mut new_mode = DEFAULT_PERM;
    match matches.value_of(options::MODE) {
        Some(m) => {
            for mode in m.split(',') {
                if mode.contains(digits) {
                    new_mode = mode::parse_numeric(new_mode, m, true)?;
                } else {
                    let cmode = if mode_had_minus_prefix {
                        // clap parsing is finished, now put prefix back
                        format!("-{}", mode)
                    } else {
                        mode.to_string()
                    };
                    new_mode = mode::parse_symbolic(new_mode, &cmode, mode::get_umask(), true)?;
                }
            }
            Ok(new_mode)
        }
        None => Ok(DEFAULT_PERM),
    }
}

#[cfg(windows)]
fn strip_minus_from_mode(_args: &mut Vec<String>) -> bool {
    false
}

#[cfg(not(windows))]
fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    mode::strip_minus_from_mode(args)
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let mut args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    // Before we can parse 'args' with clap (and previously getopts),
    // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
    let mode_had_minus_prefix = strip_minus_from_mode(&mut args);

    let usage = usage();
    let after_help = get_long_usage();

    // Linux-specific options, not implemented
    // opts.optflag("Z", "context", "set SELinux security context" +
    // " of each created directory to CTX"),
    let matches = uu_app()
        .override_usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
    let verbose = matches.is_present(options::VERBOSE);
    let recursive = matches.is_present(options::PARENTS);

    match get_mode(&matches, mode_had_minus_prefix) {
        Ok(mode) => exec(dirs, recursive, mode, verbose),
        Err(f) => Err(USimpleError::new(1, f)),
    }
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .setting(AppSettings::InferLongArgs)
        .arg(
            Arg::new(options::MODE)
                .short('m')
                .long(options::MODE)
                .help("set file mode (not implemented on windows)")
                .default_value("755"),
        )
        .arg(
            Arg::new(options::PARENTS)
                .short('p')
                .long(options::PARENTS)
                .help("make parent directories as needed"),
        )
        .arg(
            Arg::new(options::VERBOSE)
                .short('v')
                .long(options::VERBOSE)
                .help("print a message for each printed directory"),
        )
        .arg(
            Arg::new(options::DIRS)
                .multiple_occurrences(true)
                .takes_value(true)
                .min_values(1)
                .allow_invalid_utf8(true),
        )
}

/**
 * Create the list of new directories
 */
fn exec(dirs: OsValues, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    for dir in dirs {
        let path = Path::new(dir);
        show_if_err!(mkdir(path, recursive, mode, verbose));
    }
    Ok(())
}

fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    let create_dir = if recursive {
        fs::create_dir_all
    } else {
        fs::create_dir
    };

    create_dir(path).map_err_context(|| format!("cannot create directory {}", path.quote()))?;

    if verbose {
        println!(
            "{}: created directory {}",
            uucore::util_name(),
            path.quote()
        );
    }

    chmod(path, mode)
}

#[cfg(any(unix, target_os = "redox"))]
fn chmod(path: &Path, mode: u32) -> UResult<()> {
    use std::fs::{set_permissions, Permissions};
    use std::os::unix::fs::PermissionsExt;

    let mode = Permissions::from_mode(mode);

    set_permissions(path, mode)
        .map_err_context(|| format!("cannot set permissions {}", path.quote()))
}

#[cfg(windows)]
fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
    Ok(())
}
<commit_msg>mkdir: permissions respects umask - hardcoded default permissions changed to ones defined by umask<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Nicholas Juszczak <juszczakn@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) ugoa cmode

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, AppSettings, Arg, ArgMatches, OsValues};
use std::fs;
use std::path::Path;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError};
#[cfg(not(windows))]
use uucore::mode;
use uucore::InvalidEncodingHandling;

static DEFAULT_PERM: u32 = 0o755;

static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
mod options {
    pub const MODE: &str = "mode";
    pub const PARENTS: &str = "parents";
    pub const VERBOSE: &str = "verbose";
    pub const DIRS: &str = "dirs";
}

fn usage() -> String {
    format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
}
fn get_long_usage() -> String {
    String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
}

#[cfg(windows)]
fn get_mode(_matches: &ArgMatches, _mode_had_minus_prefix: bool) -> Result<u32, String> {
    Ok(DEFAULT_PERM)
}

#[cfg(not(windows))]
fn get_mode(matches: &ArgMatches, mode_had_minus_prefix: bool) -> Result<u32, String> {
    let digits: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    // Translate a ~str in octal form to u16, default to 755
    // Not tested on Windows
    let mut new_mode = DEFAULT_PERM;
    match matches.value_of(options::MODE) {
        Some(m) => {
            for mode in m.split(',') {
                if mode.contains(digits) {
                    new_mode = mode::parse_numeric(new_mode, m, true)?;
                } else {
                    let cmode = if mode_had_minus_prefix {
                        // clap parsing is finished, now put prefix back
                        format!("-{}", mode)
                    } else {
                        mode.to_string()
                    };
                    new_mode = mode::parse_symbolic(new_mode, &cmode, mode::get_umask(), true)?;
                }
            }
            Ok(new_mode)
        }
        None => {
            // If no mode argument is specified return the mode from umask
            Ok(mode::get_umask())
        }
    }
}

#[cfg(windows)]
fn strip_minus_from_mode(_args: &mut Vec<String>) -> bool {
    false
}

#[cfg(not(windows))]
fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
    mode::strip_minus_from_mode(args)
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let mut args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    // Before we can parse 'args' with clap (and previously getopts),
    // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
    let mode_had_minus_prefix = strip_minus_from_mode(&mut args);

    let usage = usage();
    let after_help = get_long_usage();

    // Linux-specific options, not implemented
    // opts.optflag("Z", "context", "set SELinux security context" +
    // " of each created directory to CTX"),
    let matches = uu_app()
        .override_usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
    let verbose = matches.is_present(options::VERBOSE);
    let recursive = matches.is_present(options::PARENTS);

    match get_mode(&matches, mode_had_minus_prefix) {
        Ok(mode) => exec(dirs, recursive, mode, verbose),
        Err(f) => Err(USimpleError::new(1, f)),
    }
}

pub fn uu_app<'a>() -> App<'a> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .setting(AppSettings::InferLongArgs)
        .arg(
            Arg::new(options::MODE)
                .short('m')
                .long(options::MODE)
                .help("set file mode (not implemented on windows)")
                .takes_value(true),
        )
        .arg(
            Arg::new(options::PARENTS)
                .short('p')
                .long(options::PARENTS)
                .help("make parent directories as needed"),
        )
        .arg(
            Arg::new(options::VERBOSE)
                .short('v')
                .long(options::VERBOSE)
                .help("print a message for each printed directory"),
        )
        .arg(
            Arg::new(options::DIRS)
                .multiple_occurrences(true)
                .takes_value(true)
                .min_values(1)
                .allow_invalid_utf8(true),
        )
}

/**
 * Create the list of new directories
 */
fn exec(dirs: OsValues, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    for dir in dirs {
        let path = Path::new(dir);
        show_if_err!(mkdir(path, recursive, mode, verbose));
    }
    Ok(())
}

fn mkdir(path: &Path, recursive: bool, mode: u32, verbose: bool) -> UResult<()> {
    let create_dir = if recursive {
        fs::create_dir_all
    } else {
        fs::create_dir
    };

    create_dir(path).map_err_context(|| format!("cannot create directory {}", path.quote()))?;

    if verbose {
        println!(
            "{}: created directory {}",
            uucore::util_name(),
            path.quote()
        );
    }

    chmod(path, mode)
}

#[cfg(any(unix, target_os = "redox"))]
fn chmod(path: &Path, mode: u32) -> UResult<()> {
    use std::fs::{set_permissions, Permissions};
    use std::os::unix::fs::PermissionsExt;

    let mode = Permissions::from_mode(mode);

    set_permissions(path, mode)
        .map_err_context(|| format!("cannot set permissions {}", path.quote()))
}

#[cfg(windows)]
fn chmod(_path: &Path, _mode: u32) -> UResult<()> {
    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
    Ok(())
}
<|endoftext|>