<commit_before>use core::ops::{Add, Index};
use core::ptr;

use common::{debug, memory};
use common::vec::Vec;

/// A trait for types that can be converted to `String`
pub trait ToString {
    /// Convert the type to strings
    fn to_string(&self) -> String;
}

impl ToString for &'static str {
    /// Convert the type to `String`
    fn to_string(&self) -> String {
        String::from_str(self)
    }
}

/// An iterator over unicode characters
pub struct Chars<'a> {
    /// The string iterating over
    string: &'a String,
    /// The offset of the iterator
    offset: usize,
}

impl <'a> Iterator for Chars<'a> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let ret = Some(self.string[self.offset]);
            self.offset += 1;
            ret
        } else {
            None
        }
    }
}

/// A split
pub struct Split<'a> {
    /// The string being split
    string: &'a String,
    /// The offset of the split
    offset: usize,
    /// The string seperator
    seperator: String,
}

impl <'a> Iterator for Split<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let start = self.offset;
            let mut len = 0;
            for i in start..self.string.len() {
                if self.seperator == self.string.substr(i, self.seperator.len()) {
                    self.offset += self.seperator.len();
                    break;
                } else {
                    self.offset += 1;
                    len += 1;
                }
            }
            Some(self.string.substr(start, len))
        } else {
            None
        }
    }
}

/// A set of lines
pub struct Lines<'a> {
    /// The underlying split
    split: Split<'a>
}

impl <'a> Iterator for Lines<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        match self.split.next() {
            Some(string) => if string.ends_with("\r".to_string()) {
                Some(string.substr(0, string.len() - 1))
            } else {
                Some(string)
            },
            None => None
        }
    }
}

/// A heap allocated, owned string.
pub struct String {
    /// The vector of the chars
    pub vec: Vec<char>,
}

impl String {
    /// Create a new empty `String`
    pub fn new() -> Self {
        String { vec: Vec::new() }
    }

    // TODO FromStr trait
    /// Convert a string literal to a `String`
    pub fn from_str(s: &str) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for c in s.chars() {
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a c-style string slice to a String
    pub fn from_c_slice(s: &[u8]) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for b in s {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a utf8 vector to a string
    // Why &Vec?
    pub fn from_utf8(utf_vec: &Vec<u8>) -> Self {
        let mut vec: Vec<char> = Vec::new();

        //TODO: better UTF support
        for b in utf_vec.iter() {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a C-style string literal to a `String`
    pub unsafe fn from_c_str(s: *const u8) -> Self {
        let mut vec: Vec<char> = Vec::new();

        let mut i = 0;
        loop {
            let c = ptr::read(s.offset(i)) as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
            i += 1;
        }

        String { vec: vec }
    }

    /// Convert an integer to a String using a given radix
    pub fn from_num_radix(num: usize, radix: usize) -> Self {
        if radix == 0 {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();

        let mut digit_num = num;
        loop {
            let mut digit = (digit_num % radix) as u8;
            if digit > 9 {
                digit += 'A' as u8 - 10;
            } else {
                digit += '0' as u8;
            }

            vec.insert(0, digit as char);

            if digit_num < radix {
                break;
            }

            digit_num /= radix;
        }

        String { vec: vec }
    }

    /// Convert a signed integer to a String
    // TODO: Consider using `int` instead of `num`
    pub fn from_num_radix_signed(num: isize, radix: usize) -> Self {
        if num >= 0 {
            String::from_num_radix(num as usize, radix)
        } else {
            "-".to_string() + String::from_num_radix((-num) as usize, radix)
        }
    }

    /// Convert a `char` to a string
    pub fn from_char(c: char) -> Self {
        if c == '\0' {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();
        vec.push(c);

        String { vec: vec }
    }

    /// Convert an unsigned integer to a `String` in base 10
    pub fn from_num(num: usize) -> Self {
        String::from_num_radix(num, 10)
    }

    /// Convert a signed int to a `String` in base 10
    pub fn from_num_signed(num: isize) -> Self {
        String::from_num_radix_signed(num, 10)
    }

    /// Get a substring
    // TODO: Consider to use a string slice
    pub fn substr(&self, start: usize, len: usize) -> Self {
        let mut i = start;
        if i > self.len() {
            i = self.len();
        }

        let mut j = i + len;
        if j > self.len() {
            j = self.len();
        }

        let mut vec: Vec<char> = Vec::new();

        for k in i..j {
            vec.push(self[k]);
        }

        String { vec: vec }
    }

    /// Find the index of a substring in a string
    pub fn find(&self, other: Self) -> Option<usize> {
        if self.len() >= other.len() {
            for i in 0..self.len() + 1 - other.len() {
                if self.substr(i, other.len()) == other {
                    return Some(i);
                }
            }
        }
        None
    }

    /// Check if the string starts with a given string
    pub fn starts_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: This is inefficient
            self.substr(0, other.len()) == other
        } else {
            false
        }
    }

    /// Check if a string ends with another string
    pub fn ends_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: Inefficient
            self.substr(self.len() - other.len(), other.len()) == other
        } else {
            false
        }
    }

    /// Get the length of the string
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// Get a iterator over the chars of the string
    pub fn chars(&self) -> Chars {
        Chars {
            string: &self,
            offset: 0,
        }
    }

    /// Get a iterator of the splits of the string (by a seperator)
    pub fn split(&self, seperator: Self) -> Split {
        Split {
            string: &self,
            offset: 0,
            seperator: seperator,
        }
    }

    /// Get a iterator of lines from the string
    pub fn lines(&self) -> Lines {
        Lines {
            split: self.split("\n".to_string())
        }
    }

    /// Convert the string to UTF-8
    pub fn to_utf8(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::new();

        for c in self.chars() {
            let u = c as usize;
            if u < 0x80 {
                vec.push(u as u8);
            } else if u < 0x800 {
                vec.push(0b11000000 | ((u >> 6) as u8 & 0b00011111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else if u < 0x10000 {
                vec.push(0b11100000 | ((u >> 12) as u8 & 0b00001111));
                vec.push(0b10000000 | ((u >> 6) as u8 & 0b00111111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else {
                debug::d("Unhandled to_utf8 code ");
                debug::dh(u);
                debug::dl();
                unsafe {
                    debug::dh(self.vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(self.vec.len());
                debug::d(" to ");
                unsafe {
                    debug::dh(vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(vec.len());
                debug::dl();
                break;
            }
        }

        vec
    }

    /// Convert the string to a C-style string
    pub unsafe fn to_c_str(&self) -> *const u8 {
        let length = self.len() + 1;

        let data = memory::alloc(length) as *mut u8;

        for i in 0..self.len() {
            ptr::write(data.offset(i as isize), self[i] as u8);
        }
        ptr::write(data.offset(self.len() as isize), 0);

        data
    }

    /// Parse the string to a integer using a given radix
    pub fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    pub fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self[0] == '-' {
            -(self.substr(1, self.len() - 1).to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    pub fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    pub fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }

    /// Debug
    pub fn d(&self) {
        for c in self.chars() {
            debug::dc(c);
        }
    }
}

static NULL_CHAR: char = '\0';

impl Index<usize> for String {
    type Output = char;
    fn index<'a>(&'a self, i: usize) -> &'a Self::Output {
        match self.vec.get(i) {
            Some(c) => c,
            None => &NULL_CHAR,
        }
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        if self.len() == other.len() {
            for i in 0..self.len() {
                if self[i] != other[i] {
                    return false;
                }
            }

            true
        } else {
            false
        }
    }
}

impl Clone for String {
    fn clone(&self) -> Self {
        self.substr(0, self.len())
    }
}

impl<'a> Add<&'a String> for String {
    type Output = String;
    fn add(mut self, other: &'a Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a mut String> for String {
    type Output = String;
    fn add(mut self, other: &'a mut Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl Add for String {
    type Output = String;
    fn add(mut self, other: Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a str> for String {
    type Output = String;
    fn add(self, other: &'a str) -> Self {
        self + String::from_str(other)
    }
}

impl Add<char> for String {
    type Output = String;
    fn add(mut self, other: char) -> Self {
        self.vec.push(other);
        self
    }
}

impl Add<usize> for String {
    type Output = String;
    fn add(self, other: usize) -> Self {
        self + String::from_num(other)
    }
}

impl Add<isize> for String {
    type Output = String;
    fn add(self, other: isize) -> Self {
        self + String::from_num_signed(other)
    }
}

// Slightly modified version of the impl_eq found in the std collections String
// Ideally, we'd compare these as arrays. However, we'd need to flesh out String a bit more
macro_rules! impl_chars_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
        }

        impl<'a> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
        }

    }
}

impl_chars_eq! { String, str }
impl_chars_eq! { String, &'a str }
<commit_msg>Fix ne in string compare<commit_after>use core::ops::{Add, Index};
use core::ptr;

use common::{debug, memory};
use common::vec::Vec;

/// A trait for types that can be converted to `String`
pub trait ToString {
    /// Convert the type to strings
    fn to_string(&self) -> String;
}

impl ToString for &'static str {
    /// Convert the type to `String`
    fn to_string(&self) -> String {
        String::from_str(self)
    }
}

/// An iterator over unicode characters
pub struct Chars<'a> {
    /// The string iterating over
    string: &'a String,
    /// The offset of the iterator
    offset: usize,
}

impl <'a> Iterator for Chars<'a> {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let ret = Some(self.string[self.offset]);
            self.offset += 1;
            ret
        } else {
            None
        }
    }
}

/// A split
pub struct Split<'a> {
    /// The string being split
    string: &'a String,
    /// The offset of the split
    offset: usize,
    /// The string seperator
    seperator: String,
}

impl <'a> Iterator for Split<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset < self.string.len() {
            let start = self.offset;
            let mut len = 0;
            for i in start..self.string.len() {
                if self.seperator == self.string.substr(i, self.seperator.len()) {
                    self.offset += self.seperator.len();
                    break;
                } else {
                    self.offset += 1;
                    len += 1;
                }
            }
            Some(self.string.substr(start, len))
        } else {
            None
        }
    }
}

/// A set of lines
pub struct Lines<'a> {
    /// The underlying split
    split: Split<'a>
}

impl <'a> Iterator for Lines<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        match self.split.next() {
            Some(string) => if string.ends_with("\r".to_string()) {
                Some(string.substr(0, string.len() - 1))
            } else {
                Some(string)
            },
            None => None
        }
    }
}

