<commit_before>extern crate itertools;

use std::collections::{HashSet,HashMap};
use self::itertools::Itertools;
use std::fmt;
use std::error;
use std::num;

// TODO remove the Option after the add of specific erros
#[derive(Debug)]
pub enum DFAError {
    MissingStartingState,
    MissingFinalStates,
    IncompleteTransition(usize),
    IllformedTransition(usize),
    Io(String,Option<usize>),
    Parse(num::ParseIntError,Option<usize>),
}

impl fmt::Display for DFAError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DFAError::Io(ref err,ref line) => write!(f, "IO error on line {:?}: {}", line, err),
            DFAError::MissingStartingState => write!(f, "The file is empty or only contains white characters."),
            DFAError::MissingFinalStates => write!(f, "The file does not specify the list of final states."),
            DFAError::IncompleteTransition(ref line) => write!(f, "Line {}: missing the src or the dest state.", line),
            DFAError::IllformedTransition(ref line) => write!(f, "Line {}: too much elements.", line),
            DFAError::Parse(ref err,ref line) => write!(f, "Parse error on line {:?}: {}", line, err),
        }
    }
}
impl error::Error for DFAError {
    fn description(&self) -> &str {
        match *self {
            DFAError::Io(ref err,ref _line) => err,
            DFAError::MissingStartingState => "The file is empty or only contains white characters.",
            DFAError::MissingFinalStates => "The file does not specify the list of final states.",
            DFAError::IncompleteTransition(ref _line) => "TODO", //format!("Line {}: missing the src or the dest state.", line),
            DFAError::IllformedTransition(ref _line) => "TODO", //format!("Line {}: missing the src or the dest state.", line),
            DFAError::Parse(ref err,ref _line) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            DFAError::Io(ref _err,ref _line) => Some(self),
            DFAError::MissingStartingState => Some(self),
            DFAError::MissingFinalStates => Some(self),
            DFAError::IncompleteTransition(_) => Some(self),
            DFAError::IllformedTransition(_) => Some(self),
            DFAError::Parse(ref err,ref _line) => Some(err),
        }
    }
}

impl From<String> for DFAError {
    fn from(err: String) -> DFAError {
        DFAError::Io(err,None)
    }
}

impl From<num::ParseIntError> for DFAError {
    fn from(err: num::ParseIntError) -> DFAError {
        DFAError::Parse(err,None)
    }
}

pub struct DFA {
    transitions : HashMap<(char,usize),usize>,
    start       : usize,
    finals      : HashSet<usize>,
}

impl DFA {
    pub fn new() -> DFA {
        DFA{transitions: HashMap::new(), start: 0, finals: HashSet::new()}
    }

    fn parse_dfa_error(contents: &str, line: usize) -> Result<usize, DFAError> {
            contents.parse::<usize>()
                    .map_err(|e| DFAError::Parse(e,Some(line)))
    }

    // TODO read from a "File"
    pub fn new_from_file(file: &str) -> Result<DFA, DFAError> {
        let mut dfa = DFA::new();
        // lines iterates over the non-empty lines.
        let mut lines = file
            .lines()
            .enumerate()
            .map(|(nline,line)| (nline+1,line.trim()))
            .filter(|&(_,line)| !line.is_empty());
        dfa.start = try!(lines
            .next()
            .ok_or(DFAError::MissingStartingState)
            .and_then(|(nline,contents)| DFA::parse_dfa_error(contents,nline)));
        dfa.finals = try!(lines
            .next()
            .ok_or(DFAError::MissingFinalStates)
            .and_then(|(nline,contents)| Ok((nline,contents.split_whitespace())))
            // need to move the closure inside the make to create a copy of nline for
            // th closure stack frame, otherwise the compiler can't guarantee that the
            // lifetime of the closure won't exceed the lifetime of nline.
            .and_then(|(nline,contents)| Ok((nline,contents.map(move |token| DFA::parse_dfa_error(token,nline)))))
            .and_then(|(_, mut contents)| {
                contents.fold_results(HashSet::new(),|mut acc,elt| {
                    acc.insert(elt);
                    acc
                })
            }));
        for (nline,line) in lines {
            let mut tokens = line.split_whitespace();
            // can't fail because lines iterates over the non-empty line
            let symb = tokens.next().unwrap().chars().nth(0).unwrap();
            let src = try!(tokens
                .next()
                .ok_or(DFAError::IncompleteTransition(nline))
                .and_then(|contents| DFA::parse_dfa_error(contents,nline)));
            let dest = try!(tokens
                .next()
                .ok_or(DFAError::IncompleteTransition(nline))
                .and_then(|contents| DFA::parse_dfa_error(contents,nline)));
            if tokens.next().is_some() {
                return Err(DFAError::IllformedTransition(nline));
            }
            dfa.transitions.insert((symb,src), dest);
        }
        Ok(dfa)
    }

    // TODO return the position of the first match
    //      maybe create an another function to do that
    pub fn run(&self, input: &str) -> bool {
        let f = input
            .chars()
            .fold(Some(self.start), |state,c| {
                match state {
                    Some(n) => self.transitions.get(&(c,n)).map(|v| *v),
                    None => None,
                }
            });
        match f {
            Some(n) => self.finals.contains(&n),
            None => false
        }
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "START: {}", self.start));
        try!(writeln!(f, "FINALS:"));
        for fi in self.finals.iter() {
            try!(writeln!(f,"  {}", fi));
        }
        try!(writeln!(f, "TRANSITIONS:"));
        for (tr,d) in self.transitions.iter() {
            let (c,s) = *tr;
            try!(writeln!(f, "  ({},{}) => {}", c, s, d));
        }
        write!(f, "")
    }
}

// TODO add specific error analysis
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_dfa() {
        let model =
            "0\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        let dfa = DFA::new_from_file(&model).unwrap();
        let samples =
            vec![("ababac", false),
                 ("ababc", true),
                 ("", false),
                 ("abc", true),
                 ("c", true),
                 ("ac", false),
                 ("ababababababababababababababababababababc", true),];

        for (input,expected_result) in samples {
            assert!(dfa.run(input) == expected_result, "input false for: \"{}\"", input);
        }
    }

    #[test]
    #[should_panic]
    fn test_empty_file() {
        let model =
            "";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_start_not_a_number() {
        let model =
            "a";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_many_starts() {
        let model =
            "0 1\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_no_finals() {
        let model =
            "1\n\
            ";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_finals_not_a_number() {
        let model =
            "1\n\
             2 a 3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_transitions_with_at_least_four_elements() {
        let model =
            "0 1\n\
             3\n\
             a 0 1 8";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_transitions_start_with_at_least_two_chars() {
        let model =
            "0 1\n\
             3\n\
             ab 2 3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_transitions_with_src_not_a_number() {
        let model =
            "0 1\n\
             3\n\
             c b 3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_transitions_with_dest_not_a_number() {
        let model =
            "0 1\n\
             3\n\
             c 2 b";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }
}
<commit_msg>Specific errors test.<commit_after>extern crate itertools;

use std::collections::{HashSet,HashMap};
use self::itertools::Itertools;
use std::fmt;
use std::error;
use std::num;

// TODO remove the Option after the add of specific erros
#[derive(Debug)]
pub enum DFAError {
    MissingStartingState,
    MissingFinalStates,
    IncompleteTransition(usize),
    IllformedTransition(usize),
    Io(String,Option<usize>),
    Parse(num::ParseIntError,Option<usize>),
}

impl fmt::Display for DFAError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DFAError::Io(ref err,ref line) => write!(f, "IO error on line {:?}: {}", line, err),
            DFAError::MissingStartingState => write!(f, "The file is empty or only contains white characters."),
            DFAError::MissingFinalStates => write!(f, "The file does not specify the list of final states."),
            DFAError::IncompleteTransition(ref line) => write!(f, "Line {}: missing the src or the dest state.", line),
            DFAError::IllformedTransition(ref line) => write!(f, "Line {}: too much elements.", line),
            DFAError::Parse(ref err,ref line) => write!(f, "Parse error on line {:?}: {}", line, err),
        }
    }
}

