<commit_before>//! Topic filter

use std::io::{Read, Write};
use std::fmt;
use std::error::Error;
use std::ops::Deref;
use std::mem;
use std::convert::Into;

use regex::Regex;

use {Encodable, Decodable};
use encodable::StringEncodeError;
use topic_name::TopicNameRef;

const VALIDATE_TOPIC_FILTER_REGEX: &'static str = r"^(#|((\+|\$?[^/\$\+#]+)?(/(\+|[^/\$\+#]+))*?(/(\+|#|[^/\$\+#]+))?))$";

lazy_static! {
    static ref TOPIC_FILTER_VALIDATOR: Regex = Regex::new(VALIDATE_TOPIC_FILTER_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_filter(topic: &str) -> bool {
    topic.is_empty() || topic.as_bytes().len() > 65535 || !TOPIC_FILTER_VALIDATOR.is_match(&topic)
}

/// Topic filter
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
///
/// ```rust
/// use mqtt::{TopicFilter, TopicNameRef};
///
/// let topic_filter = TopicFilter::new("sport/+/player1").unwrap();
/// let matcher = topic_filter.get_matcher();
/// assert!(matcher.is_match(TopicNameRef::new("sport/abc/player1").unwrap()));
/// ```
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct TopicFilter(String);

impl TopicFilter {
    /// Creates a new topic filter from string
    /// Return error if it is not a valid topic filter
    pub fn new<S: Into<String>>(topic: S) -> Result<TopicFilter, TopicFilterError> {
        let topic = topic.into();
        if is_invalid_topic_filter(&topic) {
            Err(TopicFilterError::InvalidTopicFilter(topic))
        } else {
            Ok(TopicFilter(topic))
        }
    }

    /// Creates a new topic filter from string without validation
    pub unsafe fn new_unchecked<S: Into<String>>(topic: S) -> TopicFilter {
        TopicFilter(topic.into())
    }
}

impl<'a> Encodable<'a> for TopicFilter {
    type Err = TopicFilterError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicFilterError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicFilterError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl<'a> Decodable<'a> for TopicFilter {
    type Err = TopicFilterError;
    type Cond = ();

    fn decode_with<R: Read>(reader: &mut R, _rest: Option<()>) -> Result<TopicFilter, TopicFilterError> {
        let topic_filter: String = try!(Decodable::decode(reader).map_err(TopicFilterError::StringEncodeError));
        TopicFilter::new(topic_filter)
    }
}

impl Deref for TopicFilter {
    type Target = TopicFilterRef;

    fn deref(&self) -> &TopicFilterRef {
        unsafe { TopicFilterRef::new_unchecked(&self.0) }
    }
}

/// Reference to a `TopicFilter`
#[derive(Debug, Eq, PartialEq)]
pub struct TopicFilterRef(str);

impl TopicFilterRef {
    /// Creates a new topic filter from string
    /// Return error if it is not a valid topic filter
    pub fn new<S: AsRef<str> + ?Sized>(topic: &S) -> Result<&TopicFilterRef, TopicFilterError> {
        let topic = topic.as_ref();
        if is_invalid_topic_filter(topic) {
            Err(TopicFilterError::InvalidTopicFilter(topic.to_owned()))
        } else {
            Ok(unsafe { mem::transmute(topic) })
        }
    }

    /// Creates a new topic filter from string without validation
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic: &S) -> &TopicFilterRef {
        mem::transmute(topic.as_ref())
    }

    /// Get a matcher
    pub fn get_matcher<'a>(&'a self) -> TopicFilterMatcher<'a> {
        TopicFilterMatcher::new(&self.0)
    }
}

impl Deref for TopicFilterRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

/// Errors while parsing topic filters
#[derive(Debug)]
pub enum TopicFilterError {
    StringEncodeError(StringEncodeError),
    InvalidTopicFilter(String),
}

impl fmt::Display for TopicFilterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => err.fmt(f),
            &TopicFilterError::InvalidTopicFilter(ref topic) => write!(f, "Invalid topic filter ({})", topic),
        }
    }
}

impl Error for TopicFilterError {
    fn description(&self) -> &str {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => err.description(),
            &TopicFilterError::InvalidTopicFilter(..) => "Invalid topic filter",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => Some(err),
            &TopicFilterError::InvalidTopicFilter(..) => None,
        }
    }
}

/// Matcher for matching topic names with this filter
#[derive(Debug, Copy, Clone)]
pub struct TopicFilterMatcher<'a> {
    topic_filter: &'a str,
}

impl<'a> TopicFilterMatcher<'a> {
    fn new(filter: &'a str) -> TopicFilterMatcher<'a> {
        TopicFilterMatcher { topic_filter: filter }
    }

    /// Check if this filter can match the `topic_name`
    pub fn is_match(&self, topic_name: &TopicNameRef) -> bool {
        let mut tn_itr = topic_name.split('/');
        let mut ft_itr = self.topic_filter.split('/');

        // The Server MUST NOT match Topic Filters starting with a wildcard character (# or +)
        // with Topic Names beginning with a $ character [MQTT-4.7.2-1].

        let first_ft = ft_itr.next().unwrap();
        let first_tn = tn_itr.next().unwrap();

        if first_tn.starts_with('$') {
            if first_tn != first_ft {
                return false;
            }
        } else {
            match first_ft {
                // Matches the whole topic
                "#" => return true,
                "+" => {}
                _ => {
                    if first_tn != first_ft {
                        return false;
                    }
                }
            }
        }

        loop {
            match (ft_itr.next(), tn_itr.next()) {
                (Some(ft), Some(tn)) => {
                    match ft {
                        "#" => break,
                        "+" => {}
                        _ => {
                            if ft != tn {
                                return false;
                            }
                        }
                    }
                }
                (Some(ft), None) => {
                    if ft != "#" {
                        return false;
                    } else {
                        break;
                    }
                }
                (None, Some(..)) => return false,
                (None, None) => break,
            }
        }

        return true;
    }
}

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

    #[test]
    fn topic_filter_validate() {
        let topic = "#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1/ranking".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis#".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "sport/tennis/#/ranking".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "+".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "+/tennis/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport+".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "sport/+/player1".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "+/+".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "$SYS/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "$SYS".to_owned();
        TopicFilter::new(topic).unwrap();
    }

    #[test]
    fn topic_filter_matcher() {
        let filter = TopicFilter::new("sport/#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("sport").unwrap()));

        let filter = TopicFilter::new("#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("sport").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("/").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("abc/def").unwrap()));
        assert!(!matcher.is_match(TopicNameRef::new("$SYS").unwrap()));
        assert!(!matcher.is_match(TopicNameRef::new("$SYS/abc").unwrap()));

        let filter = TopicFilter::new("+/monitor/Clients").unwrap();
        let matcher = filter.get_matcher();
        assert!(!matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));

        let filter = TopicFilter::new("$SYS/#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("$SYS").unwrap()));

        let filter = TopicFilter::new("$SYS/monitor/+").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));
    }
}
<commit_msg>Fix topic filter validation regex<commit_after>//! Topic filter

use std::io::{Read, Write};
use std::fmt;
use std::error::Error;
use std::ops::Deref;
use std::mem;
use std::convert::Into;

use regex::Regex;

use {Encodable, Decodable};
use encodable::StringEncodeError;
use topic_name::TopicNameRef;

const VALIDATE_TOPIC_FILTER_REGEX: &'static str = r"^(([^+#]*|\+)(/([^+#]*|\+))*(/#)?|#)$";

lazy_static! {
    static ref TOPIC_FILTER_VALIDATOR: Regex = Regex::new(VALIDATE_TOPIC_FILTER_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_filter(topic: &str) -> bool {
    topic.is_empty() || topic.as_bytes().len() > 65535 || !TOPIC_FILTER_VALIDATOR.is_match(&topic)
}

/// Topic filter
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
///
/// ```rust
/// use mqtt::{TopicFilter, TopicNameRef};
///
/// let topic_filter = TopicFilter::new("sport/+/player1").unwrap();
/// let matcher = topic_filter.get_matcher();
/// assert!(matcher.is_match(TopicNameRef::new("sport/abc/player1").unwrap()));
/// ```
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct TopicFilter(String);

impl TopicFilter {
    /// Creates a new topic filter from string
    /// Return error if it is not a valid topic filter
    pub fn new<S: Into<String>>(topic: S) -> Result<TopicFilter, TopicFilterError> {
        let topic = topic.into();
        if is_invalid_topic_filter(&topic) {
            Err(TopicFilterError::InvalidTopicFilter(topic))
        } else {
            Ok(TopicFilter(topic))
        }
    }

    /// Creates a new topic filter from string without validation
    pub unsafe fn new_unchecked<S: Into<String>>(topic: S) -> TopicFilter {
        TopicFilter(topic.into())
    }
}

impl<'a> Encodable<'a> for TopicFilter {
    type Err = TopicFilterError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicFilterError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicFilterError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl<'a> Decodable<'a> for TopicFilter {
    type Err = TopicFilterError;
    type Cond = ();

    fn decode_with<R: Read>(reader: &mut R, _rest: Option<()>) -> Result<TopicFilter, TopicFilterError> {
        let topic_filter: String = try!(Decodable::decode(reader).map_err(TopicFilterError::StringEncodeError));
        TopicFilter::new(topic_filter)
    }
}

impl Deref for TopicFilter {
    type Target = TopicFilterRef;

    fn deref(&self) -> &TopicFilterRef {
        unsafe { TopicFilterRef::new_unchecked(&self.0) }
    }
}

/// Reference to a `TopicFilter`
#[derive(Debug, Eq, PartialEq)]
pub struct TopicFilterRef(str);

impl TopicFilterRef {
    /// Creates a new topic filter from string
    /// Return error if it is not a valid topic filter
    pub fn new<S: AsRef<str> + ?Sized>(topic: &S) -> Result<&TopicFilterRef, TopicFilterError> {
        let topic = topic.as_ref();
        if is_invalid_topic_filter(topic) {
            Err(TopicFilterError::InvalidTopicFilter(topic.to_owned()))
        } else {
            Ok(unsafe { mem::transmute(topic) })
        }
    }

    /// Creates a new topic filter from string without validation
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic: &S) -> &TopicFilterRef {
        mem::transmute(topic.as_ref())
    }

    /// Get a matcher
    pub fn get_matcher<'a>(&'a self) -> TopicFilterMatcher<'a> {
        TopicFilterMatcher::new(&self.0)
    }
}