/// A heap allocated, owned string.
pub struct String {
    /// The vector of the chars
    pub vec: Vec<char>,
}

impl String {
    /// Create a new empty `String`
    pub fn new() -> Self {
        String { vec: Vec::new() }
    }

    // TODO FromStr trait
    /// Convert a string literal to a `String`
    pub fn from_str(s: &str) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for c in s.chars() {
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a c-style string slice to a String
    pub fn from_c_slice(s: &[u8]) -> Self {
        let mut vec: Vec<char> = Vec::new();

        for b in s {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a utf8 vector to a string
    // Why &Vec?
    pub fn from_utf8(utf_vec: &Vec<u8>) -> Self {
        let mut vec: Vec<char> = Vec::new();

        //TODO: better UTF support
        for b in utf_vec.iter() {
            let c = *b as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
        }

        String { vec: vec }
    }

    /// Convert a C-style string literal to a `String`
    pub unsafe fn from_c_str(s: *const u8) -> Self {
        let mut vec: Vec<char> = Vec::new();

        let mut i = 0;
        loop {
            let c = ptr::read(s.offset(i)) as char;
            if c == '\0' {
                break;
            }
            vec.push(c);
            i += 1;
        }

        String { vec: vec }
    }

    /// Convert an integer to a String using a given radix
    pub fn from_num_radix(num: usize, radix: usize) -> Self {
        if radix == 0 {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();

        let mut digit_num = num;
        loop {
            let mut digit = (digit_num % radix) as u8;
            if digit > 9 {
                digit += 'A' as u8 - 10;
            } else {
                digit += '0' as u8;
            }

            vec.insert(0, digit as char);

            if digit_num < radix {
                break;
            }

            digit_num /= radix;
        }

        String { vec: vec }
    }

    /// Convert a signed integer to a String
    // TODO: Consider using `int` instead of `num`
    pub fn from_num_radix_signed(num: isize, radix: usize) -> Self {
        if num >= 0 {
            String::from_num_radix(num as usize, radix)
        } else {
            "-".to_string() + String::from_num_radix((-num) as usize, radix)
        }
    }

    /// Convert a `char` to a string
    pub fn from_char(c: char) -> Self {
        if c == '\0' {
            return String::new();
        }

        let mut vec: Vec<char> = Vec::new();
        vec.push(c);

        String { vec: vec }
    }

    /// Convert an unsigned integer to a `String` in base 10
    pub fn from_num(num: usize) -> Self {
        String::from_num_radix(num, 10)
    }

    /// Convert a signed int to a `String` in base 10
    pub fn from_num_signed(num: isize) -> Self {
        String::from_num_radix_signed(num, 10)
    }

    /// Get a substring
    // TODO: Consider to use a string slice
    pub fn substr(&self, start: usize, len: usize) -> Self {
        let mut i = start;
        if i > self.len() {
            i = self.len();
        }

        let mut j = i + len;
        if j > self.len() {
            j = self.len();
        }

        let mut vec: Vec<char> = Vec::new();

        for k in i..j {
            vec.push(self[k]);
        }

        String { vec: vec }
    }

    /// Find the index of a substring in a string
    pub fn find(&self, other: Self) -> Option<usize> {
        if self.len() >= other.len() {
            for i in 0..self.len() + 1 - other.len() {
                if self.substr(i, other.len()) == other {
                    return Some(i);
                }
            }
        }
        None
    }

    /// Check if the string starts with a given string
    pub fn starts_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: This is inefficient
            self.substr(0, other.len()) == other
        } else {
            false
        }
    }

    /// Check if a string ends with another string
    pub fn ends_with(&self, other: Self) -> bool {
        if self.len() >= other.len() {
            // FIXME: Inefficient
            self.substr(self.len() - other.len(), other.len()) == other
        } else {
            false
        }
    }

    /// Get the length of the string
    pub fn len(&self) -> usize {
        self.vec.len()
    }

    /// Get a iterator over the chars of the string
    pub fn chars(&self) -> Chars {
        Chars {
            string: &self,
            offset: 0,
        }
    }

    /// Get a iterator of the splits of the string (by a seperator)
    pub fn split(&self, seperator: Self) -> Split {
        Split {
            string: &self,
            offset: 0,
            seperator: seperator,
        }
    }

    /// Get a iterator of lines from the string
    pub fn lines(&self) -> Lines {
        Lines {
            split: self.split("\n".to_string())
        }
    }

    /// Convert the string to UTF-8
    pub fn to_utf8(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::new();

        for c in self.chars() {
            let u = c as usize;
            if u < 0x80 {
                vec.push(u as u8);
            } else if u < 0x800 {
                vec.push(0b11000000 | ((u >> 6) as u8 & 0b00011111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else if u < 0x10000 {
                vec.push(0b11100000 | ((u >> 12) as u8 & 0b00001111));
                vec.push(0b10000000 | ((u >> 6) as u8 & 0b00111111));
                vec.push(0b10000000 | (u as u8 & 0b00111111));
            } else {
                debug::d("Unhandled to_utf8 code ");
                debug::dh(u);
                debug::dl();
                unsafe {
                    debug::dh(self.vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(self.vec.len());
                debug::d(" to ");
                unsafe {
                    debug::dh(vec.as_ptr() as usize);
                }
                debug::d(" ");
                debug::dd(vec.len());
                debug::dl();
                break;
            }
        }

        vec
    }

    /// Convert the string to a C-style string
    pub unsafe fn to_c_str(&self) -> *const u8 {
        let length = self.len() + 1;

        let data = memory::alloc(length) as *mut u8;

        for i in 0..self.len() {
            ptr::write(data.offset(i as isize), self[i] as u8);
        }
        ptr::write(data.offset(self.len() as isize), 0);

        data
    }

    /// Parse the string to a integer using a given radix
    pub fn to_num_radix(&self, radix: usize) -> usize {
        if radix == 0 {
            return 0;
        }

        let mut num = 0;
        for c in self.chars() {
            let digit;
            if c >= '0' && c <= '9' {
                digit = c as usize - '0' as usize
            } else if c >= 'A' && c <= 'Z' {
                digit = c as usize - 'A' as usize + 10
            } else if c >= 'a' && c <= 'z' {
                digit = c as usize - 'a' as usize + 10
            } else {
                break;
            }

            if digit >= radix {
                break;
            }

            num *= radix;
            num += digit;
        }

        num
    }

    /// Parse the string as a signed integer using a given radix
    pub fn to_num_radix_signed(&self, radix: usize) -> isize {
        if self[0] == '-' {
            -(self.substr(1, self.len() - 1).to_num_radix(radix) as isize)
        } else {
            self.to_num_radix(radix) as isize
        }
    }

    /// Parse it as a unsigned integer in base 10
    pub fn to_num(&self) -> usize {
        self.to_num_radix(10)
    }

    /// Parse it as a signed integer in base 10
    pub fn to_num_signed(&self) -> isize {
        self.to_num_radix_signed(10)
    }

    /// Debug
    pub fn d(&self) {
        for c in self.chars() {
            debug::dc(c);
        }
    }
}

static NULL_CHAR: char = '\0';

impl Index<usize> for String {
    type Output = char;
    fn index<'a>(&'a self, i: usize) -> &'a Self::Output {
        match self.vec.get(i) {
            Some(c) => c,
            None => &NULL_CHAR,
        }
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        if self.len() == other.len() {
            for i in 0..self.len() {
                if self[i] != other[i] {
                    return false;
                }
            }

            true
        } else {
            false
        }
    }
}

impl Clone for String {
    fn clone(&self) -> Self {
        self.substr(0, self.len())
    }
}

impl<'a> Add<&'a String> for String {
    type Output = String;
    fn add(mut self, other: &'a Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a mut String> for String {
    type Output = String;
    fn add(mut self, other: &'a mut Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl Add for String {
    type Output = String;
    fn add(mut self, other: Self) -> Self {
        self.vec.push_all(&other.vec);
        self
    }
}

impl<'a> Add<&'a str> for String {
    type Output = String;
    fn add(self, other: &'a str) -> Self {
        self + String::from_str(other)
    }
}

impl Add<char> for String {
    type Output = String;
    fn add(mut self, other: char) -> Self {
        self.vec.push(other);
        self
    }
}

impl Add<usize> for String {
    type Output = String;
    fn add(self, other: usize) -> Self {
        self + String::from_num(other)
    }
}

impl Add<isize> for String {
    type Output = String;
    fn add(self, other: isize) -> Self {
        self + String::from_num_signed(other)
    }
}

// Slightly modified version of the impl_eq found in the std collections String
// Ideally, we'd compare these as arrays. However, we'd need to flesh out String a bit more
macro_rules! impl_chars_eq {
    ($lhs:ty, $rhs: ty) => {
        impl<'a> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$rhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a != b) }
        }

        impl<'a> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a == b) }
            #[inline]
            fn ne(&self, other: &$lhs) -> bool { self.chars().zip(other.chars()).all(|(a,b)| a != b) }
        }

    }
}

impl_chars_eq! { String, str }
impl_chars_eq! { String, &'a str }
<|endoftext|>


<commit_before>use std::env::*;
use std::ffi::{OsStr, OsString};

use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};

fn make_rand_name() -> OsString {
    let rng = thread_rng();
    let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10).collect::<String>());
    let n = OsString::from(n);
    assert!(var_os(&n).is_none());
    n
}

fn eq(a: Option<OsString>, b: Option<&str>) {
    assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
}

#[test]
fn test_set_var() {
    let n = make_rand_name();
    set_var(&n, "VALUE");
    eq(var_os(&n), Some("VALUE"));
}

#[test]
fn test_remove_var() {
    let n = make_rand_name();
    set_var(&n, "VALUE");
    remove_var(&n);
    eq(var_os(&n), None);
}

#[test]
fn test_set_var_overwrite() {
    let n = make_rand_name();
    set_var(&n, "1");
    set_var(&n, "2");
    eq(var_os(&n), Some("2"));
    set_var(&n, "");
    eq(var_os(&n), Some(""));
}

#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_var_big() {
    let mut s = "".to_string();
    let mut i = 0;
    while i < 100 {
        s.push_str("aaaaaaaaaa");
        i += 1;
    }
    let n = make_rand_name();
    set_var(&n, &s);
    eq(var_os(&n), Some(&s));
}

#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() {
    let n = make_rand_name();
    let s = "x".repeat(10000);
    set_var(&n, &s);
    eq(var_os(&n), Some(&s));
    remove_var(&n);
    eq(var_os(&n), None);
}

#[test]
fn test_env_set_var() {
    let n = make_rand_name();

    let mut e = vars_os();
    set_var(&n, "VALUE");
    assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));

    assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
}