impl error::Error for DFAError {
    fn description(&self) -> &str {
        match *self {
            DFAError::Io(ref err,ref _line) => err,
            DFAError::MissingStartingState => "The file is empty or only contains white characters.",
            DFAError::MissingFinalStates => "The file does not specify the list of final states.",
            DFAError::IncompleteTransition(ref _line) => "TODO", //format!("Line {}: missing the src or the dest state.", line),
            DFAError::IllformedTransition(ref _line) => "TODO", //format!("Line {}: missing the src or the dest state.", line),
            DFAError::Parse(ref err,ref _line) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            DFAError::Io(ref _err,ref _line) => Some(self),
            DFAError::MissingStartingState => Some(self),
            DFAError::MissingFinalStates => Some(self),
            DFAError::IncompleteTransition(_) => Some(self),
            DFAError::IllformedTransition(_) => Some(self),
            DFAError::Parse(ref err,ref _line) => Some(err),
        }
    }
}

impl From<String> for DFAError {
    fn from(err: String) -> DFAError {
        DFAError::Io(err,None)
    }
}

impl From<num::ParseIntError> for DFAError {
    fn from(err: num::ParseIntError) -> DFAError {
        DFAError::Parse(err,None)
    }
}

#[derive(Debug)]
pub struct DFA {
    transitions : HashMap<(char,usize),usize>,
    start       : usize,
    finals      : HashSet<usize>,
}

impl DFA {
    pub fn new() -> DFA {
        DFA{transitions: HashMap::new(), start: 0, finals: HashSet::new()}
    }

    fn parse_dfa_error(contents: &str, line: usize) -> Result<usize, DFAError> {
            contents.parse::<usize>()
                    .map_err(|e| DFAError::Parse(e,Some(line)))
    }

    // TODO test if the tranisiton start with two symbols instead of one
    // TODO read from a "File"
    pub fn new_from_file(file: &str) -> Result<DFA, DFAError> {
        let mut dfa = DFA::new();
        // lines iterates over the non-empty lines.
        let mut lines = file
            .lines()
            .enumerate()
            .map(|(nline,line)| (nline+1,line.trim()))
            .filter(|&(_,line)| !line.is_empty());
        dfa.start = try!(lines
            .next()
            .ok_or(DFAError::MissingStartingState)
            .and_then(|(nline,contents)| DFA::parse_dfa_error(contents,nline)));
        dfa.finals = try!(lines
            .next()
            .ok_or(DFAError::MissingFinalStates)
            .and_then(|(nline,contents)| Ok((nline,contents.split_whitespace())))
            // need to move the closure inside the make to create a copy of nline for
            // th closure stack frame, otherwise the compiler can't guarantee that the
            // lifetime of the closure won't exceed the lifetime of nline.
            .and_then(|(nline,contents)| Ok((nline,contents.map(move |token| DFA::parse_dfa_error(token,nline)))))
            .and_then(|(_, mut contents)| {
                contents.fold_results(HashSet::new(),|mut acc,elt| {
                    acc.insert(elt);
                    acc
                })
            }));
        for (nline,line) in lines {
            let mut tokens = line.split_whitespace();
            // can't fail because lines iterates over the non-empty line
            let symb = tokens.next().unwrap().chars().nth(0).unwrap();
            println!("{}", nline);
            let src = try!(tokens
                .next()
                .ok_or(DFAError::IncompleteTransition(nline))
                .and_then(|contents| DFA::parse_dfa_error(contents,nline)));
            let dest = try!(tokens
                .next()
                .ok_or(DFAError::IncompleteTransition(nline))
                .and_then(|contents| DFA::parse_dfa_error(contents,nline)));
            if tokens.next().is_some() {
                return Err(DFAError::IllformedTransition(nline));
            }
            dfa.transitions.insert((symb,src), dest);
        }
        Ok(dfa)
    }

    // TODO return the position of the first match
    //      maybe create an another function to do that
    pub fn run(&self, input: &str) -> bool {
        let f = input
            .chars()
            .fold(Some(self.start), |state,c| {
                match state {
                    Some(n) => self.transitions.get(&(c,n)).map(|v| *v),
                    None => None,
                }
            });
        match f {
            Some(n) => self.finals.contains(&n),
            None => false
        }
    }
}

impl fmt::Display for DFA {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "START: {}", self.start));
        try!(writeln!(f, "FINALS:"));
        for fi in self.finals.iter() {
            try!(writeln!(f,"  {}", fi));
        }
        try!(writeln!(f, "TRANSITIONS:"));
        for (tr,d) in self.transitions.iter() {
            let (c,s) = *tr;
            try!(writeln!(f, "  ({},{}) => {}", c, s, d));
        }
        write!(f, "")
    }
}

// TODO add specific error analysis
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_dfa() {
        let model =
            "0\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        let dfa = DFA::new_from_file(&model).unwrap();
        let samples =
            vec![("ababac", false),
                 ("ababc", true),
                 ("", false),
                 ("abc", true),
                 ("c", true),
                 ("ac", false),
                 ("ababababababababababababababababababababc", true),];

        for (input,expected_result) in samples {
            assert!(dfa.run(input) == expected_result, "input false for: \"{}\"", input);
        }
    }

    #[test]
    fn test_empty_file() {
        let model =
            "";
        match DFA::new_from_file(model) {
            Err(DFAError::MissingStartingState) => assert!(true),
            _ => assert!(false, "Missing state expected."),
        }
    }

    #[test]
    fn test_start_not_a_number() {
        let model =
            "a";
        match DFA::new_from_file(model) {
            Err(DFAError::Parse(_,line)) => assert!(line.unwrap() == 1),
            _ => assert!(false, "Parsing error."),
        }
    }

    #[test]
    fn test_many_starts() {
        let model =
            "0 1\n\
             3\n\
             a 0 1\n\
             c 0 3\n\
             b 1 2\n\
             a 2 1\n\
             c 2 3";
        match DFA::new_from_file(model) {
            Err(DFAError::Parse(_,line)) => assert!(line.unwrap() == 1),
            _ => assert!(false, "Parsing error."),
        }
    }

    #[test]
    fn test_no_finals() {
        let model =
            "1\n\
            ";
        match DFA::new_from_file(model) {
            Err(DFAError::MissingFinalStates) => assert!(true),
            _ => assert!(false, "Missing final states expected."),
        }
    }

    #[test]
    fn test_finals_not_a_number() {
        let model =
            "1\n\
             2 a 3";
        match DFA::new_from_file(model) {
            Err(DFAError::Parse(_,line)) => assert!(line.unwrap() == 2),
            _ => assert!(false, "Parsing error."),
        }
    }

    #[test]
    fn test_no_transistions() {
        let model =
            "0\n\
             3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    fn test_transitions_with_at_least_four_elements() {
        let model =
            "0\n\
             3\n\
             a 0 1 8";
        match DFA::new_from_file(model) {
            Err(DFAError::IllformedTransition(line)) => assert!(line == 3),
            _ => assert!(false, "IllformedTransition expected."),
        }
    }

    #[test]
    #[should_panic]
    fn test_transitions_start_with_at_least_two_chars() {
        let model =
            "0\n\
             3\n\
             ab 2 3";
        let _dfa = DFA::new_from_file(&model).unwrap();
    }

    #[test]
    fn test_transitions_with_src_not_a_number() {
        let model =
            "0\n\
             3\n\
             c b 3";
        match DFA::new_from_file(model) {
            Err(DFAError::Parse(_,line)) => assert!(line.unwrap() == 3),
            _ => assert!(false, "Parsing error."),
        }
    }

    #[test]
    fn test_transitions_with_dest_not_a_number() {
        let model =
            "0\n\
             3\n\
             c 2 b";
        match DFA::new_from_file(model) {
            Err(DFAError::Parse(_,line)) => assert!(line.unwrap() == 3),
            _ => assert!(false, "Parsing error."),
        }
    }
}
<|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 std::cmp::min;
use std::num::Wrapping;

use sys_util::{GuestAddress, GuestMemory};

const VIRTQ_DESC_F_NEXT: u16 = 0x1;
const VIRTQ_DESC_F_WRITE: u16 = 0x2;
#[allow(dead_code)]
const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;

/// A virtio descriptor chain.
pub struct DescriptorChain<'a> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    queue_size: u16,
    ttl: u16, // used to prevent infinite chain cycles

    /// Index into the descriptor table
    pub index: u16,

    /// Guest physical address of device specific data
    pub addr: GuestAddress,

    /// Length of device specific data
    pub len: u32,

    /// Includes next, write, and indirect bits
    pub flags: u16,

    /// Index into the descriptor table of the next descriptor if flags has
    /// the next bit set
    pub next: u16,
}