impl Deref for TopicFilterRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

/// Errors while parsing topic filters
#[derive(Debug)]
pub enum TopicFilterError {
    StringEncodeError(StringEncodeError),
    InvalidTopicFilter(String),
}

impl fmt::Display for TopicFilterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => err.fmt(f),
            &TopicFilterError::InvalidTopicFilter(ref topic) => write!(f, "Invalid topic filter ({})", topic),
        }
    }
}

impl Error for TopicFilterError {
    fn description(&self) -> &str {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => err.description(),
            &TopicFilterError::InvalidTopicFilter(..) => "Invalid topic filter",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &TopicFilterError::StringEncodeError(ref err) => Some(err),
            &TopicFilterError::InvalidTopicFilter(..) => None,
        }
    }
}

/// Matcher for matching topic names with this filter
#[derive(Debug, Copy, Clone)]
pub struct TopicFilterMatcher<'a> {
    topic_filter: &'a str,
}

impl<'a> TopicFilterMatcher<'a> {
    fn new(filter: &'a str) -> TopicFilterMatcher<'a> {
        TopicFilterMatcher { topic_filter: filter }
    }

    /// Check if this filter can match the `topic_name`
    pub fn is_match(&self, topic_name: &TopicNameRef) -> bool {
        let mut tn_itr = topic_name.split('/');
        let mut ft_itr = self.topic_filter.split('/');

        // The Server MUST NOT match Topic Filters starting with a wildcard character (# or +)
        // with Topic Names beginning with a $ character [MQTT-4.7.2-1].

        let first_ft = ft_itr.next().unwrap();
        let first_tn = tn_itr.next().unwrap();

        if first_tn.starts_with('$') {
            if first_tn != first_ft {
                return false;
            }
        } else {
            match first_ft {
                // Matches the whole topic
                "#" => return true,
                "+" => {}
                _ => {
                    if first_tn != first_ft {
                        return false;
                    }
                }
            }
        }

        loop {
            match (ft_itr.next(), tn_itr.next()) {
                (Some(ft), Some(tn)) => {
                    match ft {
                        "#" => break,
                        "+" => {}
                        _ => {
                            if ft != tn {
                                return false;
                            }
                        }
                    }
                }
                (Some(ft), None) => {
                    if ft != "#" {
                        return false;
                    } else {
                        break;
                    }
                }
                (None, Some(..)) => return false,
                (None, None) => break,
            }
        }

        return true;
    }
}

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

    #[test]
    fn topic_filter_validate() {
        let topic = "#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1/ranking".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/player1/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport/tennis#".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "sport/tennis/#/ranking".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "+".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "+/tennis/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "sport+".to_owned();
        assert!(TopicFilter::new(topic).is_err());

        let topic = "sport/+/player1".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "+/+".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "$SYS/#".to_owned();
        TopicFilter::new(topic).unwrap();

        let topic = "$SYS".to_owned();
        TopicFilter::new(topic).unwrap();
    }

    #[test]
    fn topic_filter_matcher() {
        let filter = TopicFilter::new("sport/#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("sport").unwrap()));

        let filter = TopicFilter::new("#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("sport").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("/").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("abc/def").unwrap()));
        assert!(!matcher.is_match(TopicNameRef::new("$SYS").unwrap()));
        assert!(!matcher.is_match(TopicNameRef::new("$SYS/abc").unwrap()));

        let filter = TopicFilter::new("+/monitor/Clients").unwrap();
        let matcher = filter.get_matcher();
        assert!(!matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));

        let filter = TopicFilter::new("$SYS/#").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));
        assert!(matcher.is_match(TopicNameRef::new("$SYS").unwrap()));

        let filter = TopicFilter::new("$SYS/monitor/+").unwrap();
        let matcher = filter.get_matcher();
        assert!(matcher.is_match(TopicNameRef::new("$SYS/monitor/Clients").unwrap()));
    }
}
<|endoftext|>


<commit_before>use emulator::Emulator;
use operand::Operand;
use instruction::Instruction;

pub type Operation = fn(&Instruction, &mut Emulator);

pub fn op_add(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let total = lhs + rhs;
    core.vf_store(total > 0xFF);  //set vF if result overflows
    core.store(inst.dest(), total);
}

/// Subtract src from dest, store in dest. Set flag if NOT borrow
pub fn op_sub(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest()) as i32;
    let rhs = core.load(inst.src()) as i32;
    let total = ((lhs - rhs) as u32) & 0xFF;

    core.vf_store(lhs > rhs);  //set vF if NOT borrow
    core.store(inst.dest(), total);
}

/// Subtract dest from src, store in dest. Set flag if NOT borrow
pub fn op_subn(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.src()) as i32;
    let rhs = core.load(inst.dest()) as i32;
    let total = ((lhs - rhs) as u32) & 0xFF;

    core.vf_store(lhs > rhs);  //set vF if NOT borrow
    core.store(inst.dest(), total);
}

pub fn op_or(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs | rhs;
    core.store(inst.dest(), result);
}

pub fn op_and(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs & rhs;
    core.store(inst.dest(), result);
}

pub fn op_xor(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs ^ rhs;
    core.store(inst.dest(), result);
}

/// Shifts the source right 1 bit, and stores in dest. vF set to old LSB
pub fn op_shr(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let carry = (val & 1) == 1;
    let result = val >> 1;
    core.store(inst.dest(), result);
    core.vf_store(carry);
}

/// Shifts the source left 1 bit, and stores in dest. vF set to old MSB
pub fn op_shl(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let carry = (val & 0x80) == 0x80;
    let result = (val << 1) & 0xFF;
    core.store(inst.dest(), result);
    core.vf_store(carry);
}

pub fn op_load(inst: &Instruction, core: &mut Emulator) {
    let data = core.load(inst.src());
    core.store(inst.dest(), data);
}

pub fn op_font(inst: &Instruction, core: &mut Emulator) {
    let addr = core.config.font_addr as u32 + core.load(inst.src()) * 5;
    core.store(inst.dest(), addr);
}

pub fn op_bcd(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let hundreds = val / 100;
    let val = val - hundreds * 100;
    let tens = val / 10;
    let ones = val - tens * 10;

    assert!(hundreds < 10);
    assert!(tens < 10);
    assert!(ones < 10);

    let inital_i = core.i();      //store I so it can be restored
    core.store(inst.dest(), hundreds);
    core.set_i(inital_i + 1);
    core.store(inst.dest(), tens);
    core.set_i(inital_i + 2);
    core.store(inst.dest(), ones);
    core.set_i(inital_i);
}

pub fn op_rand(inst: &Instruction, core: &mut Emulator) {
    let mask = core.load(inst.src());
    let data = core.rng.next_u32() & mask;
    core.store(inst.dest(), data);
}

pub fn op_skipeq(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    if lhs == rhs {
        core.advance_pc();
    }
}

pub fn op_skipneq(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    if lhs != rhs {
        core.advance_pc();
    }
}

pub fn op_skipkey(inst: &Instruction, core: &mut Emulator) {
    let key = core.load(inst.dest()) as usize;
    let mut key_state = false;
    {
        let keys = core.state.keys.read().unwrap();
        key_state = keys.is_down(key);
    }
    if key_state {
        core.advance_pc();
    }
}

pub fn op_skipnkey(inst: &Instruction, core: &mut Emulator) {
    let key = core.load(inst.dest()) as usize;
    let mut key_state = false;
    {
        let keys = core.state.keys.read().unwrap();
        key_state = keys.is_down(key);
    }
    if !key_state {
        core.advance_pc();
    }
}

#[allow(unused_variables)]
pub fn op_waitkey(inst: &Instruction, core: &mut Emulator) {
    panic!("WaitKey Unimplemented")
}

/// Jump to address
pub fn op_jump(inst: &Instruction, core: &mut Emulator) {
    let addr = core.load(inst.dest()) as usize;
    core.jump_pc(addr);
}

/// Jump to address + V0
pub fn op_jumpv0(inst: &Instruction, core: &mut Emulator) {
    let mut addr = core.load(inst.dest()) as usize;
    addr += core.reg(0) as usize;
    core.jump_pc(addr);
}

pub fn op_call(inst: &Instruction, core: &mut Emulator) {
    let addr = core.load(inst.dest()) as usize;
    let pc = core.pc();
    core.stack.push(pc);
    core.jump_pc(addr);
}

#[allow(unused_variables)]
pub fn op_ret(inst: &Instruction, core: &mut Emulator) {
    let addr = core.stack.pop().unwrap();
    core.jump_pc(addr);
}

#[allow(unused_variables)]
pub fn op_cls(inst: &Instruction, core: &mut Emulator) {
    let mut vram = core.state.vram.write().unwrap();

    vram.pixels = [[0; 32]; 64];
}

pub fn op_sprite(inst: &Instruction, core: &mut Emulator) {

    let x = core.load(inst.dest());
    let mut y = core.load(inst.src());
    let n = core.load(inst.aux());

    let mut i = core.i();

    let mut pixels = core.state.vram.read().unwrap().pixels;

    // println!("sprite: x{} y{} n{} i{:X}", x, y, n, i );
    core.vf_clear();
    for _ in 0..n {
        let byte = core.ram(i);
        for bit in 0..8 {
            let pixel = if byte & (0x80 >> bit) == 0 {
                0
            } else {
                1
            };
            let x_loc = ((x + bit) & 63) as usize;
            let y_loc = (y & 31) as usize;
            pixels[x_loc][y_loc] ^= pixel;
            if pixels[x_loc][y_loc] == 0 && pixel == 1 {
                core.vf_set();
            }
        }
        i += 1;
        y += 1;
    }

    let mut vram = core.state.vram.write().unwrap();
    vram.pixels = pixels;

}

pub fn op_stash(inst: &Instruction, core: &mut Emulator) {
    let last = match inst.src() {
        Operand::Register(r) => r,
        _ => {
            panic!("Fetch only works with a register");
        }
    };
    let i = core.i();
    for r in 0...last {
        let value = core.reg(r) as u8;
        core.set_ram(i + r, value);
    }
    core.set_i(i + last + 1);
}