#[test]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
#[allow(deprecated)]
fn env_home_dir() {
    fn var_to_os_string(var: Result<String, VarError>) -> Option<OsString> {
        match var {
            Ok(var) => Some(OsString::from(var)),
            Err(VarError::NotUnicode(var)) => Some(var),
            _ => None,
        }
    }

    cfg_if::cfg_if! {
        if #[cfg(unix)] {
            use std::path::PathBuf;

            let oldhome = var_to_os_string(var("HOME"));

            set_var("HOME", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");
            if cfg!(target_os = "android") {
                assert!(home_dir().is_none());
            } else {
                // When HOME is not set, some platforms return `None`,
                // but others return `Some` with a default.
                // Just check that it is not "/home/MountainView".
                assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
            }

            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
        } else if #[cfg(windows)] {
            use std::path::PathBuf;

            let oldhome = var_to_os_string(var("HOME"));
            let olduserprofile = var_to_os_string(var("USERPROFILE"));

            remove_var("HOME");
            remove_var("USERPROFILE");

            assert!(home_dir().is_some());

            set_var("HOME", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");

            set_var("USERPROFILE", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            set_var("HOME", "/home/MountainView");
            set_var("USERPROFILE", "/home/PaloAlto");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");
            remove_var("USERPROFILE");

            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
            if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
        }
    }
}
<commit_msg>Auto merge of #79797 - jethrogb:sgx-fix-79038, r=Mark-Simulacrum<commit_after>use std::env::*;
use std::ffi::{OsStr, OsString};

use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};

fn make_rand_name() -> OsString {
    let rng = thread_rng();
    let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10).collect::<String>());
    let n = OsString::from(n);
    assert!(var_os(&n).is_none());
    n
}

fn eq(a: Option<OsString>, b: Option<&str>) {
    assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s));
}

#[test]
fn test_set_var() {
    let n = make_rand_name();
    set_var(&n, "VALUE");
    eq(var_os(&n), Some("VALUE"));
}

#[test]
fn test_remove_var() {
    let n = make_rand_name();
    set_var(&n, "VALUE");
    remove_var(&n);
    eq(var_os(&n), None);
}

#[test]
fn test_set_var_overwrite() {
    let n = make_rand_name();
    set_var(&n, "1");
    set_var(&n, "2");
    eq(var_os(&n), Some("2"));
    set_var(&n, "");
    eq(var_os(&n), Some(""));
}

#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_var_big() {
    let mut s = "".to_string();
    let mut i = 0;
    while i < 100 {
        s.push_str("aaaaaaaaaa");
        i += 1;
    }
    let n = make_rand_name();
    set_var(&n, &s);
    eq(var_os(&n), Some(&s));
}

#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_env_set_get_huge() {
    let n = make_rand_name();
    let s = "x".repeat(10000);
    set_var(&n, &s);
    eq(var_os(&n), Some(&s));
    remove_var(&n);
    eq(var_os(&n), None);
}

#[test]
fn test_env_set_var() {
    let n = make_rand_name();

    let mut e = vars_os();
    set_var(&n, "VALUE");
    assert!(!e.any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));

    assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
}