impl<'a> DescriptorChain<'a> {
    fn checked_new(mem: &GuestMemory,
                   desc_table: GuestAddress,
                   queue_size: u16,
                   index: u16)
                   -> Option<DescriptorChain> {
        if index >= queue_size {
            return None;
        }

        let desc_head = match mem.checked_offset(desc_table, (index as usize) * 16) {
            Some(a) => a,
            None => return None,
        };
        // These reads can't fail unless Guest memory is hopelessly broken.
        let addr = GuestAddress(mem.read_obj_from_addr::<u64>(desc_head).unwrap() as usize);
        if mem.checked_offset(desc_head, 16).is_none() {
            return None;
        }
        let len: u32 = mem.read_obj_from_addr(desc_head.unchecked_add(8))
            .unwrap();
        let flags: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(12))
            .unwrap();
        let next: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(14))
            .unwrap();
        let chain = DescriptorChain {
            mem: mem,
            desc_table: desc_table,
            queue_size: queue_size,
            ttl: queue_size,
            index: index,
            addr: addr,
            len: len,
            flags: flags,
            next: next,
        };

        if chain.is_valid() { Some(chain) } else { None }
    }

    fn is_valid(&self) -> bool {
        if self.mem
               .checked_offset(self.addr, self.len as usize)
               .is_none() {
            false
        } else if self.has_next() && self.next >= self.queue_size {
            false
        } else {
            true
        }
    }

    /// Gets if this descriptor chain has another descriptor chain linked after it.
    pub fn has_next(&self) -> bool {
        self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1
    }

    /// If the driver designated this as a write only descriptor.
    ///
    /// If this is false, this descriptor is read only.
    /// Write only means the the emulated device can write and the driver can read.
    pub fn is_write_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE != 0
    }

    /// Gets the next descriptor in this descriptor chain, if there is one.
    ///
    /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is
    /// the head of the next _available_ descriptor chain.
    pub fn next_descriptor(&self) -> Option<DescriptorChain<'a>> {
        if self.has_next() {
            DescriptorChain::checked_new(self.mem, self.desc_table, self.queue_size, self.next)
                .map(|mut c| {
                         c.ttl = self.ttl - 1;
                         c
                     })
        } else {
            None
        }
    }
}

/// Consuming iterator over all available descriptor chain heads in the queue.
pub struct AvailIter<'a, 'b> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    avail_ring: GuestAddress,
    next_index: Wrapping<u16>,
    last_index: Wrapping<u16>,
    queue_size: u16,
    next_avail: &'b mut Wrapping<u16>,
}

impl<'a, 'b> Iterator for AvailIter<'a, 'b> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index == self.last_index {
            return None;
        }

        let offset = (4 + (self.next_index.0 % self.queue_size) * 2) as usize;
        let avail_addr = match self.mem.checked_offset(self.avail_ring, offset) {
            Some(a) => a,
            None => return None,
        };
        // This index is checked below in checked_new
        let desc_index: u16 = self.mem.read_obj_from_addr(avail_addr).unwrap();

        self.next_index += Wrapping(1);

        let ret =
            DescriptorChain::checked_new(self.mem, self.desc_table, self.queue_size, desc_index);
        if ret.is_some() {
            *self.next_avail += Wrapping(1);
        }
        ret
    }
}

#[derive(Clone)]
/// A virtio queue's parameters.
pub struct Queue {
    /// The maximal size in elements offered by the device
    pub max_size: u16,

    /// The queue size in elements the driver selected
    pub size: u16,

    /// Inidcates if the queue is finished with configuration
    pub ready: bool,

    /// Guest physical address of the descriptor table
    pub desc_table: GuestAddress,

    /// Guest physical address of the available ring
    pub avail_ring: GuestAddress,

    /// Guest physical address of the used ring
    pub used_ring: GuestAddress,

    next_avail: Wrapping<u16>,
    next_used: Wrapping<u16>,
}

impl Queue {
    /// Constructs an empty virtio queue with the given `max_size`.
    pub fn new(max_size: u16) -> Queue {
        Queue {
            max_size: max_size,
            size: 0,
            ready: false,
            desc_table: GuestAddress(0),
            avail_ring: GuestAddress(0),
            used_ring: GuestAddress(0),
            next_avail: Wrapping(0),
            next_used: Wrapping(0),
        }
    }

    /// Return the actual size of the queue, as the driver may not set up a
    /// queue as big as the device allows.
    pub fn actual_size(&self) -> u16 {
        min(self.size, self.max_size)
    }

    pub fn is_valid(&self, mem: &GuestMemory) -> bool {
        let queue_size = self.actual_size() as usize;
        let desc_table = self.desc_table;
        let desc_table_size = 16 * queue_size;
        let avail_ring = self.avail_ring;
        let avail_ring_size = 6 + 2 * queue_size;
        let used_ring = self.used_ring;
        let used_ring_size = 6 + 8 * queue_size;
        if !self.ready {
            println!("error: attempt to use virtio queue that is not marked ready");
            false
        } else if self.size > self.max_size || self.size == 0 ||
                  (self.size & (self.size - 1)) != 0 {
            println!("error: virtio queue with invalid size: {}", self.size);
            false
        } else if desc_table
                      .checked_add(desc_table_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     desc_table.offset(),
                     desc_table_size);
            false
        } else if avail_ring
                      .checked_add(avail_ring_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     avail_ring.offset(),
                     avail_ring_size);
            false
        } else if used_ring
                      .checked_add(used_ring_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     used_ring.offset(),
                     used_ring_size);
            false
        } else {
            true
        }

    }

    /// A consuming iterator over all available descriptor chain heads offered by the driver.
    pub fn iter<'a, 'b>(&'b mut self, mem: &'a GuestMemory) -> AvailIter<'a, 'b> {
        if !self.is_valid(mem) {
            return AvailIter {
                       mem: mem,
                       desc_table: GuestAddress(0),
                       avail_ring: GuestAddress(0),
                       next_index: Wrapping(0),
                       last_index: Wrapping(0),
                       queue_size: 0,
                       next_avail: &mut self.next_avail,
                   };
        }
        let queue_size = self.actual_size();
        let avail_ring = self.avail_ring;

        let index_addr = mem.checked_offset(avail_ring, 2).unwrap();
        // Note that last_index has no invalid values
        let last_index: u16 = mem.read_obj_from_addr::<u16>(index_addr).unwrap();

        AvailIter {
            mem: mem,
            desc_table: self.desc_table,
            avail_ring: avail_ring,
            next_index: self.next_avail,
            last_index: Wrapping(last_index),
            queue_size: queue_size,
            next_avail: &mut self.next_avail,
        }
    }

    /// Puts an available descriptor head into the used ring for use by the guest.
    pub fn add_used(&mut self, mem: &GuestMemory, desc_index: u16, len: u32) {
        if desc_index >= self.actual_size() {
            println!("error: attempted to add out of bounds descriptor to used ring: {}",
                     desc_index);
            return;
        }

        let used_ring = self.used_ring;
        let next_used = (self.next_used.0 % self.actual_size()) as usize;
        let used_elem = used_ring.unchecked_add(4 + next_used * 8);

        // These writes can't fail as we are guaranteed to be within the descriptor ring.
        mem.write_obj_at_addr(desc_index as u32, used_elem)
            .unwrap();
        mem.write_obj_at_addr(len as u32, used_elem.unchecked_add(4))
            .unwrap();

        self.next_used += Wrapping(1);
        mem.write_obj_at_addr(self.next_used.0 as u16, used_ring.unchecked_add(2))
            .unwrap();
    }
}
<commit_msg>crosvm: Add barrier before updating used_ring index<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 std::cmp::min;
use std::num::Wrapping;
use std::sync::atomic::{fence, Ordering};

use sys_util::{GuestAddress, GuestMemory};

const VIRTQ_DESC_F_NEXT: u16 = 0x1;
const VIRTQ_DESC_F_WRITE: u16 = 0x2;
#[allow(dead_code)]
const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;

/// A virtio descriptor chain.
pub struct DescriptorChain<'a> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    queue_size: u16,
    ttl: u16, // used to prevent infinite chain cycles

    /// Index into the descriptor table
    pub index: u16,

    /// Guest physical address of device specific data
    pub addr: GuestAddress,

    /// Length of device specific data
    pub len: u32,

    /// Includes next, write, and indirect bits
    pub flags: u16,

    /// Index into the descriptor table of the next descriptor if flags has
    /// the next bit set
    pub next: u16,
}