pub fn op_fetch(inst: &Instruction, core: &mut Emulator) {
    let last = match inst.dest() {
        Operand::Register(r) => r,
        _ => {
            panic!("Fetch only works with a register");
        }
    };
    let i = core.i();
    for r in 0...last {
        let v = core.ram(i + r);
        core.set_reg(r, v);
    }
    core.set_i(i + last + 1);
}
<commit_msg>Minor cleanups<commit_after>use emulator::Emulator;
use operand::Operand;
use instruction::Instruction;

pub type Operation = fn(&Instruction, &mut Emulator);

pub fn op_add(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let total = lhs + rhs;
    core.vf_store(total > 0xFF);  //set vF if result overflows
    core.store(inst.dest(), total);
}

/// Subtract src from dest, store in dest. Set flag if NOT borrow
pub fn op_sub(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest()) as i32;
    let rhs = core.load(inst.src()) as i32;
    let total = ((lhs - rhs) as u32) & 0xFF;

    core.vf_store(lhs > rhs);  //set vF if NOT borrow
    core.store(inst.dest(), total);
}

/// Subtract dest from src, store in dest. Set flag if NOT borrow
pub fn op_subn(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.src()) as i32;
    let rhs = core.load(inst.dest()) as i32;
    let total = ((lhs - rhs) as u32) & 0xFF;

    core.vf_store(lhs > rhs);  //set vF if NOT borrow
    core.store(inst.dest(), total);
}

pub fn op_or(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs | rhs;
    core.store(inst.dest(), result);
}

pub fn op_and(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs & rhs;
    core.store(inst.dest(), result);
}

pub fn op_xor(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    let result = lhs ^ rhs;
    core.store(inst.dest(), result);
}

/// Shifts the source right 1 bit, and stores in dest. vF set to old LSB
pub fn op_shr(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let carry = (val & 1) == 1;
    let result = val >> 1;
    core.store(inst.dest(), result);
    core.vf_store(carry);
}

/// Shifts the source left 1 bit, and stores in dest. vF set to old MSB
pub fn op_shl(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let carry = (val & 0x80) == 0x80;
    let result = (val << 1) & 0xFF;
    core.store(inst.dest(), result);
    core.vf_store(carry);
}

pub fn op_load(inst: &Instruction, core: &mut Emulator) {
    let data = core.load(inst.src());
    core.store(inst.dest(), data);
}

pub fn op_font(inst: &Instruction, core: &mut Emulator) {
    let addr = core.config.font_addr as u32 + core.load(inst.src()) * 5;
    core.store(inst.dest(), addr);
}

pub fn op_bcd(inst: &Instruction, core: &mut Emulator) {
    let val = core.load(inst.src());
    let hundreds = val / 100;
    let val = val - hundreds * 100;
    let tens = val / 10;
    let ones = val - tens * 10;

    assert!(hundreds < 10);
    assert!(tens < 10);
    assert!(ones < 10);

    let inital_i = core.i();      //store I so it can be restored
    core.store(inst.dest(), hundreds);
    core.set_i(inital_i + 1);
    core.store(inst.dest(), tens);
    core.set_i(inital_i + 2);
    core.store(inst.dest(), ones);
    core.set_i(inital_i);
}

pub fn op_rand(inst: &Instruction, core: &mut Emulator) {
    let mask = core.load(inst.src());
    let data = core.rng.next_u32() & mask;
    core.store(inst.dest(), data);
}

pub fn op_skipeq(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    if lhs == rhs {
        core.advance_pc();
    }
}

pub fn op_skipneq(inst: &Instruction, core: &mut Emulator) {
    let lhs = core.load(inst.dest());
    let rhs = core.load(inst.src());
    if lhs != rhs {
        core.advance_pc();
    }
}

pub fn op_skipkey(inst: &Instruction, core: &mut Emulator) {
    let key = core.load(inst.dest()) as usize;
    let key_state: bool;
    {
        let keys = core.state.keys.read().unwrap();
        key_state = keys.is_down(key);
    }
    if key_state {
        core.advance_pc();
    }
}

pub fn op_skipnkey(inst: &Instruction, core: &mut Emulator) {
    let key = core.load(inst.dest()) as usize;
    let key_state: bool;
    {
        let keys = core.state.keys.read().unwrap();
        key_state = keys.is_down(key);
    }
    if !key_state {
        core.advance_pc();
    }
}

#[allow(unused_variables)]
pub fn op_waitkey(inst: &Instruction, core: &mut Emulator) {
    panic!("WaitKey Unimplemented")
}

/// Jump to address
pub fn op_jump(inst: &Instruction, core: &mut Emulator) {
    let addr = core.load(inst.dest()) as usize;
    core.jump_pc(addr);
}

/// Jump to address + V0
pub fn op_jumpv0(inst: &Instruction, core: &mut Emulator) {
    let mut addr = core.load(inst.dest()) as usize;
    addr += core.reg(0) as usize;
    core.jump_pc(addr);
}

pub fn op_call(inst: &Instruction, core: &mut Emulator) {
    let addr = core.load(inst.dest()) as usize;
    let pc = core.pc();
    core.stack.push(pc);
    core.jump_pc(addr);
}

#[allow(unused_variables)]
pub fn op_ret(inst: &Instruction, core: &mut Emulator) {
    let addr = core.stack.pop().unwrap();
    core.jump_pc(addr);
}

#[allow(unused_variables)]
pub fn op_cls(inst: &Instruction, core: &mut Emulator) {
    let mut vram = core.state.vram.write().unwrap();

    vram.pixels = [[0; 32]; 64];
}

pub fn op_sprite(inst: &Instruction, core: &mut Emulator) {

    let x = core.load(inst.dest());
    let mut y = core.load(inst.src());
    let n = core.load(inst.aux());

    let mut i = core.i();

    let mut pixels = core.state.vram.read().unwrap().pixels;

    // println!("sprite: x{} y{} n{} i{:X}", x, y, n, i );
    core.vf_clear();
    for _ in 0..n {
        let byte = core.ram(i);
        for bit in 0..8 {
            let pixel = if byte & (0x80 >> bit) == 0 {
                0
            } else {
                1
            };
            let x_loc = ((x + bit) & 63) as usize;
            let y_loc = (y & 31) as usize;
            pixels[x_loc][y_loc] ^= pixel;
            if pixels[x_loc][y_loc] == 0 && pixel == 1 {
                core.vf_set();
            }
        }
        i += 1;
        y += 1;
    }

    let mut vram = core.state.vram.write().unwrap();
    vram.pixels = pixels;

}

pub fn op_stash(inst: &Instruction, core: &mut Emulator) {
    let last = match inst.src() {
        Operand::Register(r) => r,
        _ => {
            panic!("Fetch only works with a register");
        }
    };
    let i = core.i();
    for r in 0...last {
        let value = core.reg(r) as u8;
        core.set_ram(i + r, value);
    }
    core.set_i(i + last + 1);
}

pub fn op_fetch(inst: &Instruction, core: &mut Emulator) {
    let last = match inst.dest() {
        Operand::Register(r) => r,
        _ => {
            panic!("Fetch only works with a register");
        }
    };
    let i = core.i();
    for r in 0...last {
        let v = core.ram(i + r);
        core.set_reg(r, v);
    }
    core.set_i(i + last + 1);
}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin)]
#![plugin(tojson_macros)]

extern crate iron;
extern crate handlebars_iron as hbs;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::{status};
use hbs::{Template, HandlebarsEngine, Watchable};
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use std::sync::Arc;

#[derive(ToJson)]
struct Team {
    name: String,
    pts: u16
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let teams = vec![ Team { name: "Jiangsu Sainty".to_string(),
                             pts: 43u16 },
                      Team { name: "Beijing Guoan".to_string(),
                             pts: 27u16 },
                      Team { name: "Guangzhou Evergrand".to_string(),
                             pts: 22u16 },
                      Team { name: "Shandong Luneng".to_string(),
                             pts: 12u16 } ];

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let mut resp = Response::new();

    let data = make_data();
    resp.set_mut(Template::new("index", data)).set_mut(status::Ok);
    Ok(resp)
}