#[test]
#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))]
#[allow(deprecated)]
fn env_home_dir() {
    use std::path::PathBuf;

    fn var_to_os_string(var: Result<String, VarError>) -> Option<OsString> {
        match var {
            Ok(var) => Some(OsString::from(var)),
            Err(VarError::NotUnicode(var)) => Some(var),
            _ => None,
        }
    }

    cfg_if::cfg_if! {
        if #[cfg(unix)] {
            let oldhome = var_to_os_string(var("HOME"));

            set_var("HOME", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");
            if cfg!(target_os = "android") {
                assert!(home_dir().is_none());
            } else {
                // When HOME is not set, some platforms return `None`,
                // but others return `Some` with a default.
                // Just check that it is not "/home/MountainView".
                assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
            }

            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
        } else if #[cfg(windows)] {
            let oldhome = var_to_os_string(var("HOME"));
            let olduserprofile = var_to_os_string(var("USERPROFILE"));

            remove_var("HOME");
            remove_var("USERPROFILE");

            assert!(home_dir().is_some());

            set_var("HOME", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");

            set_var("USERPROFILE", "/home/MountainView");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            set_var("HOME", "/home/MountainView");
            set_var("USERPROFILE", "/home/PaloAlto");
            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));

            remove_var("HOME");
            remove_var("USERPROFILE");

            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
            if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{size_t, c_int, c_ushort,c_void};
use libc::types::os::arch::c95::wchar_t;
use mem::{new0,newarray0,delete,deletearray};
use std::mem;
use std::ptr;
use std::slice;
use std::string;
use std::str;
use types::{cef_string_utf16_t, cef_string_utf8_t, cef_string_wide_t};
use types::{cef_string_userfree_utf16_t, cef_string_userfree_utf8_t, cef_string_userfree_wide_t};

//cef_string

#[no_mangle]
extern "C" fn string_wide_dtor(str: *mut wchar_t) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf8_dtor(str: *mut u8) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf16_dtor(str: *mut c_ushort) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_free(cs: *mut cef_string_userfree_wide_t) {
   cef_string_wide_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf8_t) {
   cef_string_utf8_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) {
   cef_string_utf16_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_clear(cs: *mut cef_string_utf8_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut u8;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_alloc() -> *mut cef_string_utf8_t {
    #![inline(never)]
    new0::<cef_string_utf8_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_set(src: *const u8, src_len: size_t, output: *mut cef_string_utf8_t, copy: c_int) -> c_int {
    cef_string_utf8_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<u8>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_utf8_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_utf16(src: *const u8, src_len: size_t, output: *mut cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |result| {
            match str::from_utf8(result) {
                 Some(enc) => {
                      let conv = enc.utf16_units().collect::<Vec<u16>>();
                      cef_string_utf16_set(conv.as_ptr(), conv.len() as size_t, output, 1);
                      1
                 },
                 None => 0
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_to_utf8(src: *const u16, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |ustr| {
            match string::String::from_utf16(ustr) {
                Some(str) => {
                    cef_string_utf8_set(str.as_bytes().as_ptr(), str.len() as size_t, output, 1);
                    1 as c_int
                },
                None =>  0 as c_int
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_clear(cs: *mut cef_string_utf16_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut c_ushort;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_alloc() -> *mut cef_string_utf16_t {
    #![inline(never)]
    new0::<cef_string_utf16_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_set(src: *const c_ushort, src_len: size_t, output: *mut cef_string_utf16_t, copy: c_int) -> c_int {
    cef_string_utf16_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<c_ushort>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_utf16_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_cmp(a: *const cef_string_utf16_t, b: *const cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(mem::transmute((*a).str), (*a).length as uint, |astr:&[u16]| {
            slice::raw::buf_as_slice(mem::transmute((*b).str), (*b).length as uint, |bstr:&[u16]| {
                  match astr.cmp(&bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_wide_clear(cs: *mut cef_string_wide_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut wchar_t;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_alloc() -> *mut cef_string_wide_t {
    #![inline(never)]
    new0::<cef_string_wide_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_wide_set(src: *const wchar_t, src_len: size_t, output: *mut cef_string_wide_t, copy: c_int) -> c_int {
    cef_string_wide_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<wchar_t>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_wide_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}
<commit_msg>embedding: cef_string_utf8_cmp()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{size_t, c_int, c_ushort,c_void};
use libc::types::os::arch::c95::wchar_t;
use mem::{new0,newarray0,delete,deletearray};
use std::mem;
use std::ptr;
use std::slice;
use std::string;
use std::str;
use types::{cef_string_utf16_t, cef_string_utf8_t, cef_string_wide_t};
use types::{cef_string_userfree_utf16_t, cef_string_userfree_utf8_t, cef_string_userfree_wide_t};

//cef_string

#[no_mangle]
extern "C" fn string_wide_dtor(str: *mut wchar_t) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf8_dtor(str: *mut u8) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf16_dtor(str: *mut c_ushort) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_free(cs: *mut cef_string_userfree_wide_t) {
   cef_string_wide_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf8_t) {
   cef_string_utf8_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) {
   cef_string_utf16_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_clear(cs: *mut cef_string_utf8_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut u8;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_alloc() -> *mut cef_string_utf8_t {
    #![inline(never)]
    new0::<cef_string_utf8_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_set(src: *const u8, src_len: size_t, output: *mut cef_string_utf8_t, copy: c_int) -> c_int {
    cef_string_utf8_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<u8>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_utf8_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_cmp(a: *const cef_string_utf8_t, b: *const cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(mem::transmute((*a).str), (*a).length as uint, |astr:&[u8]| {
            slice::raw::buf_as_slice(mem::transmute((*b).str), (*b).length as uint, |bstr:&[u8]| {
                  match astr.cmp(&bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_utf16(src: *const u8, src_len: size_t, output: *mut cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |result| {
            match str::from_utf8(result) {
                 Some(enc) => {
                      let conv = enc.utf16_units().collect::<Vec<u16>>();
                      cef_string_utf16_set(conv.as_ptr(), conv.len() as size_t, output, 1);
                      1
                 },
                 None => 0
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_to_utf8(src: *const u16, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |ustr| {
            match string::String::from_utf16(ustr) {
                Some(str) => {
                    cef_string_utf8_set(str.as_bytes().as_ptr(), str.len() as size_t, output, 1);
                    1 as c_int
                },
                None =>  0 as c_int
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_clear(cs: *mut cef_string_utf16_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut c_ushort;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_alloc() -> *mut cef_string_utf16_t {
    #![inline(never)]
    new0::<cef_string_utf16_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_set(src: *const c_ushort, src_len: size_t, output: *mut cef_string_utf16_t, copy: c_int) -> c_int {
    cef_string_utf16_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<c_ushort>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_utf16_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_cmp(a: *const cef_string_utf16_t, b: *const cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(mem::transmute((*a).str), (*a).length as uint, |astr:&[u16]| {
            slice::raw::buf_as_slice(mem::transmute((*b).str), (*b).length as uint, |bstr:&[u16]| {
                  match astr.cmp(&bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_wide_clear(cs: *mut cef_string_wide_t) {
    unsafe {
        if !fptr_is_null(mem::transmute((*cs).dtor)) {
            let dtor = (*cs).dtor;
            dtor((*cs).str);
        }
        (*cs).length = 0;
        (*cs).str = 0 as *mut wchar_t;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_alloc() -> *mut cef_string_wide_t {
    #![inline(never)]
    new0::<cef_string_wide_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_wide_set(src: *const wchar_t, src_len: size_t, output: *mut cef_string_wide_t, copy: c_int) -> c_int {
    cef_string_wide_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<wchar_t>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = string_wide_dtor;
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate iron;
extern crate persistent;
#[macro_use]
extern crate potboiler_common;
extern crate logger;
extern crate serde_json;
extern crate serde;
extern crate hyper;
extern crate router;
extern crate uuid;

use iron::modifiers::Redirect;
use iron::prelude::{Chain, Iron, IronError, IronResult, Request, Response};
use iron::status;
use logger::Logger;
use persistent::Read as PRead;
use potboiler_common::db;
use potboiler_common::string_error::StringError;
use potboiler_common::types::Log;
use serde_json::{Map, Value};
use std::env;
use std::ops::Deref;
use types::QueueOperation;
use uuid::Uuid;

mod types;

pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
    static ref HOST: String = env::var("HOST").expect("Needed HOST");
}

fn iron_str_error<T: std::error::Error + std::marker::Send + 'static>(se: T) -> iron::IronError {
    let desc = format!("{:?}", se);
    return IronError::new(se, (status::BadRequest, desc));
}

fn string_from_body<T: std::io::Read>(body: &mut T) -> IronResult<String> {
    let mut result = String::new();
    try!(body.read_to_string(&mut result).map_err(iron_str_error));
    Ok(result)
}

fn json_from_body(req: &mut Request) -> IronResult<Value> {
    let body_string = try!(string_from_body(&mut req.body));
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    return Ok(json);
}

fn add_queue_operation(op: QueueOperation) -> IronResult<String> {
    let client = hyper::client::Client::new();
    let mut res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&op).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    let data = try!(string_from_body(&mut res));
    Ok(data)
}

fn create_queue(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let op = try!(serde_json::from_value::<types::QueueCreate>(json).map_err(iron_str_error));
    let name = op.name.clone();
    match add_queue_operation(QueueOperation::Create(op)) {
        Ok(_) => {
            let new_url = format!("http://{}:8000/queue/{}", HOST.deref(), &name);
            Ok(Response::with((status::Created,
                               Redirect(iron::Url::parse(&new_url).expect("URL parsed ok")))))
        }
        Err(val) => Err(val),
    }
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let log = try!(serde_json::from_value::<Log>(json).map_err(iron_str_error));
    info!("body: {:?}", log);
    let op = try!(serde_json::from_value::<QueueOperation>(log.data).map_err(iron_str_error));
    info!("op: {:?}", op);
    let conn = get_pg_connection!(&req);
    match op {
        QueueOperation::Create(create) => {
            info!("create: {:?}", create);
            let trans = conn.transaction().unwrap();
            let qc = types::QueueConfig { timeout_ms: create.timeout_ms };
            trans.execute("INSERT INTO queues (key, config) VALUES($1, $2)",
                         &[&create.name, &serde_json::to_value(&qc)])
                .unwrap();
            trans.execute(&format!("CREATE TABLE IF NOT EXISTS {} (id UUID PRIMARY KEY, task_name \
                                   VARCHAR(2083), state VARCHAR(8), info JSONB)",
                                  &create.name),
                         &[])
                .expect("make particular queue table worked");
            trans.commit().unwrap();
        }
        QueueOperation::Add(add) => {
            info!("add: {:?}", add);
            conn.execute(&format!("INSERT INTO {} (id, task_name, state, info) VALUES($1, $2, $3, $4)",
                                  add.queue_name),
                         &[&log.id,
                           &add.task_name,
                           &String::from("pending"),
                           &serde_json::to_value(&add.data)])
                .unwrap();
        }
        _ => {}
    };
    Ok(Response::with(status::NoContent))
}

fn get_queue_name(req: &mut Request) -> IronResult<String> {
    Ok(try!(potboiler_common::get_req_key(req, "queue_name")
        .ok_or(iron_str_error(StringError::from("No queue_name")))))
}

fn get_queue_items(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let queue_name = try!(get_queue_name(req));
    let results = try!(conn.query(&format!("select id, task_name, state from {}", &queue_name),
               &[])
        .map_err(iron_str_error));
    let mut queue = Map::new();
    for row in &results {
        let id: Uuid = row.get("id");
        let raw_state: String = row.get("state");
        let item = types::QueueListItem {
            task_name: row.get("task_name"),
            // FIXME: format! bit is a hacky workaround for https://github.com/serde-rs/serde/issues/251
            state: serde_json::from_str(&format!("\"{}\"", raw_state)).unwrap(),
        };
        queue.insert(id.to_string(), serde_json::to_value(&item));
    }
    let value = Value::Object(queue);
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
}

fn add_queue_item(req: &mut Request) -> IronResult<Response> {
    let mut json = try!(json_from_body(req));
    {
        let queue_name = try!(get_queue_name(req));
        let map = json.as_object_mut().unwrap();
        map.insert("queue_name".to_string(), serde_json::to_value(&queue_name));
    }
    let op = try!(serde_json::from_value::<types::QueueAdd>(json).map_err(iron_str_error));
    match add_queue_operation(QueueOperation::Add(op)) {
        Ok(_) => Ok(Response::with(status::Created)),
        Err(val) => Err(val),
    }
}

fn make_queue_table(conn: &PostgresConnection) {
    conn.execute("CREATE TABLE IF NOT EXISTS queues (key VARCHAR(1024) PRIMARY KEY, config JSONB)",
                 &[])
        .expect("make queue table worked");
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    map.insert("url".to_string(),
               format!("http://{}:8000/event", HOST.deref()).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_queue_table(&conn);
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = router::Router::new();
    router.post("/create", create_queue);
    router.post("/event", new_event);
    router.get("/queue/:queue_name", get_queue_items);
    router.post("/queue/:queue_name", add_queue_item);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Pigtail booted");
    Iron::new(chain).http("0.0.0.0:8000").unwrap();
}
<commit_msg>Add "get single item" to Pigtail<commit_after>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate postgres;
extern crate iron;
extern crate persistent;
#[macro_use]
extern crate potboiler_common;
extern crate logger;
extern crate serde_json;
extern crate serde;
extern crate hyper;
extern crate router;
extern crate uuid;

use iron::modifiers::Redirect;
use iron::prelude::{Chain, Iron, IronError, IronResult, Request, Response};
use iron::status;
use logger::Logger;
use persistent::Read as PRead;
use potboiler_common::db;
use potboiler_common::string_error::StringError;
use potboiler_common::types::Log;
use serde_json::{Map, Value};
use std::env;
use std::ops::Deref;
use types::QueueOperation;
use uuid::Uuid;

mod types;

pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
    static ref HOST: String = env::var("HOST").expect("Needed HOST");
}

fn iron_str_error<T: std::error::Error + std::marker::Send + 'static>(se: T) -> iron::IronError {
    let desc = format!("{:?}", se);
    return IronError::new(se, (status::BadRequest, desc));
}

fn string_from_body<T: std::io::Read>(body: &mut T) -> IronResult<String> {
    let mut result = String::new();
    try!(body.read_to_string(&mut result).map_err(iron_str_error));
    Ok(result)
}

fn json_from_body(req: &mut Request) -> IronResult<Value> {
    let body_string = try!(string_from_body(&mut req.body));
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    return Ok(json);
}

fn add_queue_operation(op: QueueOperation) -> IronResult<String> {
    let client = hyper::client::Client::new();
    let mut res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&op).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    let data = try!(string_from_body(&mut res));
    Ok(data)
}

fn create_queue(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let op = try!(serde_json::from_value::<types::QueueCreate>(json).map_err(iron_str_error));
    let name = op.name.clone();
    match add_queue_operation(QueueOperation::Create(op)) {
        Ok(_) => {
            let new_url = format!("http://{}:8000/queue/{}", HOST.deref(), &name);
            Ok(Response::with((status::Created,
                               Redirect(iron::Url::parse(&new_url).expect("URL parsed ok")))))
        }
        Err(val) => Err(val),
    }
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let json = try!(json_from_body(req));
    let log = try!(serde_json::from_value::<Log>(json).map_err(iron_str_error));
    info!("body: {:?}", log);
    let op = try!(serde_json::from_value::<QueueOperation>(log.data).map_err(iron_str_error));
    info!("op: {:?}", op);
    let conn = get_pg_connection!(&req);
    match op {
        QueueOperation::Create(create) => {
            info!("create: {:?}", create);
            let trans = conn.transaction().unwrap();
            let qc = types::QueueConfig { timeout_ms: create.timeout_ms };
            trans.execute("INSERT INTO queues (key, config) VALUES($1, $2)",
                         &[&create.name, &serde_json::to_value(&qc)])
                .unwrap();
            trans.execute(&format!("CREATE TABLE IF NOT EXISTS {} (id UUID PRIMARY KEY, task_name \
                                   VARCHAR(2083), state VARCHAR(8), info JSONB)",
                                  &create.name),
                         &[])
                .expect("make particular queue table worked");
            trans.commit().unwrap();
        }
        QueueOperation::Add(add) => {
            info!("add: {:?}", add);
            conn.execute(&format!("INSERT INTO {} (id, task_name, state, info) VALUES($1, $2, $3, $4)",
                                  add.queue_name),
                         &[&log.id,
                           &add.task_name,
                           &String::from("pending"),
                           &serde_json::to_value(&add.data)])
                .unwrap();
        }
        _ => {}
    };
    Ok(Response::with(status::NoContent))
}

fn get_req_key_with_iron_err(req: &mut Request, key: &str) -> IronResult<String> {
    Ok(try!(potboiler_common::get_req_key(req, key)
        .ok_or(iron_str_error(StringError::from(format!("No {}", key))))))
}

fn get_queue_name(req: &mut Request) -> IronResult<String> {
    get_req_key_with_iron_err(req, "queue_name")
}

fn row_to_queue_item(row: postgres::rows::Row) -> types::QueueListItem {
    let raw_state: String = row.get("state");
    return types::QueueListItem {
        task_name: row.get("task_name"),
        // FIXME: format! bit is a hacky workaround for https://github.com/serde-rs/serde/issues/251
        state: serde_json::from_str(&format!("\"{}\"", raw_state)).unwrap(),
    };
}

fn get_queue_items(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let queue_name = try!(get_queue_name(req));
    let results = try!(conn.query(&format!("select id, task_name, state from {}", &queue_name),
               &[])
        .map_err(iron_str_error));
    let mut queue = Map::new();
    for row in &results {
        let id: Uuid = row.get("id");
        let item = row_to_queue_item(row);
        queue.insert(id.to_string(), serde_json::to_value(&item));
    }
    let value = Value::Object(queue);
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
}

fn get_queue_item(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let queue_name = try!(get_queue_name(req));
    let id: Uuid = try!(Uuid::parse_str(&try!(get_req_key_with_iron_err(req, "id"))).map_err(iron_str_error));
    let results = try!(conn.query(&format!("select task_name, state from {} where id=$1", &queue_name),
               &[&id])
        .map_err(iron_str_error));
    if results.is_empty() {
        Ok(Response::with((status::NotFound, format!("No queue item {} in {}", id, queue_name))))
    } else {
        let row = results.get(0);
        let item = row_to_queue_item(row);
        Ok(Response::with((status::Ok, serde_json::to_string(&item).unwrap())))
    }
}

fn add_queue_item(req: &mut Request) -> IronResult<Response> {
    let mut json = try!(json_from_body(req));
    {
        let queue_name = try!(get_queue_name(req));
        let map = json.as_object_mut().unwrap();
        map.insert("queue_name".to_string(), serde_json::to_value(&queue_name));
    }
    let op = try!(serde_json::from_value::<types::QueueAdd>(json).map_err(iron_str_error));
    match add_queue_operation(QueueOperation::Add(op)) {
        Ok(_) => Ok(Response::with(status::Created)),
        Err(val) => Err(val),
    }
}

fn make_queue_table(conn: &PostgresConnection) {
    conn.execute("CREATE TABLE IF NOT EXISTS queues (key VARCHAR(1024) PRIMARY KEY, config JSONB)",
                 &[])
        .expect("make queue table worked");
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    map.insert("url".to_string(),
               format!("http://{}:8000/event", HOST.deref()).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_queue_table(&conn);
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = router::Router::new();
    router.post("/create", create_queue);
    router.post("/event", new_event);
    router.get("/queue/:queue_name", get_queue_items);
    router.get("/queue/:queue_name/:id", get_queue_item);
    router.post("/queue/:queue_name", add_queue_item);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Pigtail booted");
    Iron::new(chain).http("0.0.0.0:8000").unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use fd::var::*;
use propagator::*;
use propagator::Status::*;

pub struct EqualXY {
  x: FDVar,
  y: FDVar
}

impl EqualXY {
  pub fn new(x: FDVar, y: FDVar) -> EqualXY {
    EqualXY { x: x, y: y }
  }
}

impl Propagator for EqualXY {
  type Event = FDEvent;

  fn status(&self) -> Status {
    // Disentailed:
    // |--|
    //     |--|
    //
    // Entailed:
    // |-|
    // |-|
    //
    // Unknown: Everything else.

    if FDVar::is_disjoint(&self.x, &self.y) {
      Disentailed
    }
    else if self.x.lb() == self.y.ub() && self.x.ub() == self.y.lb() {
      Entailed
    }
    else {
      Unknown
    }
  }

  fn propagate(&mut self) -> Vec<(u32, <EqualXY as Propagator>::Event)> {
    FDVar::intersection(&mut self.x, &mut self.y)
  }
}

pub struct XLessThanY {
  x: FDVar,
  y: FDVar
}

impl XLessThanY {
  pub fn new(x: FDVar, y: FDVar) -> XLessThanY {
    XLessThanY { x: x, y: y }
  }
}

impl Propagator for XLessThanY {
  type Event = FDEvent;

  fn status(&self) -> Status {
    // Disentailed:
    //     |--|
    // |--|
    //
    // Entailed:
    // |--|
    //     |--|
    //
    // Unknown: Everything else.

    if self.x.is_failed() || self.y.is_failed() || self.x.lb() > self.y.ub() {
      Disentailed
    }
    else if self.x.ub() < self.y.lb() {
      Entailed
    }
    else {
      Unknown
    }
  }

  fn propagate(&mut self) -> Vec<(u32, <XLessThanY as Propagator>::Event)> {
    let mut events = vec![];
    if self.x.is_failed() { self.y.failed(&mut events); }
    else if self.y.is_failed() { self.x.failed(&mut events); }
    else if self.x.ub() >= self.y.ub() {
      self.x.update_ub(self.y.ub() - 1, &mut events);
    }
    if self.x.lb() >= self.y.lb() {
      self.y.update_lb(self.x.lb() + 1, &mut events);
    }
    events
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use fd::var::*;
  use fd::var::FDEvent::*;
  use propagator::Status::*;
  use propagator::*;

  #[test]
  fn equalxy_propagate_test() {
    let empty = FDVar::new(0, Interval::empty());
    let var0_10 = FDVar::new(1, (0,10).to_interval());
    let var10_20 = FDVar::new(2, (10,20).to_interval());
    let var5_15 = FDVar::new(3, (5,15).to_interval());
    let var11_20 = FDVar::new(4, (11,20).to_interval());
    let var1_1 = FDVar::new(5, (1,1).to_interval());

    equalxy_propagate_test_one(var0_10, var10_20, Unknown, Entailed, vec![(1, Assignment), (2, Assignment)]);
    equalxy_propagate_test_one(var5_15, var10_20, Unknown, Unknown, vec![(3, Bound), (2, Bound)]);
    equalxy_propagate_test_one(var1_1, var0_10, Unknown, Entailed, vec![(1, Assignment)]);
    equalxy_propagate_test_one(var0_10, var0_10, Unknown, Unknown, vec![]);
    equalxy_propagate_test_one(var0_10, empty, Disentailed, Disentailed, vec![(1, Failure)]);
    equalxy_propagate_test_one(var1_1, empty, Disentailed, Disentailed, vec![(5, Failure)]);
    equalxy_propagate_test_one(var0_10, var11_20, Disentailed, Disentailed, vec![(1, Failure), (4, Failure)]);
  }

  fn equalxy_propagate_test_one(v1: FDVar, v2: FDVar, before: Status, after: Status, expected: Vec<(u32, FDEvent)>) {
    let propagator = EqualXY::new(v1, v2);
    propagate_test_one(propagator, before, after, expected);
  }

  #[test]
  fn xlessy_propagate_test() {
    let empty = FDVar::new(0, Interval::empty());
    let var0_10 = FDVar::new(1, (0,10).to_interval());
    let var10_20 = FDVar::new(2, (10,20).to_interval());
    let var5_15 = FDVar::new(3, (5,15).to_interval());
    let var11_20 = FDVar::new(4, (11,20).to_interval());
    let var1_1 = FDVar::new(5, (1,1).to_interval());

    xlessy_propagate_test_one(var0_10, var10_20, Unknown, Unknown, vec![]);
    xlessy_propagate_test_one(var5_15, var10_20, Unknown, Unknown, vec![]);
    xlessy_propagate_test_one(var5_15, var0_10, Unknown, Unknown, vec![(3, Bound), (1, Bound)]);
    xlessy_propagate_test_one(var0_10, var11_20, Entailed, Entailed, vec![]);
    xlessy_propagate_test_one(var11_20, var0_10, Disentailed, Disentailed, vec![(4, Failure), (1, Failure)]);
    xlessy_propagate_test_one(var1_1, var0_10, Unknown, Entailed, vec![(1, Bound)]);
    xlessy_propagate_test_one(empty, var0_10, Disentailed, Disentailed, vec![(1, Failure)]);
    xlessy_propagate_test_one(var0_10, empty, Disentailed, Disentailed, vec![(1, Failure)]);
  }

  fn xlessy_propagate_test_one(v1: FDVar, v2: FDVar, before: Status, after: Status, expected: Vec<(u32, FDEvent)>) {
    let propagator = XLessThanY::new(v1, v2);
    propagate_test_one(propagator, before, after, expected);
  }

  fn propagate_test_one<P: Propagator<Event=FDEvent>>(mut prop: P, before: Status, after: Status, expected: Vec<(u32, FDEvent)>) {
    assert_eq!(prop.status(), before);
    let events = prop.propagate();
    assert_eq!(events, expected);
    assert_eq!(prop.status(), after);
  }
}
<commit_msg>Rename propagator EqualXY to XEqualY.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use fd::var::*;
use propagator::*;
use propagator::Status::*;

pub struct XEqualY {
  x: FDVar,
  y: FDVar
}

impl XEqualY {
  pub fn new(x: FDVar, y: FDVar) -> XEqualY {
    XEqualY { x: x, y: y }
  }
}

impl Propagator for XEqualY {
  type Event = FDEvent;

  fn status(&self) -> Status {
    // Disentailed:
    // |--|
    //     |--|
    //
    // Entailed:
    // |-|
    // |-|
    //
    // Unknown: Everything else.

    if FDVar::is_disjoint(&self.x, &self.y) {
      Disentailed
    }
    else if self.x.lb() == self.y.ub() && self.x.ub() == self.y.lb() {
      Entailed
    }
    else {
      Unknown
    }
  }

  fn propagate(&mut self) -> Vec<(u32, <XEqualY as Propagator>::Event)> {
    FDVar::intersection(&mut self.x, &mut self.y)
  }
}

pub struct XLessThanY {
  x: FDVar,
  y: FDVar
}

impl XLessThanY {
  pub fn new(x: FDVar, y: FDVar) -> XLessThanY {
    XLessThanY { x: x, y: y }
  }
}

impl Propagator for XLessThanY {
  type Event = FDEvent;

  fn status(&self) -> Status {
    // Disentailed:
    //     |--|
    // |--|
    //
    // Entailed:
    // |--|
    //     |--|
    //
    // Unknown: Everything else.

    if self.x.is_failed() || self.y.is_failed() || self.x.lb() > self.y.ub() {
      Disentailed
    }
    else if self.x.ub() < self.y.lb() {
      Entailed
    }
    else {
      Unknown
    }
  }

  fn propagate(&mut self) -> Vec<(u32, <XLessThanY as Propagator>::Event)> {
    let mut events = vec![];
    if self.x.is_failed() { self.y.failed(&mut events); }
    else if self.y.is_failed() { self.x.failed(&mut events); }
    else if self.x.ub() >= self.y.ub() {
      self.x.update_ub(self.y.ub() - 1, &mut events);
    }
    if self.x.lb() >= self.y.lb() {
      self.y.update_lb(self.x.lb() + 1, &mut events);
    }
    events
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use fd::var::*;
  use fd::var::FDEvent::*;
  use propagator::Status::*;
  use propagator::*;

  #[test]
  fn equalxy_propagate_test() {
    let empty = FDVar::new(0, Interval::empty());
    let var0_10 = FDVar::new(1, (0,10).to_interval());
    let var10_20 = FDVar::new(2, (10,20).to_interval());
    let var5_15 = FDVar::new(3, (5,15).to_interval());
    let var11_20 = FDVar::new(4, (11,20).to_interval());
    let var1_1 = FDVar::new(5, (1,1).to_interval());

    xequaly_propagate_test_one(var0_10, var10_20, Unknown, Entailed, vec![(1, Assignment), (2, Assignment)]);
    xequaly_propagate_test_one(var5_15, var10_20, Unknown, Unknown, vec![(3, Bound), (2, Bound)]);
    xequaly_propagate_test_one(var1_1, var0_10, Unknown, Entailed, vec![(1, Assignment)]);
    xequaly_propagate_test_one(var0_10, var0_10, Unknown, Unknown, vec![]);
    xequaly_propagate_test_one(var0_10, empty, Disentailed, Disentailed, vec![(1, Failure)]);
    xequaly_propagate_test_one(var1_1, empty, Disentailed, Disentailed, vec![(5, Failure)]);
    xequaly_propagate_test_one(var0_10, var11_20, Disentailed, Disentailed, vec![(1, Failure), (4, Failure)]);
  }

  fn xequaly_propagate_test_one(v1: FDVar, v2: FDVar, before: Status, after: Status, expected: Vec<(u32, FDEvent)>) {
    let propagator = XEqualY::new(v1, v2);
    propagate_test_one(propagator, before, after, expected);
  }

  #[test]
  fn xlessy_propagate_test() {
    let empty = FDVar::new(0, Interval::empty());
    let var0_10 = FDVar::new(1, (0,10).to_interval());
    let var10_20 = FDVar::new(2, (10,20).to_interval());
    let var5_15 = FDVar::new(3, (5,15).to_interval());
    let var11_20 = FDVar::new(4, (11,20).to_interval());
    let var1_1 = FDVar::new(5, (1,1).to_interval());

    xlessy_propagate_test_one(var0_10, var10_20, Unknown, Unknown, vec![]);
    xlessy_propagate_test_one(var5_15, var10_20, Unknown, Unknown, vec![]);
    xlessy_propagate_test_one(var5_15, var0_10, Unknown, Unknown, vec![(3, Bound), (1, Bound)]);
    xlessy_propagate_test_one(var0_10, var11_20, Entailed, Entailed, vec![]);
    xlessy_propagate_test_one(var11_20, var0_10, Disentailed, Disentailed, vec![(4, Failure), (1, Failure)]);
    xlessy_propagate_test_one(var1_1, var0_10, Unknown, Entailed, vec![(1, Bound)]);
    xlessy_propagate_test_one(empty, var0_10, Disentailed, Disentailed, vec![(1, Failure)]);
    xlessy_propagate_test_one(var0_10, empty, Disentailed, Disentailed, vec![(1, Failure)]);
  }

  fn xlessy_propagate_test_one(v1: FDVar, v2: FDVar, before: Status, after: Status, expected: Vec<(u32, FDEvent)>) {
    let propagator = XLessThanY::new(v1, v2);
    propagate_test_one(propagator, before, after, expected);
  }

  fn propagate_test_one<P>(mut prop: P, before: Status, after: Status, expected: Vec<(u32, FDEvent)>)
   where P: Propagator<Event=FDEvent> {
    assert_eq!(prop.status(), before);
    let events = prop.propagate();
    assert_eq!(events, expected);
    assert_eq!(prop.status(), after);
  }
}
<|endoftext|>


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

use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::net::ip::IpAddr;
use rt::io::{Reader, Writer, Listener};
use rt::io::{io_error, read_error, EndOfFile};
use rt::rtio::{IoFactory, IoFactoryObject,
               RtioTcpListener, RtioTcpListenerObject,
               RtioTcpStream, RtioTcpStreamObject};
use rt::local::Local;

pub struct TcpStream {
    rtstream: ~RtioTcpStreamObject
}

impl TcpStream {
    fn new(s: ~RtioTcpStreamObject) -> TcpStream {
        TcpStream {
            rtstream: s
        }
    }

    pub fn connect(addr: IpAddr) -> Option<TcpStream> {
        let stream = unsafe {
            rtdebug!("borrowing io to connect");
            let io = Local::unsafe_borrow::<IoFactoryObject>();
            rtdebug!("about to connect");
            (*io).tcp_connect(addr)
        };

        match stream {
            Ok(s) => {
                Some(TcpStream::new(s))
            }
            Err(ioerr) => {
                rtdebug!("failed to connect: %?", ioerr);
                io_error::cond.raise(ioerr);
                return None;
            }
        }
    }
}

impl Reader for TcpStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let bytes_read = self.rtstream.read(buf);
        match bytes_read {
            Ok(read) => Some(read),
            Err(ioerr) => {
                // EOF is indicated by returning None
                if ioerr.kind != EndOfFile {
                    read_error::cond.raise(ioerr);
                }
                return None;
            }
        }
    }

    fn eof(&mut self) -> bool { fail!() }
}

impl Writer for TcpStream {
    fn write(&mut self, buf: &[u8]) {
        let res = self.rtstream.write(buf);
        match res {
            Ok(_) => (),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
            }
        }
    }

    fn flush(&mut self) { fail!() }
}

pub struct TcpListener {
    rtlistener: ~RtioTcpListenerObject,
}

impl TcpListener {
    pub fn bind(addr: IpAddr) -> Option<TcpListener> {
        let listener = unsafe {
            let io = Local::unsafe_borrow::<IoFactoryObject>();
            (*io).tcp_bind(addr)
        };
        match listener {
            Ok(l) => {
                Some(TcpListener {
                    rtlistener: l
                })
            }
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                return None;
            }
        }
    }
}

impl Listener<TcpStream> for TcpListener {
    fn accept(&mut self) -> Option<TcpStream> {
        let rtstream = self.rtlistener.accept();
        match rtstream {
            Ok(s) => {
                Some(TcpStream::new(s))
            }
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                return None;
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use int;
    use cell::Cell;
    use rt::test::*;
    use rt::io::net::ip::Ipv4;
    use rt::io::*;

    #[test] #[ignore]
    fn bind_error() {
        do run_in_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == PermissionDenied);
                called = true;
            }).in {
                let addr = Ipv4(0, 0, 0, 0, 1);
                let listener = TcpListener::bind(addr);
                assert!(listener.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn connect_error() {
        do run_in_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == ConnectionRefused);
                called = true;
            }).in {
                let addr = Ipv4(0, 0, 0, 0, 1);
                let stream = TcpStream::connect(addr);
                assert!(stream.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn smoke_test() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                stream.read(buf);
                assert!(buf[0] == 99);
            }

            do spawntask_immediately {
                let mut stream = TcpStream::connect(addr);
                stream.write([99]);
            }
        }
    }

    #[test]
    fn read_eof() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                let nread = stream.read(buf);
                assert!(nread.is_none());
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn read_eof_twice() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                let nread = stream.read(buf);
                assert!(nread.is_none());
                let nread = stream.read(buf);
                assert!(nread.is_none());
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn write_close() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let buf = [0];
                loop {
                    let mut stop = false;
                    do io_error::cond.trap(|e| {
                        // NB: ECONNRESET on linux, EPIPE on mac
                        assert!(e.kind == ConnectionReset || e.kind == BrokenPipe);
                        stop = true;
                    }).in {
                        stream.write(buf);
                    }
                    if stop { break }
                }
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn multiple_connect_serial() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            let max = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for max.times {
                    let mut stream = listener.accept();
                    let mut buf = [0];
                    stream.read(buf);
                    assert_eq!(buf[0], 99);
                }
            }

            do spawntask_immediately {
                for max.times {
                    let mut stream = TcpStream::connect(addr);
                    stream.write([99]);
                }
            }
        }
    }

    #[test]
    fn multiple_connect_interleaved_greedy_schedule() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            static MAX: int = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for int::range(0, MAX) |i| {
                    let stream = Cell::new(listener.accept());
                    rtdebug!("accepted");
                    // Start another task to handle the connection
                    do spawntask_immediately {
                        let mut stream = stream.take();
                        let mut buf = [0];
                        stream.read(buf);
                        assert!(buf[0] == i as u8);
                        rtdebug!("read");
                    }
                }
            }

            connect(0, addr);

            fn connect(i: int, addr: IpAddr) {
                if i == MAX { return }

                do spawntask_immediately {
                    rtdebug!("connecting");
                    let mut stream = TcpStream::connect(addr);
                    // Connect again before writing
                    connect(i + 1, addr);
                    rtdebug!("writing");
                    stream.write([i as u8]);
                }
            }
        }
    }

    #[test]
    fn multiple_connect_interleaved_lazy_schedule() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            static MAX: int = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for int::range(0, MAX) |_| {
                    let stream = Cell::new(listener.accept());
                    rtdebug!("accepted");
                    // Start another task to handle the connection
                    do spawntask_later {
                        let mut stream = stream.take();
                        let mut buf = [0];
                        stream.read(buf);
                        assert!(buf[0] == 99);
                        rtdebug!("read");
                    }
                }
            }

            connect(0, addr);

            fn connect(i: int, addr: IpAddr) {
                if i == MAX { return }

                do spawntask_later {
                    rtdebug!("connecting");
                    let mut stream = TcpStream::connect(addr);
                    // Connect again before writing
                    connect(i + 1, addr);
                    rtdebug!("writing");
                    stream.write([99]);
                }
            }
        }
    }

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

use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::net::ip::IpAddr;
use rt::io::{Reader, Writer, Listener};
use rt::io::{io_error, read_error, EndOfFile};
use rt::rtio::{IoFactory, IoFactoryObject,
               RtioTcpListener, RtioTcpListenerObject,
               RtioTcpStream, RtioTcpStreamObject};
use rt::local::Local;

pub struct TcpStream(~RtioTcpStreamObject);

impl TcpStream {
    fn new(s: ~RtioTcpStreamObject) -> TcpStream {
        TcpStream(s)
    }

    pub fn connect(addr: IpAddr) -> Option<TcpStream> {
        let stream = unsafe {
            rtdebug!("borrowing io to connect");
            let io = Local::unsafe_borrow::<IoFactoryObject>();
            rtdebug!("about to connect");
            (*io).tcp_connect(addr)
        };

        match stream {
            Ok(s) => Some(TcpStream::new(s)),
            Err(ioerr) => {
                rtdebug!("failed to connect: %?", ioerr);
                io_error::cond.raise(ioerr);
                None
            }
        }
    }
}

impl Reader for TcpStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        match (**self).read(buf) {
            Ok(read) => Some(read),
            Err(ioerr) => {
                // EOF is indicated by returning None
                if ioerr.kind != EndOfFile {
                    read_error::cond.raise(ioerr);
                }
                return None;
            }
        }
    }

    fn eof(&mut self) -> bool { fail!() }
}

impl Writer for TcpStream {
    fn write(&mut self, buf: &[u8]) {
        match (**self).write(buf) {
            Ok(_) => (),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
            }
        }
    }

    fn flush(&mut self) { fail!() }
}

pub struct TcpListener(~RtioTcpListenerObject);

impl TcpListener {
    pub fn bind(addr: IpAddr) -> Option<TcpListener> {
        let listener = unsafe {
            let io = Local::unsafe_borrow::<IoFactoryObject>();
            (*io).tcp_bind(addr)
        };
        match listener {
            Ok(l) => Some(TcpListener(l)),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                return None;
            }
        }
    }
}

impl Listener<TcpStream> for TcpListener {
    fn accept(&mut self) -> Option<TcpStream> {
        match (**self).accept() {
            Ok(s) => {
                Some(TcpStream::new(s))
            }
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                return None;
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use int;
    use cell::Cell;
    use rt::test::*;
    use rt::io::net::ip::Ipv4;
    use rt::io::*;

    #[test] #[ignore]
    fn bind_error() {
        do run_in_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == PermissionDenied);
                called = true;
            }).in {
                let addr = Ipv4(0, 0, 0, 0, 1);
                let listener = TcpListener::bind(addr);
                assert!(listener.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn connect_error() {
        do run_in_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == ConnectionRefused);
                called = true;
            }).in {
                let addr = Ipv4(0, 0, 0, 0, 1);
                let stream = TcpStream::connect(addr);
                assert!(stream.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn smoke_test() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                stream.read(buf);
                assert!(buf[0] == 99);
            }

            do spawntask_immediately {
                let mut stream = TcpStream::connect(addr);
                stream.write([99]);
            }
        }
    }

    #[test]
    fn read_eof() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                let nread = stream.read(buf);
                assert!(nread.is_none());
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn read_eof_twice() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let mut buf = [0];
                let nread = stream.read(buf);
                assert!(nread.is_none());
                let nread = stream.read(buf);
                assert!(nread.is_none());
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn write_close() {
        do run_in_newsched_task {
            let addr = next_test_ip4();

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                let mut stream = listener.accept();
                let buf = [0];
                loop {
                    let mut stop = false;
                    do io_error::cond.trap(|e| {
                        // NB: ECONNRESET on linux, EPIPE on mac
                        assert!(e.kind == ConnectionReset || e.kind == BrokenPipe);
                        stop = true;
                    }).in {
                        stream.write(buf);
                    }
                    if stop { break }
                }
            }

            do spawntask_immediately {
                let _stream = TcpStream::connect(addr);
                // Close
            }
        }
    }

    #[test]
    fn multiple_connect_serial() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            let max = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for max.times {
                    let mut stream = listener.accept();
                    let mut buf = [0];
                    stream.read(buf);
                    assert_eq!(buf[0], 99);
                }
            }

            do spawntask_immediately {
                for max.times {
                    let mut stream = TcpStream::connect(addr);
                    stream.write([99]);
                }
            }
        }
    }

    #[test]
    fn multiple_connect_interleaved_greedy_schedule() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            static MAX: int = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for int::range(0, MAX) |i| {
                    let stream = Cell::new(listener.accept());
                    rtdebug!("accepted");
                    // Start another task to handle the connection
                    do spawntask_immediately {
                        let mut stream = stream.take();
                        let mut buf = [0];
                        stream.read(buf);
                        assert!(buf[0] == i as u8);
                        rtdebug!("read");
                    }
                }
            }

            connect(0, addr);

            fn connect(i: int, addr: IpAddr) {
                if i == MAX { return }

                do spawntask_immediately {
                    rtdebug!("connecting");
                    let mut stream = TcpStream::connect(addr);
                    // Connect again before writing
                    connect(i + 1, addr);
                    rtdebug!("writing");
                    stream.write([i as u8]);
                }
            }
        }
    }

    #[test]
    fn multiple_connect_interleaved_lazy_schedule() {
        do run_in_newsched_task {
            let addr = next_test_ip4();
            static MAX: int = 10;

            do spawntask_immediately {
                let mut listener = TcpListener::bind(addr);
                for int::range(0, MAX) |_| {
                    let stream = Cell::new(listener.accept());
                    rtdebug!("accepted");
                    // Start another task to handle the connection
                    do spawntask_later {
                        let mut stream = stream.take();
                        let mut buf = [0];
                        stream.read(buf);
                        assert!(buf[0] == 99);
                        rtdebug!("read");
                    }
                }
            }

            connect(0, addr);

            fn connect(i: int, addr: IpAddr) {
                if i == MAX { return }

                do spawntask_later {
                    rtdebug!("connecting");
                    let mut stream = TcpStream::connect(addr);
                    // Connect again before writing
                    connect(i + 1, addr);
                    rtdebug!("writing");
                    stream.write([99]);
                }
            }
        }
    }

}
<|endoftext|>