impl<'a> DescriptorChain<'a> {
    fn checked_new(mem: &GuestMemory,
                   desc_table: GuestAddress,
                   queue_size: u16,
                   index: u16)
                   -> Option<DescriptorChain> {
        if index >= queue_size {
            return None;
        }

        let desc_head = match mem.checked_offset(desc_table, (index as usize) * 16) {
            Some(a) => a,
            None => return None,
        };
        // These reads can't fail unless Guest memory is hopelessly broken.
        let addr = GuestAddress(mem.read_obj_from_addr::<u64>(desc_head).unwrap() as usize);
        if mem.checked_offset(desc_head, 16).is_none() {
            return None;
        }
        let len: u32 = mem.read_obj_from_addr(desc_head.unchecked_add(8))
            .unwrap();
        let flags: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(12))
            .unwrap();
        let next: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(14))
            .unwrap();
        let chain = DescriptorChain {
            mem: mem,
            desc_table: desc_table,
            queue_size: queue_size,
            ttl: queue_size,
            index: index,
            addr: addr,
            len: len,
            flags: flags,
            next: next,
        };

        if chain.is_valid() { Some(chain) } else { None }
    }

    fn is_valid(&self) -> bool {
        if self.mem
               .checked_offset(self.addr, self.len as usize)
               .is_none() {
            false
        } else if self.has_next() && self.next >= self.queue_size {
            false
        } else {
            true
        }
    }

    /// Gets if this descriptor chain has another descriptor chain linked after it.
    pub fn has_next(&self) -> bool {
        self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1
    }

    /// If the driver designated this as a write only descriptor.
    ///
    /// If this is false, this descriptor is read only.
    /// Write only means the the emulated device can write and the driver can read.
    pub fn is_write_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE != 0
    }

    /// Gets the next descriptor in this descriptor chain, if there is one.
    ///
    /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is
    /// the head of the next _available_ descriptor chain.
    pub fn next_descriptor(&self) -> Option<DescriptorChain<'a>> {
        if self.has_next() {
            DescriptorChain::checked_new(self.mem, self.desc_table, self.queue_size, self.next)
                .map(|mut c| {
                         c.ttl = self.ttl - 1;
                         c
                     })
        } else {
            None
        }
    }
}

/// Consuming iterator over all available descriptor chain heads in the queue.
pub struct AvailIter<'a, 'b> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    avail_ring: GuestAddress,
    next_index: Wrapping<u16>,
    last_index: Wrapping<u16>,
    queue_size: u16,
    next_avail: &'b mut Wrapping<u16>,
}

impl<'a, 'b> Iterator for AvailIter<'a, 'b> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.next_index == self.last_index {
            return None;
        }

        let offset = (4 + (self.next_index.0 % self.queue_size) * 2) as usize;
        let avail_addr = match self.mem.checked_offset(self.avail_ring, offset) {
            Some(a) => a,
            None => return None,
        };
        // This index is checked below in checked_new
        let desc_index: u16 = self.mem.read_obj_from_addr(avail_addr).unwrap();

        self.next_index += Wrapping(1);

        let ret =
            DescriptorChain::checked_new(self.mem, self.desc_table, self.queue_size, desc_index);
        if ret.is_some() {
            *self.next_avail += Wrapping(1);
        }
        ret
    }
}

#[derive(Clone)]
/// A virtio queue's parameters.
pub struct Queue {
    /// The maximal size in elements offered by the device
    pub max_size: u16,

    /// The queue size in elements the driver selected
    pub size: u16,

    /// Inidcates if the queue is finished with configuration
    pub ready: bool,

    /// Guest physical address of the descriptor table
    pub desc_table: GuestAddress,

    /// Guest physical address of the available ring
    pub avail_ring: GuestAddress,

    /// Guest physical address of the used ring
    pub used_ring: GuestAddress,

    next_avail: Wrapping<u16>,
    next_used: Wrapping<u16>,
}

impl Queue {
    /// Constructs an empty virtio queue with the given `max_size`.
    pub fn new(max_size: u16) -> Queue {
        Queue {
            max_size: max_size,
            size: 0,
            ready: false,
            desc_table: GuestAddress(0),
            avail_ring: GuestAddress(0),
            used_ring: GuestAddress(0),
            next_avail: Wrapping(0),
            next_used: Wrapping(0),
        }
    }

    /// Return the actual size of the queue, as the driver may not set up a
    /// queue as big as the device allows.
    pub fn actual_size(&self) -> u16 {
        min(self.size, self.max_size)
    }

    pub fn is_valid(&self, mem: &GuestMemory) -> bool {
        let queue_size = self.actual_size() as usize;
        let desc_table = self.desc_table;
        let desc_table_size = 16 * queue_size;
        let avail_ring = self.avail_ring;
        let avail_ring_size = 6 + 2 * queue_size;
        let used_ring = self.used_ring;
        let used_ring_size = 6 + 8 * queue_size;
        if !self.ready {
            println!("error: attempt to use virtio queue that is not marked ready");
            false
        } else if self.size > self.max_size || self.size == 0 ||
                  (self.size & (self.size - 1)) != 0 {
            println!("error: virtio queue with invalid size: {}", self.size);
            false
        } else if desc_table
                      .checked_add(desc_table_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     desc_table.offset(),
                     desc_table_size);
            false
        } else if avail_ring
                      .checked_add(avail_ring_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     avail_ring.offset(),
                     avail_ring_size);
            false
        } else if used_ring
                      .checked_add(used_ring_size)
                      .map_or(true, |v| !mem.address_in_range(v)) {
            println!("error: virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                     used_ring.offset(),
                     used_ring_size);
            false
        } else {
            true
        }

    }

    /// A consuming iterator over all available descriptor chain heads offered by the driver.
    pub fn iter<'a, 'b>(&'b mut self, mem: &'a GuestMemory) -> AvailIter<'a, 'b> {
        if !self.is_valid(mem) {
            return AvailIter {
                       mem: mem,
                       desc_table: GuestAddress(0),
                       avail_ring: GuestAddress(0),
                       next_index: Wrapping(0),
                       last_index: Wrapping(0),
                       queue_size: 0,
                       next_avail: &mut self.next_avail,
                   };
        }
        let queue_size = self.actual_size();
        let avail_ring = self.avail_ring;

        let index_addr = mem.checked_offset(avail_ring, 2).unwrap();
        // Note that last_index has no invalid values
        let last_index: u16 = mem.read_obj_from_addr::<u16>(index_addr).unwrap();

        AvailIter {
            mem: mem,
            desc_table: self.desc_table,
            avail_ring: avail_ring,
            next_index: self.next_avail,
            last_index: Wrapping(last_index),
            queue_size: queue_size,
            next_avail: &mut self.next_avail,
        }
    }

    /// Puts an available descriptor head into the used ring for use by the guest.
    pub fn add_used(&mut self, mem: &GuestMemory, desc_index: u16, len: u32) {
        if desc_index >= self.actual_size() {
            println!("error: attempted to add out of bounds descriptor to used ring: {}",
                     desc_index);
            return;
        }

        let used_ring = self.used_ring;
        let next_used = (self.next_used.0 % self.actual_size()) as usize;
        let used_elem = used_ring.unchecked_add(4 + next_used * 8);

        // These writes can't fail as we are guaranteed to be within the descriptor ring.
        mem.write_obj_at_addr(desc_index as u32, used_elem)
            .unwrap();
        mem.write_obj_at_addr(len as u32, used_elem.unchecked_add(4))
            .unwrap();

        self.next_used += Wrapping(1);

        // This fence ensures all descriptor writes are visible before the index update is.
        fence(Ordering::Release);

        mem.write_obj_at_addr(self.next_used.0 as u16, used_ring.unchecked_add(2))
            .unwrap();
    }
}
<|endoftext|>


<commit_before>use analysis::parameter::Parameter;
use analysis::rust_type::rust_type;
use analysis::conversion_type::ConversionType;
use env::Env;
use library;
use traits::*;

pub trait TrampolineFromGlib {
    fn trampoline_from_glib(&self, env: &Env, need_downcast: bool) -> String;
}

impl TrampolineFromGlib for Parameter {
    fn trampoline_from_glib(&self, env: &Env, need_downcast: bool) -> String {
        use analysis::conversion_type::ConversionType::*;
        match ConversionType::of(&env.library, self.typ) {
            Direct => self.name.clone(),
            Scalar => format!("from_glib({})", self.name),
            Pointer => {
                let (mut left, mut right) = from_glib_xxx(self.transfer);
                let type_name = rust_type(env, self.typ).into_string();
                left = format!("&{}::{}", type_name, left);
                if need_downcast {
                    right = format!("{}.downcast_unchecked()", right);
                }
                format!("{}{}{}", left, self.name, right)
            }
            Unknown => format!("/*Unknown conversion*/{}", self.name)
        }
    }
}