fn main() {
    let mut chain = Chain::new(hello_world);
    let template_engine_ref = Arc::new(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    template_engine_ref.watch();

    chain.link_after(template_engine_ref);

    println!("Server running at http://localhost:3000/");
    Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>(fix) remove tojson_macro in watch_server example<commit_after>extern crate iron;
extern crate handlebars_iron as hbs;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::{status};
use hbs::{Template, HandlebarsEngine, Watchable};
use rustc_serialize::json::{ToJson, Json};
use std::collections::BTreeMap;
use std::sync::Arc;

struct Team {
    name: String,
    pts: u16
}

impl ToJson for Team {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("name".to_string(), self.name.to_json());
        m.insert("pts".to_string(), self.pts.to_json());
        m.to_json()
    }
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let teams = vec![ Team { name: "Jiangsu Sainty".to_string(),
                             pts: 43u16 },
                      Team { name: "Beijing Guoan".to_string(),
                             pts: 27u16 },
                      Team { name: "Guangzhou Evergrand".to_string(),
                             pts: 22u16 },
                      Team { name: "Shandong Luneng".to_string(),
                             pts: 12u16 } ];

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let mut resp = Response::new();

    let data = make_data();
    resp.set_mut(Template::new("index", data)).set_mut(status::Ok);
    Ok(resp)
}

fn main() {
    let mut chain = Chain::new(hello_world);
    let template_engine_ref = Arc::new(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    template_engine_ref.watch();

    chain.link_after(template_engine_ref);

    println!("Server running at http://localhost:3000/");
    Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ActionHandlers;
use super::{config, Context, Dispatcher, Event, Message, MiliSec, Response, Request, Timer};

const TIMER_STEP: MiliSec = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Request>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    exits_received: u32
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            for i in contexts.into_iter() {
                let context: context::Context = i.into();
                let event_handler: Box<context::EventHandler<Event>> = context.into();
            }

            //let mut dispatcher = Dispatcher::new(contexts, dispatcher_output_channel_tx);
            //dispatcher.start_loop(rx);
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            exits_received: 0
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request>> {
        self.consume_results();
        self.dispatcher_input_channel.send(Request::Event(Event::Message(message)))
    }

    fn consume_results(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            if let Response::Event(result) = i {
                self.action_handlers.handle(result);
            }
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.consume_results();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        let _ = self.wait_for_dispatcher_to_exit();
    }

    fn wait_for_dispatcher_to_exit(&mut self) -> Result<(), ()> {
        loop {
            let value = self.dispatcher_output_channel.recv();
            match value {
                Ok(value) => {
                    try!(self.handle_command(value))
                },
                _ => {}
            }
        }
    }

    fn handle_command(&mut self, command: Response) -> Result<(), ()> {
        match command {
            Response::Event(result) => self.action_handlers.handle(result),
            Response::Exit => {
                if self.handle_exit_command() {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_exit_command(&mut self) -> bool {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        self.exits_received += 1;
        self.exits_received >= 1
    }
}
<commit_msg>correlator: remove uncompiling code<commit_after>use std::sync::mpsc;
use std::thread;
use std::result::Result;

use action::ActionHandlers;
use super::{config, Context, Dispatcher, Event, Message, MiliSec, Response, Request, Timer};

const TIMER_STEP: MiliSec = 100;

pub struct Correlator {
    action_handlers: ActionHandlers,
    dispatcher_input_channel: mpsc::Sender<Request>,
    dispatcher_output_channel: mpsc::Receiver<Response>,
    dispatcher_thread_handle: thread::JoinHandle<()>,
    exits_received: u32
}

impl Correlator {
    pub fn new(contexts: Vec<config::Context>, action_handlers: ActionHandlers) -> Correlator {
        let (dispatcher_input_channel, rx) = mpsc::channel();
        let (dispatcher_output_channel_tx, dispatcher_output_channel_rx) = mpsc::channel();
        let _ = Timer::from_chan(TIMER_STEP, dispatcher_input_channel.clone());

        let handle = thread::spawn(move || {
            for i in contexts.into_iter() {
                //let context: context::Context = i.into();
                //let event_handler: Box<context::EventHandler<Event>> = context.into();
            }

            //let mut dispatcher = Dispatcher::new(contexts, dispatcher_output_channel_tx);
            //dispatcher.start_loop(rx);
        });

        Correlator {
            action_handlers: action_handlers,
            dispatcher_input_channel: dispatcher_input_channel,
            dispatcher_output_channel: dispatcher_output_channel_rx,
            dispatcher_thread_handle: handle,
            exits_received: 0
        }
    }

    pub fn push_message(&mut self, message: Message) -> Result<(), mpsc::SendError<Request>> {
        self.consume_results();
        self.dispatcher_input_channel.send(Request::Event(Event::Message(message)))
    }

    fn consume_results(&mut self) {
        for i in self.dispatcher_output_channel.try_recv() {
            if let Response::Event(result) = i {
                self.action_handlers.handle(result);
            }
        }
    }

    pub fn stop(mut self) -> thread::Result<()> {
        self.consume_results();
        self.stop_dispatcher();
        self.dispatcher_thread_handle.join()
    }

    fn stop_dispatcher(&mut self) {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        let _ = self.wait_for_dispatcher_to_exit();
    }

    fn wait_for_dispatcher_to_exit(&mut self) -> Result<(), ()> {
        loop {
            let value = self.dispatcher_output_channel.recv();
            match value {
                Ok(value) => {
                    try!(self.handle_command(value))
                },
                _ => {}
            }
        }
    }

    fn handle_command(&mut self, command: Response) -> Result<(), ()> {
        match command {
            Response::Event(result) => self.action_handlers.handle(result),
            Response::Exit => {
                if self.handle_exit_command() {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_exit_command(&mut self) -> bool {
        let _ = self.dispatcher_input_channel.send(Request::Exit);
        self.exits_received += 1;
        self.exits_received >= 1
    }
}
<|endoftext|>


<commit_before>use std::str;
use rustc_serialize::hex::FromHex;
use std::path::PathBuf;

use rex_utils;
use rex_utils::rect::Rect;
use super::super::frontend::{Frontend, Style, KeyPress};
use super::input::Input;
use super::widget::Widget;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLineBehavior {
    fn get_prefix(&self) -> &str;
    fn get_status(&self) -> Result<&str, &str> {
        Ok("")
    }
    fn do_update(&mut self, data: &[u8]) {

    }
    fn do_enter(&mut self, data: &[u8]);
    fn do_cancel(&mut self);
    fn do_shortcut(&mut self, shortcut: char) {

    }
}

pub struct InputLine<T:InputLineBehavior> {
    behavior: T,
    data: Vec<u8>,
    input_pos: isize,
}

impl<T:InputLineBehavior> InputLine<T> {
    pub fn new(behavior: T) -> InputLine<T> {
        InputLine {
            behavior: behavior,
            data: vec![],
            input_pos: 0,
        }
    }
}

impl<T:InputLineBehavior> Widget for InputLine<T> {
    fn input(&mut self, input: &Input, key: KeyPress) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.behavior.do_enter(&self.data)
            }
            BaseInputLineActions::Cancel => {
                self.behavior.do_cancel()
            }
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: Make it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::Ctrl(ch) => {
                self.behavior.do_shortcut(ch)
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                    self.behavior.do_update(&self.data);
                }
            }
        };

        self.behavior.do_update(&self.data);

        return true;
    }

    fn draw(&mut self, rb: &mut Frontend, area: Rect<isize>, has_focus: bool) {
        let prefix = self.behavior.get_prefix();

        let (style, status_msg) = match self.behavior.get_status() {
            Ok(sm) => (Style::InputLine, sm),
            Err(sm) => (Style::InputLineError, sm),
        };

        let (x_pos, start_index) = if area.width >= status_msg.len() as isize {
            (area.width - status_msg.len() as isize, 0)
        } else {
            (0, area.width - status_msg.len() as isize)
        };

        rb.print_style(area.left as usize, area.top as usize, style,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(x_pos as usize, area.top as usize, style,
              &status_msg[start_index as usize..]);
        rb.print_style(area.left as usize, area.top as usize, style,
                 &format!("{}{} ", prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLineBehavior {
    radix: RadixType,
    is_valid: bool,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLineBehavior {
    pub fn new() -> GotoInputLineBehavior {
        GotoInputLineBehavior {
            radix: RadixType::DecRadix,
            is_valid: true,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
    }

    fn get_pos(&mut self, data: &[u8]) -> Option<isize> {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        match str::from_utf8(&data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        }
    }

    fn do_goto(&mut self, data: &[u8]) {
        match self.get_pos(data) {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };
    }
}

impl InputLineBehavior for GotoInputLineBehavior {
    fn get_prefix(&self) -> &str {
        match self.radix {
            RadixType::DecRadix => "Goto (Dec):",
            RadixType::HexRadix => "Goto (Hex):",
            RadixType::OctRadix => "Goto (Oct):",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid position")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = self.get_pos(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        if self.is_valid {
            self.do_goto(data);
        }
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'd' => {
                self.set_radix(RadixType::DecRadix);
            }
            'h' => {
                self.set_radix(RadixType::HexRadix);
            }
            'o' => {
                self.set_radix(RadixType::OctRadix);
            }
            _ => ()
        }
    }
}

enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    data_type: DataType,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            data_type: DataType::AsciiStr,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
    }

    fn do_find(&mut self, data: &[u8]) {
        let ll = str::from_utf8(data).unwrap().from_hex();

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => data.clone().into(),
            DataType::UnicodeStr => data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Ok(n) => n,
                    Err(_) => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLineBehavior for FindInputLine {
    fn get_prefix(&self) -> &str {
        match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ",
            DataType::UnicodeStr => "Find(Uni): ",
            DataType::HexStr => "Find(Hex): ",
        }
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.do_find(data);
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'a' => {
                self.set_search_data_type(DataType::AsciiStr);
            }
            'u' => {
                self.set_search_data_type(DataType::UnicodeStr);
            }
            'h' => {
                self.set_search_data_type(DataType::HexStr);
            }
            _ => ()
        }
    }
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine {
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl PathInputLine {
    pub fn new(prefix: String) -> PathInputLine {
        PathInputLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default()
        }
    }
}

impl InputLineBehavior for PathInputLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(PathBuf::from(str::from_utf8(data).unwrap()));
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}

signal_decl!{ConfigSetEvent(String)}

pub struct ConfigSetLine {
    pub on_done: ConfigSetEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl ConfigSetLine {
    pub fn new(prefix: String) -> ConfigSetLine {
        ConfigSetLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }
}

impl InputLineBehavior for ConfigSetLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(str::from_utf8(&data).unwrap().to_owned());
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}
<commit_msg>Add error status to Find input line<commit_after>use std::str;
use std::env;
use std::io;
use std::fs;
use rustc_serialize::hex::FromHex;
use std::path::{PathBuf, Path};

use rex_utils;
use rex_utils::rect::Rect;
use super::super::frontend::{Frontend, Style, KeyPress};
use super::input::Input;
use super::widget::Widget;

use super::common::Canceled;

pub enum BaseInputLineActions {
    Edit(char),
    Ctrl(char),
    MoveLeft,
    MoveRight,
    DeleteWithMove,
    Ok,
    Cancel
}

pub trait InputLineBehavior {
    fn get_prefix(&self) -> &str;
    fn get_status(&self) -> Result<&str, &str> {
        Ok("")
    }
    fn do_update(&mut self, data: &[u8]) {

    }
    fn do_enter(&mut self, data: &[u8]);
    fn do_cancel(&mut self);
    fn do_shortcut(&mut self, shortcut: char) {

    }
}

pub struct InputLine<T:InputLineBehavior> {
    behavior: T,
    data: Vec<u8>,
    input_pos: isize,
}

impl<T:InputLineBehavior> InputLine<T> {
    pub fn new(behavior: T) -> InputLine<T> {
        InputLine {
            behavior: behavior,
            data: vec![],
            input_pos: 0,
        }
    }
}

impl<T:InputLineBehavior> Widget for InputLine<T> {
    fn input(&mut self, input: &Input, key: KeyPress) -> bool {
        let action = if let Some(action) = input.inputline_input(key) { action } else {
            return false;
        };

        match action {
            BaseInputLineActions::Ok => {
                self.behavior.do_enter(&self.data)
            }
            BaseInputLineActions::Cancel => {
                self.behavior.do_cancel()
            }
            BaseInputLineActions::MoveLeft => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                }
            }
            BaseInputLineActions::MoveRight => {
                if self.input_pos < self.data.len() as isize {
                    self.input_pos += 1;
                }
            }
            BaseInputLineActions::Edit(ch) => {
                if ch.len_utf8() == 1 {
                    self.data.insert(self.input_pos as usize, ch as u8);
                    self.input_pos += 1;
                } else {
                    // TODO: Make it printable rather than alphanumeric
                }
            }
            BaseInputLineActions::Ctrl(ch) => {
                self.behavior.do_shortcut(ch)
            }
            BaseInputLineActions::DeleteWithMove => {
                if self.input_pos > 0 {
                    self.input_pos -= 1;
                    self.data.remove(self.input_pos as usize);
                    self.behavior.do_update(&self.data);
                }
            }
        };

        self.behavior.do_update(&self.data);

        return true;
    }

    fn draw(&mut self, rb: &mut Frontend, area: Rect<isize>, has_focus: bool) {
        let prefix = self.behavior.get_prefix();

        let (style, status_msg) = match self.behavior.get_status() {
            Ok(sm) => (Style::InputLine, sm),
            Err(sm) => (Style::InputLineError, sm),
        };

        let (x_pos, start_index) = if area.width >= status_msg.len() as isize {
            (area.width - status_msg.len() as isize, 0)
        } else {
            (0, area.width - status_msg.len() as isize)
        };

        rb.print_style(area.left as usize, area.top as usize, style,
                 &rex_utils::string_with_repeat(' ', area.width as usize));
        rb.print_style(x_pos as usize, area.top as usize, style,
              &status_msg[start_index as usize..]);
        rb.print_style(area.left as usize, area.top as usize, style,
                 &format!("{}{} ", prefix, str::from_utf8(&self.data).unwrap()));
        if has_focus {
            rb.set_cursor(prefix.len() as isize + self.input_pos, (area.top as isize));
        }
    }
}

enum RadixType {
    DecRadix,
    HexRadix,
    OctRadix,
}

signal_decl!{GotoEvent(isize)}

pub struct GotoInputLineBehavior {
    radix: RadixType,
    is_valid: bool,
    pub on_done: GotoEvent,
    pub on_cancel: Canceled,
}

impl GotoInputLineBehavior {
    pub fn new() -> GotoInputLineBehavior {
        GotoInputLineBehavior {
            radix: RadixType::DecRadix,
            is_valid: true,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_radix(&mut self, r: RadixType) {
        self.radix = r;
    }

    fn get_pos(&mut self, data: &[u8]) -> Option<isize> {
        let radix = match self.radix {
            RadixType::DecRadix => 10,
            RadixType::HexRadix => 16,
            RadixType::OctRadix => 8,
        };

        match str::from_utf8(&data) {
            Ok(gs) => isize::from_str_radix(&gs, radix).ok(),
            Err(_) => None
        }
    }

    fn do_goto(&mut self, data: &[u8]) {
        match self.get_pos(data) {
            Some(pos) => {
                self.on_done.signal(pos)
            }
            None => {
                self.on_cancel.signal(Some(format!("Bad position!")));
            }
        };
    }
}

impl InputLineBehavior for GotoInputLineBehavior {
    fn get_prefix(&self) -> &str {
        match self.radix {
            RadixType::DecRadix => "Goto (Dec):",
            RadixType::HexRadix => "Goto (Hex):",
            RadixType::OctRadix => "Goto (Oct):",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid position")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = self.get_pos(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        if self.is_valid {
            self.do_goto(data);
        }
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'd' => {
                self.set_radix(RadixType::DecRadix);
            }
            'h' => {
                self.set_radix(RadixType::HexRadix);
            }
            'o' => {
                self.set_radix(RadixType::OctRadix);
            }
            _ => ()
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum DataType {
    AsciiStr,
    UnicodeStr,
    HexStr,
}

signal_decl!{FindEvent(Vec<u8>)}

pub struct FindInputLine {
    data_type: DataType,
    is_valid: bool,
    pub on_find: FindEvent,
    pub on_cancel: Canceled,
}

impl FindInputLine {
    pub fn new() -> FindInputLine {
        FindInputLine {
            data_type: DataType::AsciiStr,
            is_valid: true,
            on_find: Default::default(),
            on_cancel: Default::default(),
        }
    }

    fn set_search_data_type(&mut self, dt: DataType) {
        self.data_type = dt;
    }

    fn parse_hex(&self, data: &[u8]) -> Option<Vec<u8>> {
        str::from_utf8(data).unwrap().from_hex().ok()
    }

    fn do_find(&mut self, data: &[u8]) {
        let ll = self.parse_hex(data);

        let needle: Vec<u8> = match self.data_type {
            DataType::AsciiStr => data.clone().into(),
            DataType::UnicodeStr => data.clone().into(),
            DataType::HexStr => {
                match ll {
                    Some(n) => n,
                    None => {
                        self.on_cancel.signal(Some(format!("Bad hex value")));
                        return;
                    }
                }
            }
        };

        self.on_find.signal(needle);
    }
}

impl InputLineBehavior for FindInputLine {
    fn get_prefix(&self) -> &str {
        match self.data_type {
            DataType::AsciiStr => "Find(Ascii): ",
            DataType::UnicodeStr => "Find(Uni): ",
            DataType::HexStr => "Find(Hex): ",
        }
    }

    fn get_status(&self) -> Result<&str, &str> {
        if self.is_valid {
            Ok("")
        } else {
            Err("Invalid Hex Value")
        }
    }

    fn do_update(&mut self, data: &[u8]) {
        self.is_valid = (self.data_type != DataType::HexStr) || self.parse_hex(data).is_some();
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.do_find(data);
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }

    fn do_shortcut(&mut self, shortcut: char) {
        match shortcut {
            'a' => {
                self.set_search_data_type(DataType::AsciiStr);
            }
            'u' => {
                self.set_search_data_type(DataType::UnicodeStr);
            }
            'h' => {
                self.set_search_data_type(DataType::HexStr);
            }
            _ => ()
        }
    }
}

signal_decl!{PathEvent(PathBuf)}

pub struct PathInputLine {
    pub on_done: PathEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl PathInputLine {
    pub fn new(prefix: String) -> PathInputLine {
        PathInputLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default()
        }
    }
}

impl InputLineBehavior for PathInputLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(PathBuf::from(str::from_utf8(data).unwrap()));
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}

signal_decl!{ConfigSetEvent(String)}

pub struct ConfigSetLine {
    pub on_done: ConfigSetEvent,
    pub on_cancel: Canceled,
    prefix: String,
}

impl ConfigSetLine {
    pub fn new(prefix: String) -> ConfigSetLine {
        ConfigSetLine {
            prefix: prefix,
            on_done: Default::default(),
            on_cancel: Default::default(),
        }
    }
}

impl InputLineBehavior for ConfigSetLine {
    fn get_prefix(&self) -> &str {
        &self.prefix
    }

    fn do_enter(&mut self, data: &[u8]) {
        self.on_done.signal(str::from_utf8(&data).unwrap().to_owned());
    }

    fn do_cancel(&mut self) {
        self.on_cancel.signal(None);
    }
}
<|endoftext|>


<commit_before>use crate::relocations::{Relocation, RelocationSize, RelocationKind, ImpossibleRelocation, fits_signed_bitfield};
use byteorder::{ByteOrder, LittleEndian};
use std::convert::TryFrom;

/// Relocation implementation for the aarch64 architecture.
#[derive(Debug, Clone)]
pub enum Aarch64Relocation {
    // b, bl 26 bits, dword aligned
    B,
    // b.cond, cbnz, cbz, ldr, ldrsw, prfm: 19 bits, dword aligned
    BCOND,
    // adr split 21 bit, byte aligned
    ADR,
    // adrp split 21 bit, 4096-byte aligned
    ADRP,
    // tbnz, tbz: 14 bits, dword aligned
    TBZ,
    // Anything in directives
    Plain(RelocationSize),
}

impl Aarch64Relocation {
    fn op_mask(&self) -> u32 {
        match self {
            Self::B => 0xFC00_0000,
            Self::BCOND => 0xFF00_001F,
            Self::ADR => 0x9F00_001F,
            Self::ADRP => 0x9F00_001F,
            Self::TBZ => 0xFFF8_001F,
            Self::Plain(_) => 0
        }
    }

    fn encode(&self, value: isize) -> Result<u32, ImpossibleRelocation> {
        let value = i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?;
        Ok(match self {
            Self::B => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 26) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x3FF_FFFF) << 5
            },
            Self::BCOND => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 19) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x7FFFF) << 5
            },
            Self::ADR => {
                if !fits_signed_bitfield(value, 21) {
                    return Err(ImpossibleRelocation { } );
                }
                let low = (value) as u32;
                let high = (value >> 2) as u32;
                ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
            },
            Self::ADRP => {
                if value & 0xFFF != 0 || !fits_signed_bitfield(value >> 12, 21) {
                    return Err(ImpossibleRelocation { } );
                }
                let low = (value >> 12) as u32;
                let high = (value >> 14) as u32;
                ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
            },
            Self::TBZ => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 14) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x3FFF) << 5
            },
            Self::Plain(_) => return Err(ImpossibleRelocation { } )
        })
    }
}

impl Relocation for Aarch64Relocation {
    type Encoding = (u8,);
    fn from_encoding(encoding: Self::Encoding) -> Self {
        match encoding.0 {
            0 => Self::B,
            1 => Self::BCOND,
            2 => Self::ADR,
            3 => Self::ADRP,
            4 => Self::TBZ,
            x  => Self::Plain(RelocationSize::from_encoding(x - 4))
        }
    }
    fn from_size(size: RelocationSize) -> Self {
        Self::Plain(size)
    }
    fn size(&self) -> usize {
        match self {
            Self::Plain(s) => s.size(),
            _ => RelocationSize::DWord.size(),
        }
    }
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
        if let Self::Plain(s) = self {
            return s.write_value(buf, value);
        };

        let mask = self.op_mask();
        let template = LittleEndian::read_u32(buf) & mask;

        let packed = self.encode(value)?;

        LittleEndian::write_u32(buf, template | packed);
        Ok(())
    }
    fn read_value(&self, buf: &[u8]) -> isize {
        if let Self::Plain(s) = self {
            return s.read_value(buf);
        };

        let mask = !self.op_mask();
        let value = LittleEndian::read_u32(buf);
        let unpacked = match self {
            Self::B => u64::from(
                value & mask
            ) << 2,
            Self::BCOND => u64::from(
                (value & mask) >> 5
            ) << 2,
            Self::ADR  => u64::from(
                (((value >> 5 ) & 0x7FFFF) << 2) |
                ((value >> 29) & 3 )
            ),
            Self::ADRP => u64::from(
                (((value >> 5 ) & 0x7FFFF) << 2) |
                ((value >> 29) & 3 )
            ) << 12,
            Self::TBZ => u64::from(
                (value & mask) >> 5
            ) << 2,
            Self::Plain(_) => unreachable!()
        };

        // Sign extend.
        let bits = match self {
            Self::B => 26,
            Self::BCOND => 19,
            Self::ADR => 21,
            Self::ADRP => 33,
            Self::TBZ => 14,
            Self::Plain(_) => unreachable!()
        };
        let offset = 1u64 << (bits - 1);
        let value: u64 = (unpacked ^ offset) - offset;

        value as i64 as isize
    }
    fn kind(&self) -> RelocationKind {
        RelocationKind::Relative
    }
    fn page_size() -> usize {
        4096
    }
}

pub type Assembler = crate::Assembler<Aarch64Relocation>;
pub type AssemblyModifier<'a> = crate::Modifier<'a, Aarch64Relocation>;
pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;

/// Helper function for validating that a given value can be encoded as a 32-bit logical immediate
pub fn encode_logical_immediate_32bit(value: u32) -> Option<u16> {
    let transitions = value ^ value.rotate_right(1);
    let element_size = (64u32).checked_div(transitions.count_ones())?;

    // confirm that the elements are identical
    if value != value.rotate_left(element_size) {
        return None;
    }

    let element = value & (1u32 << element_size).wrapping_sub(1);
    let ones = element.count_ones();
    let imms = (!((element_size << 1) - 1) & 0x3F) | (ones - 1);

    let immr = if (element & 1) != 0 {
        ones - (!element).trailing_zeros()
    } else {
        element_size - element.trailing_zeros()
    };

    Some(((immr as u16) << 6) | (imms as u16))
}

/// Helper function for validating that a given value can be encoded as a 64-bit logical immediate
pub fn encode_logical_immediate_64bit(value: u64) -> Option<u16> {
    let transitions = value ^ value.rotate_right(1);
    let element_size = (128u32).checked_div(transitions.count_ones())?;

    // confirm that the elements are identical
    if value != value.rotate_left(element_size) {
        return None;
    }

    let element = value & (1u64 << element_size).wrapping_sub(1);
    let ones = element.count_ones();
    let imms = (!((element_size << 1) - 1) & 0x7F) | (ones - 1);

    let immr = if (element & 1) != 0 {
        ones - (!element).trailing_zeros()
    } else {
        element_size - element.trailing_zeros()
    };

    let n = imms & 0x40 == 0;
    let imms = imms & 0x3F;

    Some(((n as u16) << 12) | ((immr as u16) << 6) | (imms as u16))
}

/// Helper function for validating that a given value can be encoded as a floating point immediate
pub fn encode_floating_point_immediate(value: f32) -> Option<u8> {
    // floating point ARM immediates are encoded as
    // abcdefgh => aBbbbbbc defgh000 00000000 00000000
    // where B = !b
    // which means we can just slice out "a" and "bcdefgh" and assume the rest was correct

    let bits = value.to_bits();

    let check = (bits >> 25) & 0x3F;
    if (check == 0b10_0000 || check == 0b01_1111) && (bits & 0x7_FFFF) == 0 {
        Some((((bits >> 24) & 0x80) | ((bits >> 19) & 0x7F)) as u8)
    } else {
        None
    }
}<commit_msg>Fix encoding of the b and adrp instructions<commit_after>use crate::relocations::{Relocation, RelocationSize, RelocationKind, ImpossibleRelocation, fits_signed_bitfield};
use byteorder::{ByteOrder, LittleEndian};
use std::convert::TryFrom;

/// Relocation implementation for the aarch64 architecture.
#[derive(Debug, Clone)]
pub enum Aarch64Relocation {
    // b, bl 26 bits, dword aligned
    B,
    // b.cond, cbnz, cbz, ldr, ldrsw, prfm: 19 bits, dword aligned
    BCOND,
    // adr split 21 bit, byte aligned
    ADR,
    // adrp split 21 bit, 4096-byte aligned
    ADRP,
    // tbnz, tbz: 14 bits, dword aligned
    TBZ,
    // Anything in directives
    Plain(RelocationSize),
}

impl Aarch64Relocation {
    fn op_mask(&self) -> u32 {
        match self {
            Self::B => 0xFC00_0000,
            Self::BCOND => 0xFF00_001F,
            Self::ADR => 0x9F00_001F,
            Self::ADRP => 0x9F00_001F,
            Self::TBZ => 0xFFF8_001F,
            Self::Plain(_) => 0
        }
    }

    fn encode(&self, value: isize) -> Result<u32, ImpossibleRelocation> {
        let value = i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?;
        Ok(match self {
            Self::B => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 26) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x3FF_FFFF)
            },
            Self::BCOND => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 19) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x7FFFF) << 5
            },
            Self::ADR => {
                if !fits_signed_bitfield(value, 21) {
                    return Err(ImpossibleRelocation { } );
                }
                let low = (value) as u32;
                let high = (value >> 2) as u32;
                ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
            },
            Self::ADRP => {
                let value = value + 0xFFF;
                if !fits_signed_bitfield(value >> 12, 21) {
                    return Err(ImpossibleRelocation { } );
                }
                let low = (value >> 12) as u32;
                let high = (value >> 14) as u32;
                ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
            },
            Self::TBZ => {
                if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 14) {
                    return Err(ImpossibleRelocation { } );
                }
                let value = (value >> 2) as u32;
                (value & 0x3FFF) << 5
            },
            Self::Plain(_) => return Err(ImpossibleRelocation { } )
        })
    }
}

impl Relocation for Aarch64Relocation {
    type Encoding = (u8,);
    fn from_encoding(encoding: Self::Encoding) -> Self {
        match encoding.0 {
            0 => Self::B,
            1 => Self::BCOND,
            2 => Self::ADR,
            3 => Self::ADRP,
            4 => Self::TBZ,
            x  => Self::Plain(RelocationSize::from_encoding(x - 4))
        }
    }
    fn from_size(size: RelocationSize) -> Self {
        Self::Plain(size)
    }
    fn size(&self) -> usize {
        match self {
            Self::Plain(s) => s.size(),
            _ => RelocationSize::DWord.size(),
        }
    }
    fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
        if let Self::Plain(s) = self {
            return s.write_value(buf, value);
        };

        let mask = self.op_mask();
        let template = LittleEndian::read_u32(buf) & mask;

        let packed = self.encode(value)?;

        LittleEndian::write_u32(buf, template | packed);
        Ok(())
    }
    fn read_value(&self, buf: &[u8]) -> isize {
        if let Self::Plain(s) = self {
            return s.read_value(buf);
        };

        let mask = !self.op_mask();
        let value = LittleEndian::read_u32(buf);
        let unpacked = match self {
            Self::B => u64::from(
                value & mask
            ) << 2,
            Self::BCOND => u64::from(
                (value & mask) >> 5
            ) << 2,
            Self::ADR  => u64::from(
                (((value >> 5 ) & 0x7FFFF) << 2) |
                ((value >> 29) & 3 )
            ),
            Self::ADRP => u64::from(
                (((value >> 5 ) & 0x7FFFF) << 2) |
                ((value >> 29) & 3 )
            ) << 12,
            Self::TBZ => u64::from(
                (value & mask) >> 5
            ) << 2,
            Self::Plain(_) => unreachable!()
        };

        // Sign extend.
        let bits = match self {
            Self::B => 26,
            Self::BCOND => 19,
            Self::ADR => 21,
            Self::ADRP => 33,
            Self::TBZ => 14,
            Self::Plain(_) => unreachable!()
        };
        let offset = 1u64 << (bits - 1);
        let value: u64 = (unpacked ^ offset) - offset;

        value as i64 as isize
    }
    fn kind(&self) -> RelocationKind {
        RelocationKind::Relative
    }
    fn page_size() -> usize {
        4096
    }
}