fn from_glib_xxx(transfer: library::Transfer) -> (String, String) {
    use library::Transfer::*;
    match transfer {
        None => ("from_glib_none(".into(), ")".into()),
        Full => ("from_glib_full(".into(), ")".into()),
        Container => ("from_glib_container(".into(), ")".into()),
    }
}
<commit_msg>Remove unneeded type names in trampoline closure calls<commit_after>use analysis::parameter::Parameter;
use analysis::rust_type::rust_type;
use analysis::conversion_type::ConversionType;
use env::Env;
use library;
use traits::*;

pub trait TrampolineFromGlib {
    fn trampoline_from_glib(&self, env: &Env, need_downcast: bool) -> String;
}

impl TrampolineFromGlib for Parameter {
    fn trampoline_from_glib(&self, env: &Env, need_downcast: bool) -> String {
        use analysis::conversion_type::ConversionType::*;
        let need_type_name = need_downcast || is_need_type_name(env, self.typ);
        match ConversionType::of(&env.library, self.typ) {
            Direct => self.name.clone(),
            Scalar => format!("from_glib({})", self.name),
            Pointer => {
                let (mut left, mut right) = from_glib_xxx(self.transfer);
                if need_type_name {
                    let type_name = rust_type(env, self.typ).into_string();
                    left = format!("&{}::{}", type_name, left);
                } else {
                    left = format!("&{}", left);
                }
                if need_downcast {
                    right = format!("{}.downcast_unchecked()", right);
                }
                format!("{}{}{}", left, self.name, right)
            }
            Unknown => format!("/*Unknown conversion*/{}", self.name)
        }
    }
}

fn from_glib_xxx(transfer: library::Transfer) -> (String, String) {
    use library::Transfer::*;
    match transfer {
        None => ("from_glib_none(".into(), ")".into()),
        Full => ("from_glib_full(".into(), ")".into()),
        Container => ("from_glib_container(".into(), ")".into()),
    }
}

fn is_need_type_name(env: &Env, type_id: library::TypeId) -> bool {
    if type_id.ns_id == library::INTERNAL_NAMESPACE {
        use library::Type::*;
        use library::Fundamental::*;
        match *env.type_(type_id) {
            Fundamental(fund) if fund == Utf8 => true,
            Fundamental(fund) if fund == Filename => true,
            _ => false,
        }
    } else {
        false
    }
}
<|endoftext|>


<commit_before><commit_msg>oops file<commit_after><|endoftext|>


<commit_before>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors. Successors are represented as extended basic blocks while predecessors are
//! represented by basic blocks.
//! BasicBlocks are denoted by tuples of EBB and branch/jump instructions. Each predecessor
//! tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here Ebb1 and Ebb2 would each have a single predecessor denoted as (Ebb0, `brz vx, Ebb1`)
//! and (Ebb0, `jmp Ebb2`) respectively.

use repr::Function;
use repr::entities::{Inst, Ebb};
use repr::instructions::InstructionData;
use entity_map::EntityMap;
use std::collections::BTreeSet;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// Storing predecessors in a BTreeSet ensures that their ordering is
/// stable with no duplicates.
pub type BasicBlockSet = BTreeSet<BasicBlock>;

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug)]
pub struct CFGNode {
    pub successors: BTreeSet<Ebb>,
    pub predecessors: BasicBlockSet,
}

impl CFGNode {
    /// CFG Node successors stripped of loop edges.
    pub fn children(&self) -> Vec<Ebb> {
        let pred_ebbs = self.predecessors.iter().map(|&(ebb, _)| { ebb }).collect();
        let children = self.successors.difference(&pred_ebbs).cloned().collect();
        children
    }
}

impl CFGNode {
    pub fn new() -> CFGNode {
        CFGNode {
            successors: BTreeSet::new(),
            predecessors: BTreeSet::new(),
        }
    }
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// During initialization mappings will be generated for any existing
    /// blocks within the CFG's associated function.
    pub fn new(func: &Function) -> ControlFlowGraph {
        let mut cfg = ControlFlowGraph { data: EntityMap::new() };

        // Even ebbs without predecessors should show up in the CFG, albeit
        // with no entires.
        for _ in &func.layout {
            cfg.push_ebb();
        }

        for ebb in &func.layout {
            for inst in func.layout.ebb_insts(ebb) {
                match func.dfg[inst] {
                    InstructionData::Branch { ty: _, opcode: _, ref data } => {
                        cfg.add_successor(ebb, data.destination);
                        cfg.add_predecessor(data.destination, (ebb, inst));
                    }
                    InstructionData::Jump { ty: _, opcode: _, ref data } => {
                        cfg.add_successor(ebb, data.destination);
                        cfg.add_predecessor(data.destination, (ebb, inst));
                    }
                    _ => (),
                }
            }
        }
        cfg
    }

    pub fn push_ebb(&mut self) {
        self.data.push(CFGNode::new());
    }

    pub fn add_successor(&mut self, from: Ebb, to: Ebb) {
        self.data[from].successors.insert(to);
    }

    pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: BasicBlock) {
        self.data[ebb].predecessors.insert(predecessor);
    }

    pub fn get_predecessors(&self, ebb: Ebb) -> &BasicBlockSet {
        &self.data[ebb].predecessors
    }

    pub fn get_successors(&self, ebb: Ebb) -> &BTreeSet<Ebb> {
        &self.data[ebb].successors
    }

    pub fn get_children(&self, ebb: Ebb) -> Vec<Ebb> {
        self.data[ebb].children()
    }

    pub fn postorder_ebbs(&self) -> Vec<Ebb> {
        if self.len() < 1 {
            return Vec::new();
        }
        let mut stack_a = vec![Ebb::with_number(0).unwrap()];
        let mut stack_b = Vec::new();
        while stack_a.len() > 0 {
            let cur = stack_a.pop().unwrap();
            for child in self.get_children(cur) {
                stack_a.push(child);
            }
            stack_b.push(cur);
        }
        stack_b
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn predecessors_iter(&self) -> CFGPredecessorsIter {
        CFGPredecessorsIter {
            cur: 0,
            cfg: &self,
        }
    }
}

/// Iterate through every mapping of ebb to predecessors in the CFG
pub struct CFGPredecessorsIter<'a> {
    cfg: &'a ControlFlowGraph,
    cur: usize,
}