pub type Assembler = crate::Assembler<Aarch64Relocation>;
pub type AssemblyModifier<'a> = crate::Modifier<'a, Aarch64Relocation>;
pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;

/// Helper function for validating that a given value can be encoded as a 32-bit logical immediate
pub fn encode_logical_immediate_32bit(value: u32) -> Option<u16> {
    let transitions = value ^ value.rotate_right(1);
    let element_size = (64u32).checked_div(transitions.count_ones())?;

    // confirm that the elements are identical
    if value != value.rotate_left(element_size) {
        return None;
    }

    let element = value & (1u32 << element_size).wrapping_sub(1);
    let ones = element.count_ones();
    let imms = (!((element_size << 1) - 1) & 0x3F) | (ones - 1);

    let immr = if (element & 1) != 0 {
        ones - (!element).trailing_zeros()
    } else {
        element_size - element.trailing_zeros()
    };

    Some(((immr as u16) << 6) | (imms as u16))
}

/// Helper function for validating that a given value can be encoded as a 64-bit logical immediate
pub fn encode_logical_immediate_64bit(value: u64) -> Option<u16> {
    let transitions = value ^ value.rotate_right(1);
    let element_size = (128u32).checked_div(transitions.count_ones())?;

    // confirm that the elements are identical
    if value != value.rotate_left(element_size) {
        return None;
    }

    let element = value & (1u64 << element_size).wrapping_sub(1);
    let ones = element.count_ones();
    let imms = (!((element_size << 1) - 1) & 0x7F) | (ones - 1);

    let immr = if (element & 1) != 0 {
        ones - (!element).trailing_zeros()
    } else {
        element_size - element.trailing_zeros()
    };

    let n = imms & 0x40 == 0;
    let imms = imms & 0x3F;

    Some(((n as u16) << 12) | ((immr as u16) << 6) | (imms as u16))
}

/// Helper function for validating that a given value can be encoded as a floating point immediate
pub fn encode_floating_point_immediate(value: f32) -> Option<u8> {
    // floating point ARM immediates are encoded as
    // abcdefgh => aBbbbbbc defgh000 00000000 00000000
    // where B = !b
    // which means we can just slice out "a" and "bcdefgh" and assume the rest was correct

    let bits = value.to_bits();

    let check = (bits >> 25) & 0x3F;
    if (check == 0b10_0000 || check == 0b01_1111) && (bits & 0x7_FFFF) == 0 {
        Some((((bits >> 24) & 0x80) | ((bits >> 19) & 0x7F)) as u8)
    } else {
        None
    }
}<|endoftext|>


<commit_before>use std::{fs::read_to_string, io::Write};

use common::{
    eyre::{bail, Result},
    serde_json,
    tokio::time::{sleep, Duration},
    tracing,
};
use fs_utils::{open_file_600, remove_if_exists};
use http_utils::CLIENT;

use crate::{
    errors::*,
    types::*,
    utils::{token_path, user_path, BASE_URL},
};

/// Get the currently authenticated user, if any
pub fn me() -> Result<Option<User>> {
    let path = user_path();
    if path.exists() {
        let json = read_to_string(path)?;
        let user: User = serde_json::from_str(&json)?;
        Ok(Some(user))
    } else {
        Ok(None)
    }
}

/// Login and return the authenticated user
///
/// Creates a voucher, opens the browser at the `/api/v1/vouchers?create=XXX` page,
/// and then starts polling `/api/v1/vouchers?redeem=XXX` to get the generated
/// API tokens.
pub async fn login() -> Result<User> {
    if let Some(user) = me()? {
        tracing::info!("Already logged in as @{}; use `stencila logout` first if you want to login as a different user", user.short_name);
        return Ok(user);
    }

    let voucher = key_utils::generate("svk");

    let create_url = format!("{}/vouchers?create={}", BASE_URL, voucher);
    tracing::info!("Opening login URL in browser: {}", create_url);
    webbrowser::open(&create_url)?;

    tracing::info!("Waiting for you to login in via browser");
    let redeem_url = format!("{}/vouchers?redeem={}", BASE_URL, voucher);
    loop {
        sleep(Duration::from_millis(1000)).await;

        let response = CLIENT.get(&redeem_url).send().await?;
        if response.status() == 200 {
            let token: ApiToken = response.json().await?;
            let json = serde_json::to_string_pretty(&token)?;
            let mut file = open_file_600(token_path())?;
            file.write_all(json.as_bytes())?;

            let response = CLIENT
                .get(format!("{}/me", BASE_URL))
                .bearer_auth(token.token)
                .send()
                .await?;
            let user: User = response.json().await?;
            let json = serde_json::to_string_pretty(&user)?;
            let mut file = open_file_600(user_path())?;
            file.write_all(json.as_bytes())?;

            tracing::info!(
                "Welcome @{}, you successfully logged in to your Stencila account",
                user.short_name
            );

            return Ok(user);
        } else if response.status() == 202 {
            // Voucher exists but not ready to be redeemed
            eprint!(".");
        } else {
            bail!(
                "While redeeming voucher: {}",
                Error::response_to_string(response).await
            );
        }
    }
}

/// Logout the currently logged in user, if any
///
/// Deletes `token.json`, `user.json`, etc.
pub async fn logout() -> Result<()> {
    match me()? {
        Some(user) => {
            remove_if_exists(token_path())?;
            remove_if_exists(user_path())?;

            tracing::info!(
                "Goodbye @{}, you successfully logged out of your Stencila account",
                user.short_name
            );
        }
        None => {
            tracing::info!("No user currently logged in");
        }
    }
    Ok(())
}

pub mod cli {
    use cli_utils::{
        clap::{self, Parser},
        common::{async_trait::async_trait, tracing},
        result, Result, Run,
    };

    use super::*;

    /// Show the currently authenticated user
    #[derive(Parser)]
    #[clap(alias = "user")]
    pub struct Me;

    #[async_trait]
    impl Run for Me {
        async fn run(&self) -> Result {
            let user = me()?;
            if user.is_none() {
                tracing::info!("No user currently logged in");
            }
            result::value(user)
        }
    }

    /// Login to your Stencila account
    ///
    /// Use this command to link the Stencila CLI to your Stencila account.
    /// A browser window will be opened allowing you to sign in to Stencila, or
    /// create a Stencila account if you do not have one already. Once you have
    /// done that an access token will be stored on your machine allowing to access the
    /// Stencila API without having to sign in again.
    #[derive(Parser)]
    #[clap(alias = "signin")]
    pub struct Login;

    #[async_trait]
    impl Run for Login {
        async fn run(&self) -> Result {
            let user = login().await?;
            result::value(user)
        }
    }

    /// Logout from your Stencila account
    ///
    /// Use this command to unlink the Stencila CLI from your Stencila account.
    /// This will not affect your login status in the browser. i.e. if you are logged in
    /// to Stencila in your browser, this will not log you out there.
    #[derive(Parser)]
    #[clap(alias = "signin")]
    pub struct Logout;

    #[async_trait]
    impl Run for Logout {
        async fn run(&self) -> Result {
            logout().await?;
            result::nothing()
        }
    }
}
<commit_msg>chore(Cloud auth): Add tag and note to voucher request<commit_after>use std::{fs::read_to_string, io::Write};

use common::{
    eyre::{bail, Result},
    serde_json,
    tokio::time::{sleep, Duration},
    tracing,
};
use fs_utils::{open_file_600, remove_if_exists};
use http_utils::CLIENT;

use crate::{
    errors::*,
    types::*,
    utils::{token_path, user_path, BASE_URL},
};

/// Get the currently authenticated user, if any
pub fn me() -> Result<Option<User>> {
    let path = user_path();
    if path.exists() {
        let json = read_to_string(path)?;
        let user: User = serde_json::from_str(&json)?;
        Ok(Some(user))
    } else {
        Ok(None)
    }
}

/// Login and return the authenticated user
///
/// Creates a voucher, opens the browser at the `/api/v1/vouchers?create=XXX` page,
/// and then starts polling `/api/v1/vouchers?redeem=XXX` to get the generated
/// API tokens.
pub async fn login() -> Result<User> {
    if let Some(user) = me()? {
        tracing::info!("Already logged in as @{}; use `stencila logout` first if you want to login as a different user", user.short_name);
        return Ok(user);
    }

    let voucher = key_utils::generate("svk");

    let create_url = format!("{}/vouchers?create={}&tag=cli&note=Automatically%20generated%20for%20logins%20from%20Stencila%20CLI", BASE_URL, voucher);
    tracing::info!("Opening login URL in browser: {}", create_url);
    webbrowser::open(&create_url)?;

    tracing::info!("Waiting for you to login in via browser");
    let redeem_url = format!("{}/vouchers?redeem={}", BASE_URL, voucher);
    loop {
        sleep(Duration::from_millis(1000)).await;

        let response = CLIENT.get(&redeem_url).send().await?;
        if response.status() == 200 {
            let token: ApiToken = response.json().await?;
            let json = serde_json::to_string_pretty(&token)?;
            let mut file = open_file_600(token_path())?;
            file.write_all(json.as_bytes())?;

            let response = CLIENT
                .get(format!("{}/me", BASE_URL))
                .bearer_auth(token.token)
                .send()
                .await?;
            let user: User = response.json().await?;
            let json = serde_json::to_string_pretty(&user)?;
            let mut file = open_file_600(user_path())?;
            file.write_all(json.as_bytes())?;

            tracing::info!(
                "Welcome @{}, you successfully logged in to your Stencila account",
                user.short_name
            );

            return Ok(user);
        } else if response.status() == 202 {
            // Voucher exists but not ready to be redeemed
            eprint!(".");
        } else {
            bail!(
                "While redeeming voucher: {}",
                Error::response_to_string(response).await
            );
        }
    }
}

/// Logout the currently logged in user, if any
///
/// Deletes `token.json`, `user.json`, etc.
pub async fn logout() -> Result<()> {
    match me()? {
        Some(user) => {
            remove_if_exists(token_path())?;
            remove_if_exists(user_path())?;

            tracing::info!(
                "Goodbye @{}, you successfully logged out of your Stencila account",
                user.short_name
            );
        }
        None => {
            tracing::info!("No user currently logged in");
        }
    }
    Ok(())
}

pub mod cli {
    use cli_utils::{
        clap::{self, Parser},
        common::{async_trait::async_trait, tracing},
        result, Result, Run,
    };

    use super::*;

    /// Show the currently authenticated user
    #[derive(Parser)]
    #[clap(alias = "user")]
    pub struct Me;

    #[async_trait]
    impl Run for Me {
        async fn run(&self) -> Result {
            let user = me()?;
            if user.is_none() {
                tracing::info!("No user currently logged in");
            }
            result::value(user)
        }
    }

    /// Login to your Stencila account
    ///
    /// Use this command to link the Stencila CLI to your Stencila account.
    /// A browser window will be opened allowing you to sign in to Stencila, or
    /// create a Stencila account if you do not have one already. Once you have
    /// done that an access token will be stored on your machine allowing to access the
    /// Stencila API without having to sign in again.
    #[derive(Parser)]
    #[clap(alias = "signin")]
    pub struct Login;

    #[async_trait]
    impl Run for Login {
        async fn run(&self) -> Result {
            let user = login().await?;
            result::value(user)
        }
    }

    /// Logout from your Stencila account
    ///
    /// Use this command to unlink the Stencila CLI from your Stencila account.
    /// This will not affect your login status in the browser. i.e. if you are logged in
    /// to Stencila in your browser, this will not log you out there.
    #[derive(Parser)]
    #[clap(alias = "signin")]
    pub struct Logout;

    #[async_trait]
    impl Run for Logout {
        async fn run(&self) -> Result {
            logout().await?;
            result::nothing()
        }
    }
}
<|endoftext|>