impl<'a> Iterator for CFGPredecessorsIter<'a> {
    type Item = (Ebb, &'a BasicBlockSet);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur < self.cfg.len() {
            let ebb = Ebb::with_number(self.cur as u32).unwrap();
            let bbs = self.cfg.get_predecessors(ebb);
            self.cur += 1;
            Some((ebb, bbs))
        } else {
            None
        }
    }
}

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

    use test_utils::make_inst;

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(None, cfg.predecessors_iter().next());
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::new(&func);
        let nodes = cfg.predecessors_iter().collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for (ebb, predecessors) in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(predecessors.len(), 0);
            assert_eq!(predecessors.len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2);
        func.layout.append_inst(br_ebb0_ebb2, ebb0);

        let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
        func.layout.append_inst(jmp_ebb0_ebb1, ebb0);

        let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb1_ebb1, ebb1);

        let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb1_ebb2, ebb1);

        let cfg = ControlFlowGraph::new(&func);

        let ebb0_predecessors = cfg.get_predecessors(ebb0);
        let ebb1_predecessors = cfg.get_predecessors(ebb1);
        let ebb2_predecessors = cfg.get_predecessors(ebb2);

        let ebb0_successors = cfg.get_successors(ebb0);
        let ebb1_successors = cfg.get_successors(ebb1);
        let ebb2_successors = cfg.get_successors(ebb2);

        assert_eq!(ebb0_predecessors.len(), 0);
        assert_eq!(ebb1_predecessors.len(), 2);
        assert_eq!(ebb2_predecessors.len(), 2);

        assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
        assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

        assert_eq!(ebb0_successors.len(), 2);
        assert_eq!(ebb1_successors.len(), 2);
        assert_eq!(ebb2_successors.len(), 0);

        assert_eq!(ebb0_successors.contains(&ebb1), true);
        assert_eq!(ebb0_successors.contains(&ebb2), true);
        assert_eq!(ebb1_successors.contains(&ebb1), true);
        assert_eq!(ebb1_successors.contains(&ebb2), true);

        assert_eq!(cfg.get_children(ebb0), vec![ebb1, ebb2]);
        assert_eq!(cfg.get_children(ebb1), vec![ebb2]);
        assert_eq!(cfg.get_children(ebb2), Vec::new());
    }

    #[test]
    fn postorder_traversal() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        let ebb3 = func.dfg.make_ebb();
        let ebb4 = func.dfg.make_ebb();
        let ebb5 = func.dfg.make_ebb();

        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);
        func.layout.append_ebb(ebb3);
        func.layout.append_ebb(ebb4);
        func.layout.append_ebb(ebb5);

        let br_ebb0_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb0_ebb1, ebb0);

        let jmp_ebb0_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb0_ebb2, ebb0);

        let jmp_ebb1_ebb3 = make_inst::jump(&mut func, ebb3);
        func.layout.append_inst(jmp_ebb1_ebb3, ebb1);

        let br_ebb2_ebb4 = make_inst::branch(&mut func, ebb4);
        func.layout.append_inst(br_ebb2_ebb4, ebb2);

        let jmp_ebb2_ebb5 = make_inst::jump(&mut func, ebb5);
        func.layout.append_inst(jmp_ebb2_ebb5, ebb2);

        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(cfg.postorder_ebbs(), vec![ebb0, ebb2, ebb5, ebb4, ebb1, ebb3]);
    }
}
<commit_msg>Cargo-fmt fixes<commit_after>//! A control flow graph represented as mappings of extended basic blocks to their predecessors
//! and successors. Successors are represented as extended basic blocks while predecessors are
//! represented by basic blocks.
//! BasicBlocks are denoted by tuples of EBB and branch/jump instructions. Each predecessor
//! tuple corresponds to the end of a basic block.
//!
//! ```c
//!     Ebb0:
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         brz vx, Ebb1 ; end of basic block
//!
//!         ...          ; beginning of basic block
//!
//!         ...
//!
//!         jmp Ebb2     ; end of basic block
//! ```
//!
//! Here Ebb1 and Ebb2 would each have a single predecessor denoted as (Ebb0, `brz vx, Ebb1`)
//! and (Ebb0, `jmp Ebb2`) respectively.

use repr::Function;
use repr::entities::{Inst, Ebb};
use repr::instructions::InstructionData;
use entity_map::EntityMap;
use std::collections::BTreeSet;

/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);

/// Storing predecessors in a BTreeSet ensures that their ordering is
/// stable with no duplicates.
pub type BasicBlockSet = BTreeSet<BasicBlock>;

/// A container for the successors and predecessors of some Ebb.
#[derive(Debug)]
pub struct CFGNode {
    pub successors: BTreeSet<Ebb>,
    pub predecessors: BasicBlockSet,
}

impl CFGNode {
    /// CFG Node successors stripped of loop edges.
    pub fn children(&self) -> Vec<Ebb> {
        let pred_ebbs = self.predecessors.iter().map(|&(ebb, _)| ebb).collect();
        let children = self.successors.difference(&pred_ebbs).cloned().collect();
        children
    }
}

impl CFGNode {
    pub fn new() -> CFGNode {
        CFGNode {
            successors: BTreeSet::new(),
            predecessors: BTreeSet::new(),
        }
    }
}

/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
/// and successors where predecessors are basic blocks and successors are
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
    data: EntityMap<Ebb, CFGNode>,
}

impl ControlFlowGraph {
    /// During initialization mappings will be generated for any existing
    /// blocks within the CFG's associated function.
    pub fn new(func: &Function) -> ControlFlowGraph {
        let mut cfg = ControlFlowGraph { data: EntityMap::new() };

        // Even ebbs without predecessors should show up in the CFG, albeit
        // with no entires.
        for _ in &func.layout {
            cfg.push_ebb();
        }

        for ebb in &func.layout {
            for inst in func.layout.ebb_insts(ebb) {
                match func.dfg[inst] {
                    InstructionData::Branch { ty: _, opcode: _, ref data } => {
                        cfg.add_successor(ebb, data.destination);
                        cfg.add_predecessor(data.destination, (ebb, inst));
                    }
                    InstructionData::Jump { ty: _, opcode: _, ref data } => {
                        cfg.add_successor(ebb, data.destination);
                        cfg.add_predecessor(data.destination, (ebb, inst));
                    }
                    _ => (),
                }
            }
        }
        cfg
    }

    pub fn push_ebb(&mut self) {
        self.data.push(CFGNode::new());
    }

    pub fn add_successor(&mut self, from: Ebb, to: Ebb) {
        self.data[from].successors.insert(to);
    }

    pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: BasicBlock) {
        self.data[ebb].predecessors.insert(predecessor);
    }

    pub fn get_predecessors(&self, ebb: Ebb) -> &BasicBlockSet {
        &self.data[ebb].predecessors
    }

    pub fn get_successors(&self, ebb: Ebb) -> &BTreeSet<Ebb> {
        &self.data[ebb].successors
    }

    pub fn get_children(&self, ebb: Ebb) -> Vec<Ebb> {
        self.data[ebb].children()
    }

    pub fn postorder_ebbs(&self) -> Vec<Ebb> {
        if self.len() < 1 {
            return Vec::new();
        }
        let mut stack_a = vec![Ebb::with_number(0).unwrap()];
        let mut stack_b = Vec::new();
        while stack_a.len() > 0 {
            let cur = stack_a.pop().unwrap();
            for child in self.get_children(cur) {
                stack_a.push(child);
            }
            stack_b.push(cur);
        }
        stack_b
    }

    pub fn len(&self) -> usize {
        self.data.len()
    }

    pub fn predecessors_iter(&self) -> CFGPredecessorsIter {
        CFGPredecessorsIter {
            cur: 0,
            cfg: &self,
        }
    }
}

/// Iterate through every mapping of ebb to predecessors in the CFG
pub struct CFGPredecessorsIter<'a> {
    cfg: &'a ControlFlowGraph,
    cur: usize,
}

impl<'a> Iterator for CFGPredecessorsIter<'a> {
    type Item = (Ebb, &'a BasicBlockSet);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur < self.cfg.len() {
            let ebb = Ebb::with_number(self.cur as u32).unwrap();
            let bbs = self.cfg.get_predecessors(ebb);
            self.cur += 1;
            Some((ebb, bbs))
        } else {
            None
        }
    }
}

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

    use test_utils::make_inst;

    #[test]
    fn empty() {
        let func = Function::new();
        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(None, cfg.predecessors_iter().next());
    }

    #[test]
    fn no_predecessors() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let cfg = ControlFlowGraph::new(&func);
        let nodes = cfg.predecessors_iter().collect::<Vec<_>>();
        assert_eq!(nodes.len(), 3);

        let mut fun_ebbs = func.layout.ebbs();
        for (ebb, predecessors) in nodes {
            assert_eq!(ebb, fun_ebbs.next().unwrap());
            assert_eq!(predecessors.len(), 0);
            assert_eq!(predecessors.len(), 0);
            assert_eq!(cfg.get_successors(ebb).len(), 0);
        }
    }

    #[test]
    fn branches_and_jumps() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);

        let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2);
        func.layout.append_inst(br_ebb0_ebb2, ebb0);

        let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
        func.layout.append_inst(jmp_ebb0_ebb1, ebb0);

        let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb1_ebb1, ebb1);

        let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb1_ebb2, ebb1);

        let cfg = ControlFlowGraph::new(&func);

        let ebb0_predecessors = cfg.get_predecessors(ebb0);
        let ebb1_predecessors = cfg.get_predecessors(ebb1);
        let ebb2_predecessors = cfg.get_predecessors(ebb2);

        let ebb0_successors = cfg.get_successors(ebb0);
        let ebb1_successors = cfg.get_successors(ebb1);
        let ebb2_successors = cfg.get_successors(ebb2);

        assert_eq!(ebb0_predecessors.len(), 0);
        assert_eq!(ebb1_predecessors.len(), 2);
        assert_eq!(ebb2_predecessors.len(), 2);

        assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
        assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
        assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);

        assert_eq!(ebb0_successors.len(), 2);
        assert_eq!(ebb1_successors.len(), 2);
        assert_eq!(ebb2_successors.len(), 0);

        assert_eq!(ebb0_successors.contains(&ebb1), true);
        assert_eq!(ebb0_successors.contains(&ebb2), true);
        assert_eq!(ebb1_successors.contains(&ebb1), true);
        assert_eq!(ebb1_successors.contains(&ebb2), true);

        assert_eq!(cfg.get_children(ebb0), vec![ebb1, ebb2]);
        assert_eq!(cfg.get_children(ebb1), vec![ebb2]);
        assert_eq!(cfg.get_children(ebb2), Vec::new());
    }

    #[test]
    fn postorder_traversal() {
        let mut func = Function::new();
        let ebb0 = func.dfg.make_ebb();
        let ebb1 = func.dfg.make_ebb();
        let ebb2 = func.dfg.make_ebb();
        let ebb3 = func.dfg.make_ebb();
        let ebb4 = func.dfg.make_ebb();
        let ebb5 = func.dfg.make_ebb();

        func.layout.append_ebb(ebb0);
        func.layout.append_ebb(ebb1);
        func.layout.append_ebb(ebb2);
        func.layout.append_ebb(ebb3);
        func.layout.append_ebb(ebb4);
        func.layout.append_ebb(ebb5);

        let br_ebb0_ebb1 = make_inst::branch(&mut func, ebb1);
        func.layout.append_inst(br_ebb0_ebb1, ebb0);

        let jmp_ebb0_ebb2 = make_inst::jump(&mut func, ebb2);
        func.layout.append_inst(jmp_ebb0_ebb2, ebb0);

        let jmp_ebb1_ebb3 = make_inst::jump(&mut func, ebb3);
        func.layout.append_inst(jmp_ebb1_ebb3, ebb1);

        let br_ebb2_ebb4 = make_inst::branch(&mut func, ebb4);
        func.layout.append_inst(br_ebb2_ebb4, ebb2);

        let jmp_ebb2_ebb5 = make_inst::jump(&mut func, ebb5);
        func.layout.append_inst(jmp_ebb2_ebb5, ebb2);

        let cfg = ControlFlowGraph::new(&func);
        assert_eq!(cfg.postorder_ebbs(),
                   vec![ebb0, ebb2, ebb5, ebb4, ebb1, ebb3]);
    }
}
<|endoftext|>


<commit_before>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
    }
}
<commit_msg>Added support for invite-notify capability.<commit_after>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
    /// [invite-notify](http://ircv3.net/specs/extensions/invite-notify-3.2.html)
    InviteNotify,
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
            Capability::InviteNotify => "invite-notify",
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
        assert_eq!(InviteNotify.as_ref(), "invite-notify");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Module providing the TestLogger Implementation

use super::logging::should_skip;
use crate::{Config, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};

use std::thread;

/// The TestLogger struct. Provides a very basic Logger implementation that may be captured by cargo.
pub struct TestLogger {
    level: LevelFilter,
    config: Config,
}

impl TestLogger {
    /// init function. Globally initializes the TestLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
        set_max_level(log_level.clone());
        set_boxed_logger(TestLogger::new(log_level, config))
    }

    /// allows to create a new logger, that can be independently used, no matter what is globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
        Box::new(TestLogger {
            level: log_level,
            config,
        })
    }
}

impl Log for TestLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        if self.enabled(record.metadata()) {
            let _ = log(&self.config, record);
        }
    }

    fn flush(&self) {}
}

impl SharedLogger for TestLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}

#[inline(always)]
pub fn log(config: &Config, record: &Record<'_>) {
    if should_skip(&config, &record) {
        return;
    }

    if let Some(time) = config.time {
        if time <= record.level() {
            write_time(config);
        }
    }

    if let Some(level) = config.level {
        if level <= record.level() {
            write_level(record);
        }
    }

    if let Some(thread) = config.thread {
        if thread < record.level() {
            write_thread_id();
        }
    }

    if let Some(target) = config.target {
        if target <= record.level() {
            write_target(record);
        }
    }

    if let Some(location) = config.location {
        if location <= record.level() {
            write_location(record);
        }
    }

    write_args(record);
}

#[inline(always)]
pub fn write_time(config: &Config) {
    let cur_time = chrono::Utc::now();
    print!(
        "{} ",
        cur_time.format(config.time_format.unwrap_or("%H:%M:%S"))
    );
}

#[inline(always)]
pub fn write_level(record: &Record<'_>) {
    print!("[{}] ", record.level());
}

#[inline(always)]
pub fn write_thread_id() {
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    print!("({}) ", id);
}

#[inline(always)]
pub fn write_target(record: &Record<'_>) {
    print!("{}: ", record.target());
}

#[inline(always)]
pub fn write_location(record: &Record<'_>) {
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        print!("[{}:{}] ", file, line);
    } else {
        print!("[{}:<unknown>] ", file);
    }
}

#[inline(always)]
pub fn write_args(record: &Record<'_>) {
    println!("{}", record.args());
}
<commit_msg>Fix #46<commit_after>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Module providing the TestLogger Implementation

use super::logging::should_skip;
use crate::{Config, SharedLogger, LevelPadding};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};

use std::thread;

/// The TestLogger struct. Provides a very basic Logger implementation that may be captured by cargo.
pub struct TestLogger {
    level: LevelFilter,
    config: Config,
}

impl TestLogger {
    /// init function. Globally initializes the TestLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
        set_max_level(log_level.clone());
        set_boxed_logger(TestLogger::new(log_level, config))
    }

    /// allows to create a new logger, that can be independently used, no matter what is globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
        Box::new(TestLogger {
            level: log_level,
            config,
        })
    }
}

impl Log for TestLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        if self.enabled(record.metadata()) {
            let _ = log(&self.config, record);
        }
    }

    fn flush(&self) {}
}

impl SharedLogger for TestLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}

#[inline(always)]
pub fn log(config: &Config, record: &Record<'_>) {
    if should_skip(&config, &record) {
        return;
    }

    if config.time <= record.level() && config.time != LevelFilter::Off {
        write_time(config);
    }

    if config.level <= record.level() && config.level != LevelFilter::Off {
        write_level(record, config);
    }

    if config.thread < record.level() && config.thread != LevelFilter::Off {
        write_thread_id();
    }

    if config.target <= record.level() && config.target != LevelFilter::Off {
        write_target(record);
    }

    if config.location <= record.level() && config.location != LevelFilter::Off {
        write_location(record);
    }

    write_args(record);
}

#[inline(always)]
pub fn write_time(config: &Config) {
    let cur_time = if config.time_local {
        chrono::Local::now().naive_local() + config.time_offset
    } else {
        chrono::Utc::now().naive_utc() + config.time_offset
    };
    print!(
        "{} ",
        cur_time.format(&*config.time_format)
    );
}

#[inline(always)]
pub fn write_level(record: &Record<'_>, config: &Config) {
    match config.level_padding {
        LevelPadding::Left => print!("[{: >5}] ", record.level()),
        LevelPadding::Right => print!("[{: <5}] ", record.level()),
        LevelPadding::Off => print!("[{}] ", record.level()),
    };
}

#[inline(always)]
pub fn write_thread_id() {
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    print!("({}) ", id);
}

#[inline(always)]
pub fn write_target(record: &Record<'_>) {
    print!("{}: ", record.target());
}

#[inline(always)]
pub fn write_location(record: &Record<'_>) {
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        print!("[{}:{}] ", file, line);
    } else {
        print!("[{}:<unknown>] ", file);
    }
}