<commit_before>#![ warn( missing_docs ) ]
#![ warn( missing_debug_implementations ) ]

//!
//! Basic exceptions handling mechanism.
//!
//! # Sample
//! ```
//! use werror::*;
//!
//! let err1 = Error::new( "Some error" );
//! println!( "err1 : {}", err1 );
//! // < err1 : Some error
//! ```

mod assert;
mod error;

pub use assert::*;
pub use error::*;
<commit_msg>Add example of usage tests from file `Readme.md`<commit_after>#![ warn( missing_docs ) ]
#![ warn( missing_debug_implementations ) ]

//!
//! Basic exceptions handling mechanism.
//!
// //! # Sample
// //! ```
// //! use werror::*;
// //!
// //! let err1 = Error::new( "Some error" );
// //! println!( "err1 : {}", err1 );
// //! // < err1 : Some error
// //! ```

#![ doc = include_str!( "../../../module/rust/werror/Readme.md" ) ]

mod assert;
mod error;

pub use assert::*;
pub use error::*;
<|endoftext|>


<commit_before>use once_cell::sync::OnceCell;
use std::ops::RangeBounds;
use std::sync::RwLock;
use serde_json::json;

/// グローバルに保持するデータ。
/// ユーザによる設定と、見つからなかった場合に使うデフォルト値からなる。
/// それぞれは Json object によるツリー構造。
struct ConfigData {
    def:  serde_json::Value,
    main: serde_json::Value,
}

// default = empty Object (map)
impl Default for ConfigData {
    fn default() -> Self {
        Self { def: json!({}), main: json!({}) }
    }
}

/// 設定データ(グローバル変数)。
/// 一応スレッドセーフとするが、初期化時に一度だけ書き換え、
/// その後は read only アクセスしかしないので RwLock とする。
static CONFIG: OnceCell<RwLock<ConfigData>> = OnceCell::new();

/// 設定データを json 文字列からロードして設定データシステムを初期化する。
pub fn init_and_load(def_json: &str, main_json: &str) -> Result<(), String>
{
    // lazy inialize + wlock
    let mut config = CONFIG
        .get_or_init(|| RwLock::new(Default::default()))
        .write()
        .unwrap();

    config.def = match serde_json::from_str(def_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };
    config.main = match serde_json::from_str(main_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };

    Ok(())
}

/// Object tree を keys: 文字列の配列 (スライス) で検索する。
/// 見つからなかった場合、および
/// 数値, 真偽値, 文字列, 配列 以外が見つかった場合は json - null を返す。
/// グローバル構造内のデータを返す場合、コピーを返す。
fn search(root: &serde_json::Value, keys: &[&str]) -> serde_json::Value {
    let null_value = serde_json::Value::Null;

    let mut value = root;
    for key in keys.iter() {
        value = match value.as_object() {
            Some(map) => map.get(*key).unwrap_or(&null_value),
            None => &null_value,
        };
    }

    if value.is_number() || value.is_boolean() || value.is_string() || value.is_array() {
        value.clone()
    }
    else {
        serde_json::Value::Null
    }
}

/// main -> def の順番で検索する。
fn search_all(keys: &[&str]) -> serde_json::Value {
    // rlock
    let config = CONFIG
        .get().unwrap()
        .read().unwrap();

    let value = search(&config.main, keys);
    if !value.is_null() {
        value
    }
    else {
        search(&config.def, keys)
    }
}

/// 真偽値設定データを取得する。
/// 見つからない場合や真偽値でない場合は None を返す。
pub fn get_boolean(keys: &[&str]) -> Option<bool> {
    search_all(keys).as_bool()
}

/// 数値データを i64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_i64<R: RangeBounds<i64>>(keys: &[&str], range: R) -> Option<i64> {
    search_all(keys).as_i64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 数値データを u64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_u64<R: RangeBounds<u64>>(keys: &[&str], range: R) -> Option<u64> {
    search_all(keys).as_u64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 文字列設定データを取得する。
/// 見つからない場合や文字列でない場合は None を返す。
pub fn get_string(keys: &[&str]) -> Option<String> {
    search_all(keys).as_str().map(|s| s.into())
}

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

    #[test]
    #[serial(config)]
    fn search() {
        let main = r#"{"a": {"b": {"c": "main"}}}"#;
        let def = r#"{"a": {"b": {"d": "default"}}}"#;

        let result = init_and_load(def, main);
        assert!(result.is_ok());

        let v = get_string(&["a", "b", "c"]);
        assert!(v.unwrap() == "main");
        let v = get_string(&["a", "b", "C"]);
        assert!(v.is_none());
        let v = get_string(&["a", "b", "d"]);
        assert!(v.unwrap() == "default");
        let v = get_string(&["a", "b", "D"]);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn i64() {
        let main = r#"{"i64": {"min": -9223372036854775808, "max": 9223372036854775807}}"#;
        let def = "{}";

        let result = init_and_load(def, main);
        assert!(result.is_ok());

        let v = get_i64(&["i64", "min"], ..);
        assert_eq!(v.unwrap(), i64::MIN);
        let v = get_i64(&["i64", "max"], ..);
        assert_eq!(v.unwrap(), i64::MAX);

        let v = get_i64(&["i64", "min"], i64::MIN+1..);
        assert!(v.is_none());
        let v = get_i64(&["i64", "max"], ..=i64::MAX-1);
        assert!(v.is_none());
    }
}
<commit_msg>テスト追加<commit_after>use once_cell::sync::OnceCell;
use std::ops::RangeBounds;
use std::sync::RwLock;
use serde_json::json;

/// グローバルに保持するデータ。
/// ユーザによる設定と、見つからなかった場合に使うデフォルト値からなる。
/// それぞれは Json object によるツリー構造。
struct ConfigData {
    def:  serde_json::Value,
    main: serde_json::Value,
}

// default = empty Object (map)
impl Default for ConfigData {
    fn default() -> Self {
        Self { def: json!({}), main: json!({}) }
    }
}

/// 設定データ(グローバル変数)。
/// 一応スレッドセーフとするが、初期化時に一度だけ書き換え、
/// その後は read only アクセスしかしないので RwLock とする。
static CONFIG: OnceCell<RwLock<ConfigData>> = OnceCell::new();

/// 設定データを json 文字列からロードして設定データシステムを初期化する。
pub fn init_and_load(def_json: &str, main_json: &str) -> Result<(), String>
{
    // lazy inialize + wlock
    let mut config = CONFIG
        .get_or_init(|| RwLock::new(Default::default()))
        .write()
        .unwrap();

    config.def = match serde_json::from_str(def_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };
    config.main = match serde_json::from_str(main_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };

    Ok(())
}

/// Object tree を keys: 文字列の配列 (スライス) で検索する。
/// 見つからなかった場合、および
/// 数値, 真偽値, 文字列, 配列 以外が見つかった場合は json - null を返す。
/// グローバル構造内のデータを返す場合、コピーを返す。
fn search(root: &serde_json::Value, keys: &[&str]) -> serde_json::Value {
    let null_value = serde_json::Value::Null;

    let mut value = root;
    for key in keys.iter() {
        value = match value.as_object() {
            Some(map) => map.get(*key).unwrap_or(&null_value),
            None => &null_value,
        };
    }

    if value.is_number() || value.is_boolean() || value.is_string() || value.is_array() {
        value.clone()
    }
    else {
        serde_json::Value::Null
    }
}

/// main -> def の順番で検索する。
fn search_all(keys: &[&str]) -> serde_json::Value {
    // rlock
    let config = CONFIG
        .get().unwrap()
        .read().unwrap();

    let value = search(&config.main, keys);
    if !value.is_null() {
        value
    }
    else {
        search(&config.def, keys)
    }
}

/// 真偽値設定データを取得する。
/// 見つからない場合や真偽値でない場合は None を返す。
pub fn get_boolean(keys: &[&str]) -> Option<bool> {
    search_all(keys).as_bool()
}

/// 数値データを i64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_i64<R: RangeBounds<i64>>(keys: &[&str], range: R) -> Option<i64> {
    search_all(keys).as_i64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 数値データを u64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_u64<R: RangeBounds<u64>>(keys: &[&str], range: R) -> Option<u64> {
    search_all(keys).as_u64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 文字列設定データを取得する。
/// 見つからない場合や文字列でない場合は None を返す。
pub fn get_string(keys: &[&str]) -> Option<String> {
    search_all(keys).as_str().map(|s| s.into())
}

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

    #[test]
    #[serial(config)]
    fn search() {
        let main = r#"{"a": {"b": {"c": "main"}}}"#;
        let def = r#"{"a": {"b": {"d": "default"}}}"#;

        let result = init_and_load(def, main);
        assert!(result.is_ok());

        let v = get_string(&["a", "b", "c"]);
        assert!(v.unwrap() == "main");
        let v = get_string(&["a", "b", "C"]);
        assert!(v.is_none());
        let v = get_string(&["a", "b", "d"]);
        assert!(v.unwrap() == "default");
        let v = get_string(&["a", "b", "D"]);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn i64() {
        let main = r#"{"i64": {"min": -9223372036854775808, "max": 9223372036854775807}}"#;
        let def = "{}";

        let result = init_and_load(def, main);
        assert!(result.is_ok());

        let v = get_i64(&["i64", "min"], ..);
        assert_eq!(v.unwrap(), i64::MIN);
        let v = get_i64(&["i64", "max"], ..);
        assert_eq!(v.unwrap(), i64::MAX);

        let v = get_i64(&["i64", "min"], i64::MIN+1..);
        assert!(v.is_none());
        let v = get_i64(&["i64", "max"], ..=i64::MAX-1);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn u64() {
        let main = r#"{"u64": {"min": 0, "max": 18446744073709551615}}"#;
        let def = "{}";

        let result = init_and_load(def, main);
        assert!(result.is_ok());

        let v = get_u64(&["u64", "min"], ..);
        assert_eq!(v.unwrap(), u64::MIN);
        let v = get_u64(&["u64", "max"], ..);
        assert_eq!(v.unwrap(), u64::MAX);

        let v = get_u64(&["u64", "min"], u64::MIN+1..);
        assert!(v.is_none());
        let v = get_u64(&["u64", "max"], ..=u64::MAX-1);
        assert!(v.is_none());
    }
}
<|endoftext|>