#[inline(always)]
pub fn write_args(record: &Record<'_>) {
    println!("{}", record.args());
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();
    let doc_comment = format!("An iterator over the variants of [{}]", name);

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    Ok(quote! {
        #[doc = #doc_comment]
        #[allow(
            missing_copy_implementations,
            missing_debug_implementations,
        )]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<commit_msg>implement Debug for EnumIter (#240)<commit_after>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();
    let doc_comment = format!("An iterator over the variants of [{}]", name);

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    // Create a string literal "MyEnumIter" to use in the debug impl.
    let iter_name_debug_struct =
        syn::parse_str::<syn::LitStr>(&format!("\"{}\"", iter_name)).unwrap();

    Ok(quote! {
        #[doc = #doc_comment]
        #[allow(
            missing_copy_implementations,
        )]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics core::fmt::Debug for #iter_name #ty_generics #where_clause {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                // We don't know if the variants implement debug themselves so the only thing we
                // can really show is how many elements are left.
                f.debug_struct(#iter_name_debug_struct)
                    .field("len", &self.len())
                    .finish()
            }
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<|endoftext|>


<commit_before><commit_msg>Bug 1543359 - P14. Fix "Wrench" test r=nical<commit_after><|endoftext|>


<commit_before>//! This mod specifies and implements the Distributed Lock Manager Redlock object, as well
//! as the necessary functions lock() and unlock(). It also declares the struct Lock which
//! is used to hold necessary information about each lock a client acquires.

use redis::{Client, Connection};
use types::{RedlockResult, Error};
use time::precise_time_s;

/// Distributed Lock Manager class object
pub struct Redlock {
    /// list of connections with Master Nodes
    servers: Vec<Connection>,
    /// no. of retries to secure locks
    retry_count: i32,
    /// time delay between each retry
    retry_delay: f32,
    /// number of locks needed
    quorum: i32,
    /// clock drift factor
    clock_drift_factor: f32,
}

/// Represents the Lock a client holds
pub struct Lock {
    /// an integer representing the number of milliseconds the lock will be valid
    validity: i32,
    /// the name of the locked resource as specified by the user.
    resource: String,
    /// a random value which is used to safely reclaim the lock.
    key: String,
}

impl Redlock {
    /// instantialize a lock manager with a vector of URLs (format: redis://host:port/db)
    /// for each Redis master node, and optionally specify a retry count and delay between
    /// each retry. If None is given, the default will be 3 and 0.2s respectively
    pub fn dlm(urls : Vec<String>, retry_count: Option<i32>, retry_delay: Option<f32>)
        -> RedlockResult<Redlock> {
        let mut servers = Vec::new();
        let quorum = urls.len() as i32;
        for u in urls {
            let client_res = Client::open(&*u);
            if client_res.is_ok() {
                let con_res = client_res.unwrap().get_connection();
                if con_res.is_ok() {
                    servers.push(con_res.unwrap());
                }
            }
        }
        if (servers.len() as i32) < quorum {
            return Err(Error::NotEnoughMasters);
        }
        let rc = match retry_count {
            Some(x) => x,
            None => 3,
        };
        let rd = match retry_delay {
            Some(x) => x,
            None => 0.2,
        };
        let cdf = 0.01;
        Ok(Redlock {
            servers: servers,
            retry_count: rc,
            retry_delay: rd,
            quorum: quorum,
            clock_drift_factor: cdf,
        })
    }

    /// generates unique id for lock key
    fn get_unique_id(&self) -> String {
        unimplemented!()
    }

    /// acquire lock from one server
    fn lock_instance(&self, server : &Connection, res_name : &str, val : &str,
                     ttl: i32) -> RedlockResult<()> {
        Ok(())
    }

    /// release lock from one server
    fn unlock_instance(&self, server : Connection, res_name : &str,
                       val : &str) -> () {
    }

    /// locks resource specified by res_name for ttl in miliseconds
    pub fn lock(&self, res_name: String, ttl: i32) -> RedlockResult<Lock> {
        let mut retry = 0;
        let val = self.get_unique_id();
        let drift : i32 = (((ttl as f32) * self.clock_drift_factor) as i32) + 2;
        while retry < self.retry_count {
            let mut n = 0;
            let start_time : i32 = (precise_time_s() * 1000.0) as i32;
            for server in self.servers {
                let res = self.lock_instance(server, &res_name, &val, ttl);
                if res.is_ok() {
                    n = n + 1;
                }
            }
            let elapsed_time : i32 = ((precise_time_s() * 1000.0) as i32) - start_time;
            let validity = ttl - elapsed_time - drift;
            if validity > 0 && n >= self.quorum {
                // lock successful!
                return Ok(Lock::new(validity, res_name, val));
            }  else {
                for server in self.servers {
                    self.unlock_instance(server, &res_name, &val);
                }
                retry = retry + 1;
                //TODO: sleep for retry_delay
            }
        }
        Err(Error::CannotObtainLock)
    }
    /// unlocks resource held by Lock
    pub fn unlock(lock: Lock) -> RedlockResult<()> {
        for server in self.servers {
            let res = self.unlock_instance(server, lock.resource, lock.key);
            if res.is_err() {
                Err(Error::MultipleRedlock)
            }
        }
        Ok(())
    }
}

impl Lock {
    /// instantialize a Lock with validity, resource name, and key
    pub fn new(validity: i32, res: String, key: String) -> Self {
        Lock { validity: validity, resource: res, key: key }
    }
}
<commit_msg>implementing lock_instance<commit_after>//! This mod specifies and implements the Distributed Lock Manager Redlock object, as well
//! as the necessary functions lock() and unlock(). It also declares the struct Lock which
//! is used to hold necessary information about each lock a client acquires.

use redis::{Client, Connection, RedisResult, FromRedisValue};
use types::{RedlockResult, Error};
use time::precise_time_s;
use redis::commands::Commands;

/// Distributed Lock Manager class object
pub struct Redlock {
    /// list of connections with Master Nodes
    servers: Vec<Connection>,
    /// no. of retries to secure locks
    retry_count: i32,
    /// time delay between each retry
    retry_delay: f32,
    /// number of locks needed
    quorum: i32,
    /// clock drift factor
    clock_drift_factor: f32,
}

/// Represents the Lock a client holds
pub struct Lock {
    /// an integer representing the number of milliseconds the lock will be valid
    validity: i32,
    /// the name of the locked resource as specified by the user.
    resource: String,
    /// a random value which is used to safely reclaim the lock.
    key: String,
}

impl Redlock {
    /// instantialize a lock manager with a vector of URLs (format: redis://host:port/db)
    /// for each Redis master node, and optionally specify a retry count and delay between
    /// each retry. If None is given, the default will be 3 and 0.2s respectively
    pub fn dlm(urls : Vec<String>, retry_count: Option<i32>, retry_delay: Option<f32>)
        -> RedlockResult<Redlock> {
        let mut servers = Vec::new();
        let quorum = urls.len() as i32;
        for u in urls {
            let client_res = Client::open(&*u);
            if client_res.is_ok() {
                let con_res = client_res.unwrap().get_connection();
                if con_res.is_ok() {
                    servers.push(con_res.unwrap());
                }
            }
        }
        if (servers.len() as i32) < quorum {
            return Err(Error::NotEnoughMasters);
        }
        let rc = match retry_count {
            Some(x) => x,
            None => 3,
        };
        let rd = match retry_delay {
            Some(x) => x,
            None => 0.2,
        };
        let cdf = 0.01;
        Ok(Redlock {
            servers: servers,
            retry_count: rc,
            retry_delay: rd,
            quorum: quorum,
            clock_drift_factor: cdf,
        })
    }

    /// generates unique id for lock key
    fn get_unique_id(&self) -> String {
        unimplemented!()
    }

    /// acquire lock from one server
    fn lock_instance(&self, server : &Connection, res_name : &str, val : &str,
                     ttl: i32) -> RedlockResult<()> {
        if server.set_nx(res_name.to_string(), val.to_string()).is_ok() {
            Ok(())
        } else {
            Err(Error::MultipleRedlock)
        }
    }

    /// release lock from one server
    fn unlock_instance(&self, server : Connection, res_name : &str,
                       val : &str) -> () {
    }

    /// locks resource specified by res_name for ttl in miliseconds
    pub fn lock(&self, res_name: String, ttl: i32) -> RedlockResult<Lock> {
        let mut retry = 0;
        let val = self.get_unique_id();
        let drift : i32 = (((ttl as f32) * self.clock_drift_factor) as i32) + 2;
        while retry < self.retry_count {
            let mut n = 0;
            let start_time : i32 = (precise_time_s() * 1000.0) as i32;
            /*
            for server in self.servers {
                let res = self.lock_instance(server, &res_name, &val, ttl);
                if res.is_ok() {
                    n = n + 1;
                }
            }
            */
            let elapsed_time : i32 = ((precise_time_s() * 1000.0) as i32) - start_time;
            let validity = ttl - elapsed_time - drift;
            if validity > 0 && n >= self.quorum {
                // lock successful!
                return Ok(Lock::new(validity, res_name, val));
            }  else {
                /*
                for server in self.servers {
                    self.unlock_instance(server, &res_name, &val);
                }
                */
                retry = retry + 1;
                //TODO: sleep for retry_delay
            }
        }
        Err(Error::CannotObtainLock)
    }
    /// unlocks resource held by Lock
    pub fn unlock(lock: Lock) -> RedlockResult<()> {
        /*
        for server in self.servers {
            let res = self.unlock_instance(server, lock.resource, lock.key);
            if res.is_err() {
                Err(Error::MultipleRedlock)
            }
        }
        */
        Ok(())
    }
}

impl Lock {
    /// instantialize a Lock with validity, resource name, and key
    pub fn new(validity: i32, res: String, key: String) -> Self {
        Lock { validity: validity, resource: res, key: key }
    }
}
<|endoftext|>