<commit_before>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    /// Appends a character to the end of the string.
    pub fn push(&mut self, c: char) {
        self.0.push(c);
    }

    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }

    pub fn starts_with<'a, T: AsRef<UStr>>(&self, prefix: &'a T) -> bool {
        self.0.starts_with(&prefix.as_ref().0)
    }

    pub fn ends_with<'a, T: AsRef<UStr>>(&self, suffix: &'a T) -> bool {
        self.0.ends_with(&suffix.as_ref().0)
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<String> for UString {
    fn from(string: String) -> UString {
        UString(string.chars().collect())
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl From<char> for UString {
    fn from(c: char) -> UString {
        UString(vec![c])
    }
}

impl From<UString> for String {
    fn from(string: UString) -> String {
        String::from_iter(string)
    }
}

impl<'a> From<&'a UString> for String {
    fn from(string: &UString) -> String {
        String::from_iter(string.into_iter().cloned())
    }
}

impl<'a> From<&'a UStr> for String {
    fn from(slice: &UStr) -> String {
        String::from_iter(slice.into_iter().cloned())
    }
}

impl<C: Into<char>> FromIterator<C> for UString {
    fn from_iter<T>(iterator: T) -> UString where T: IntoIterator<Item=C> {
        UString(iterator.into_iter().map(C::into).collect())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Iter<'a>(&'a [char]);

#[derive(Debug)]
pub struct IntoIter(Vec<char>);

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

    fn next(&mut self) -> Option<&'a char> {
        if self.0.len() > 0 {
            let result = &self.0[0];
            self.0 = &self.0[1..];
            Some(result)
        } else {
            None
        }
    }
}

impl Iterator for IntoIter {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.0.len() > 0 {
            Some(self.0.remove(0))
        } else {
            None
        }
    }
}

impl IntoIterator for UString {
    type Item = char;
    type IntoIter = IntoIter;

    fn into_iter(self) -> IntoIter {
        IntoIter(self.0)
    }
}

impl<'a> IntoIterator for &'a UString {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}

impl<'a> IntoIterator for &'a UStr {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}
<commit_msg>Add AsRef implementation<commit_after>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    /// Appends a character to the end of the string.
    pub fn push(&mut self, c: char) {
        self.0.push(c);
    }

    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }

    pub fn starts_with<'a, T: AsRef<UStr>>(&self, prefix: &'a T) -> bool {
        self.0.starts_with(&prefix.as_ref().0)
    }

    pub fn ends_with<'a, T: AsRef<UStr>>(&self, suffix: &'a T) -> bool {
        self.0.ends_with(&suffix.as_ref().0)
    }
}

impl AsRef<UStr> for UString {
    fn as_ref(&self) -> &UStr {
        &self
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<String> for UString {
    fn from(string: String) -> UString {
        UString(string.chars().collect())
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl From<char> for UString {
    fn from(c: char) -> UString {
        UString(vec![c])
    }
}

impl From<UString> for String {
    fn from(string: UString) -> String {
        String::from_iter(string)
    }
}

impl<'a> From<&'a UString> for String {
    fn from(string: &UString) -> String {
        String::from_iter(string.into_iter().cloned())
    }
}

impl<'a> From<&'a UStr> for String {
    fn from(slice: &UStr) -> String {
        String::from_iter(slice.into_iter().cloned())
    }
}

impl<C: Into<char>> FromIterator<C> for UString {
    fn from_iter<T>(iterator: T) -> UString where T: IntoIterator<Item=C> {
        UString(iterator.into_iter().map(C::into).collect())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Iter<'a>(&'a [char]);

#[derive(Debug)]
pub struct IntoIter(Vec<char>);

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

    fn next(&mut self) -> Option<&'a char> {
        if self.0.len() > 0 {
            let result = &self.0[0];
            self.0 = &self.0[1..];
            Some(result)
        } else {
            None
        }
    }
}

impl Iterator for IntoIter {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.0.len() > 0 {
            Some(self.0.remove(0))
        } else {
            None
        }
    }
}

impl IntoIterator for UString {
    type Item = char;
    type IntoIter = IntoIter;

    fn into_iter(self) -> IntoIter {
        IntoIter(self.0)
    }
}

impl<'a> IntoIterator for &'a UString {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}

impl<'a> IntoIterator for &'a UStr {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_imports)]
use std::io::Read;
use std::default::Default;
use std::io::BufReader;
use std::path::Path;
use std::fs::File;
use self::mad_decoder_mode::* ;

#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: &mad_decoder,
                        message: &mad_message,
                        input_callback: extern fn(message: &mut mad_message, stream: isize) -> mad_flow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: &mut mad_message,
                                                   header: isize,
                                                   pcm: &mad_pcm) -> mad_flow,
                        error_callback: extern fn(),
                        message_callback: extern fn());
    fn mad_decoder_run(input: &mut mad_decoder, mode: mad_decoder_mode) -> i32;
    fn mad_stream_buffer(stream: isize, buf_start: *const u8, buf_length: usize);
}

#[repr(C)]
enum mad_flow {
    mf_continue = 0x0000,	/* continue normally */
    mf_stop     = 0x0010,	/* stop decoding normally */
    mf_break    = 0x0011,	/* stop decoding and signal an error */
    mf_ignore   = 0x0020	/* ignore the current frame */
}

#[repr(C)]
struct mad_pcm {
    sample_rate: u32,
    channels: u16,
    length: u16,
    samples: [[i32; 1152]; 2],
}

#[repr(C)]
struct mad_message<'a> {
    start: &'a *const u8,
    length: usize,
    reader: &'a mut BufReader<std::fs::File>,
    position: usize,
}

#[repr(C)]
enum mad_decoder_mode {
    MAD_DECODER_MODE_SYNC = 0,
    MAD_DECODER_MODE_ASYNC
}

impl Default for mad_decoder_mode {
    fn default() -> mad_decoder_mode {MAD_DECODER_MODE_SYNC}
}

#[derive(Default)]
#[repr(C)]
struct mad_async_parameters {
    pid: u32,
    ain: isize,
    aout: isize,
}

#[derive(Default)]
#[repr(C)]
struct mad_decoder {
    mode: mad_decoder_mode,
    options: isize,
    async: mad_async_parameters,
    sync: usize,
    cb_data: usize,
    input_func: usize,
    header_func: usize,
    filter_func: usize,
    output_func: usize,
    error_func: usize,
    message_func: usize,
}

extern fn empty_callback() {

}

#[test]
fn test_open_file() {
    let path = Path::new("test_samples/fs-242.mp3");
    let f = File::open(&path).unwrap();
    let mut reader = BufReader::new(f);
    let mut input_buffer = vec![0u8; 4096];
    reader.read(&mut input_buffer);
    let message = &mut mad_message {
        start: &input_buffer.as_ptr(),
        length: input_buffer.len(),
        reader: &mut reader,
        position: 0,
    };
    let mut decoder: mad_decoder = Default::default();
    let mut decoding_result: i32 = 42;

    extern fn input_callback (msg: &mut mad_message, stream: isize) -> mad_flow {
        let mut input_buffer = vec![0u8; 4096];
        let read_result = msg.reader.read(&mut input_buffer).unwrap();
        unsafe {
            mad_stream_buffer(stream, input_buffer.as_ptr(), input_buffer.len());
        }

        msg.position += read_result;
        if read_result == 0 {
            return mad_flow::mf_stop;
        }

        mad_flow::mf_continue
    }

    extern fn output_callback(msg: &mut mad_message, header: isize, pcm: &mad_pcm) -> mad_flow {
        println!("Position: {}", msg.position);
        mad_flow::mf_continue
    }

    unsafe {
        mad_decoder_init(&mut decoder,
                         message,
                         input_callback,
                         empty_callback,
                         empty_callback,
                         output_callback,
                         empty_callback,
                         empty_callback);
        decoding_result = mad_decoder_run(&mut decoder, mad_decoder_mode::MAD_DECODER_MODE_SYNC);
    }

    assert_eq!(decoding_result, 0);
}
<commit_msg>Moved decoding to module<commit_after>#![allow(dead_code, unused_imports)]
use std::io::Read;
use std::default::Default;
use std::io::BufReader;
use std::path::Path;
use std::fs::File;
mod decoder;
<|endoftext|>


<commit_before>extern crate term;
extern crate termios;

use term::terminfo::TermInfo;
use termios::Termios;
use std::string::String;
use std::io::{stdin, Stdin, stdout, Stdout, stderr, Stderr};

/// Holds the state for the line editor
pub struct Rebar {
    i: Stdin,   //stdin handle
    o: Stdout,  //stdout handle
    e: Stderr,  //stderr handle
    termio: Termios,
    terms: TermInfo,
    prompt: String,
    buf: String,
    cursor_pos: usize,
}

/// Initialisation function
pub fn rebar() -> Rebar {
    let info = match TermInfo::from_env() {
        Ok(s) => s,
        Err(f) => panic!(f),
    };
    let ios = match Termios::from_fd(0) {
        Ok(s) => s,
        Err(f) => panic!(f),
    };
    let res = Rebar {
        i: stdin(),
        o: stdout(),
        e: stderr(),
        termio: ios,
        terms: info,
        prompt: String::new(),
        buf: String::new(),
        cursor_pos: 0
    };
    res
}

///Clears the screen using terminfo-based clear string
pub fn clear() {
    let info = term::terminfo::TermInfo::from_env();

    let fred = match info {
        Ok(val) => val,
        Err(f) => panic!(f.to_string()),
    };

    let clear = fred.strings.get("clear").unwrap();
    let mut derf = term::stdout().unwrap();
    match derf.write_all(clear) {
        Ok(..) => {},
        Err(f) => println!("Failed to clear: {}", f),
    };
}

///Refresh the line, so that you can move cursors and shit
pub fn refresh_screen(inline: &str) {
    let mut line = String::new();
    line.push_str("\r");
    line.push_str(inline);
    print!("{}", line);
}

#[test]
fn init_rebar() {
    let reb = rebar();
    reb.prompt.push('$');
    reb.cursor_pos += 1;
}

#[test]
fn clear_screen() {
    clear();
}

#[test]
fn refresh() {
    refresh_screen("");
}<commit_msg>learned how to create mutable structs<commit_after>extern crate term;
extern crate termios;

use term::terminfo::TermInfo;
use termios::Termios;
use std::string::String;
use std::io::{stdin, Stdin, stdout, Stdout, stderr, Stderr};

/// Holds the state for the line editor
pub struct Rebar {
    i: Stdin,   //stdin handle
    o: Stdout,  //stdout handle
    e: Stderr,  //stderr handle
    termio: Termios,
    terms: TermInfo,
    prompt: String,
    buf: String,
    cursor_pos: usize,
}

/// Initialisation function
pub fn rebar() -> Rebar {
    let info = match TermInfo::from_env() {
        Ok(s) => s,
        Err(f) => panic!(f),
    };
    let ios = match Termios::from_fd(0) {
        Ok(s) => s,
        Err(f) => panic!(f),
    };
    let res = Rebar {
        i: stdin(),
        o: stdout(),
        e: stderr(),
        termio: ios,
        terms: info,
        prompt: String::new(),
        buf: String::new(),
        cursor_pos: 0
    };
    res
}

///Clears the screen using terminfo-based clear string
pub fn clear() {
    let info = term::terminfo::TermInfo::from_env();

    let fred = match info {
        Ok(val) => val,
        Err(f) => panic!(f.to_string()),
    };

    let clear = fred.strings.get("clear").unwrap();
    let mut derf = term::stdout().unwrap();
    match derf.write_all(clear) {
        Ok(..) => {},
        Err(f) => println!("Failed to clear: {}", f),
    };
}

///Refresh the line, so that you can move cursors and shit
pub fn refresh_screen(inline: &str) {
    let mut line = String::new();
    line.push_str("\r");
    line.push_str(inline);
    print!("{}", line);
}

#[test]
fn init_rebar() {
    let mut reb = rebar();
    reb.prompt.push('$');
    reb.cursor_pos += 1;
}

#[test]
fn clear_screen() {
    clear();
}

#[test]
fn refresh() {
    refresh_screen("");
}<|endoftext|>


<commit_before>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init( ctn: {}; pn: {} )", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    debug!("Request path: {}", path);

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            debug!("Response received!");

            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Store CTN
                MAP.lock().unwrap().insert(ctn, pn);
            }

            debug!("Return status: {}", status);
            status
        }
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            debug!("Response: {:?}", response);
            ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    debug!("CT_data for ctn: {}", ctn);
    unsafe {
        if !MAP.lock().unwrap().contains_key(&ctn) {
            return ERR_INVALID;
        }

        let dad: &mut u8 = &mut *dad;

        let sad: &mut u8 = &mut *sad;

        let lenr: &mut size_t = &mut *lenr;

        let command = slice::from_raw_parts(command, lenc as usize);

        let response = slice::from_raw_parts_mut(response, *lenr);

        let requestData = RequestData {
            dad: *dad,
            sad: *sad,
            lenc: lenc,
            command: encode(command),
            lenr: *lenr,
        };

        debug!("dad: {}, sad: {}, lenc: {}, command: {:?}, lenr: {}, response.len(): {}",
               dad,
               sad,
               lenc,
               command,
               lenr,
               response.len());

        let pn = MAP.lock().unwrap();
        let pn = pn.get(&ctn).unwrap();
        let endpoint = "ct_data".to_string();
        let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

        debug!("Request path: {}", path);

        let mut http_response = post_request(&path, &requestData);

        match http_response.status {
            StatusCode::Ok => {
                debug!("Response received!");

                // decode server response
                let mut body = String::new();
                http_response.read_to_string(&mut body).unwrap();
                debug!("Response body: {}", body);

                let responseData: ResponseData = serde_json::from_str(&body).unwrap();

                if responseData.responseCode == OK {
                    *dad = responseData.dad;
                    *sad = responseData.sad;
                    *lenr = responseData.lenr;

                    let decoded = decode(&responseData.response).unwrap();
                    debug!("Decoded response field {:?}", decoded);

                    for (place, element) in response.iter_mut().zip(decoded.iter()) {
                        *place = *element;
                    }
                }
                debug!("Return status: {}", responseData.responseCode);
                return responseData.responseCode;
            }
            _ => {
                error!("Response not OK! Returning {}", ERR_HOST);
                debug!("Response: {:?}", http_response);
                ERR_HOST
            }
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close( ctn: {} )", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    debug!("Request path: {}", path);

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            debug!("Response received!");

            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
            }

            debug!("Return status: {}", status);
            status
        }
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            debug!("Response: {:?}", response);
            ERR_HOST
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Response
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    return client
               .post(&url)
               .headers(headers)
               .body(&body[..])
               .send()
               .unwrap();
}
<commit_msg>adjust log output<commit_after>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init: Called (ctn {}, pn {})", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_init: Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Store CTN
                MAP.lock().unwrap().insert(ctn, pn);
                debug!("CT_init: Card terminal opened.");
            }

            debug!("CT_init: Returning {}", status);
            status
        }
        _ => {
            error!("CT_init: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    unsafe {
        let dad: &mut u8 = &mut *dad;

        let sad: &mut u8 = &mut *sad;

        let lenr: &mut size_t = &mut *lenr;

        let command = slice::from_raw_parts(command, lenc as usize);

        let response = slice::from_raw_parts_mut(response, *lenr);

        debug!("CT_data: Called (ctn {}, dad {}, sad {}, lenc {}, \
               command {:?}, lenr {}), response.len() {})",
               ctn,
               dad,
               sad,
               lenc,
               command,
               lenr,
               response.len());

        if !MAP.lock().unwrap().contains_key(&ctn) {
            debug!("CT_data: Card terminal has not been opened. Returning {}",
                   ERR_INVALID);
            return ERR_INVALID;
        }

        let requestData = RequestData {
            dad: *dad,
            sad: *sad,
            lenc: lenc,
            command: encode(command),
            lenr: *lenr,
        };

        let pn = MAP.lock().unwrap();
        let pn = pn.get(&ctn).unwrap();
        let endpoint = "ct_data".to_string();
        let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

        let mut http_response = post_request(&path, &requestData);

        match http_response.status {
            StatusCode::Ok => {
                // decode server response
                let mut body = String::new();
                http_response.read_to_string(&mut body).unwrap();
                debug!("CT_data: Response body: {}", body);

                let responseData: ResponseData = serde_json::from_str(&body).unwrap();

                if responseData.responseCode == OK {
                    *dad = responseData.dad;
                    *sad = responseData.sad;
                    *lenr = responseData.lenr;

                    let decoded = decode(&responseData.response).unwrap();
                    debug!("CT_data: Decoded response field {:?}", decoded);

                    for (place, element) in response.iter_mut().zip(decoded.iter()) {
                        *place = *element;
                    }
                }
                debug!("CT_data: Returning {}", responseData.responseCode);
                return responseData.responseCode;
            }
            _ => {
                error!("CT_data: Response not OK! Returning {}", ERR_HOST);
                ERR_HOST
            }
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close: Called (ctn {})", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_close: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
                debug!("CT_close: Card terminal has been closed.");
            }

            debug!("CT_close: Returning {}", status);
            status
        }
        _ => {
            error!("CT_close: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Response
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    debug!("HTTP POST URL: {}", url);
    debug!("HTTP POST body: {:?}", body);

    let response = client
        .post(&url)
        .headers(headers)
        .body(&body[..])
        .send()
        .unwrap();

    debug!("{:?}", response); // TODO enrich output
    response
}
<|endoftext|>


<commit_before>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::rc::try_unwrap.
#![feature(rc_unique)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable, focus-based view of a tree.
///
/// This trait defines a view of a tree that is focused on a node and can be
/// navigated to that node's parent, a sibling, or a child.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should also implement
/// `std::borrow::Deref` or `std::borrow::DerefMut`.
///
/// This trait does not expose methods for mutating the tree, but this does not
/// guarantee immutability or thread safety. Implementing types may permit
/// mutation of tree data (whether by implementing `std::borrow::DerefMut`,
/// implementing `std::borrow::Deref` and having `RefCell` data, or otherwise),
/// which may in turn cause arbitrary modifications in the underlying
/// representation of the tree structure (such as reallocations). The `Editor`
/// trait, which extends this one, has explicit methods for modification of tree
/// topology.
///
/// This trait is usually implemented for borrows of some underlying tree
/// structure.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone` when this is possible. For mutable types that also
/// implement `std::borrow::DerefMut`, which may require a read-write borrow of
/// an underlying structure, this may not be possible.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. (An offset of 0 is a no-op.) Returns true iff `offset` resolves
    /// to an extant sibling.
    fn seek_sibling(&mut self, offset: isize) -> bool;

    // Navigates to the leftmost sibling. This is a no-op if the focus is
    // already at the leftmost sibling.
    fn seek_first_sibling(&mut self) {
        if self.to_parent() {
            self.seek_child(0);
        }
    }

    // Navigates to the rightmost sibling. This is a no-op if the focus is
    // already at the rightmost sibling.
    fn seek_last_sibling(&mut self) {
        if self.to_parent() {
            let last_child_index = self.child_count() - 1;
            self.seek_child(last_child_index);
        }
    }

    /// Navigates to the child at at the given index. Returns true iff `index`
    /// resolves to an extant child.
    fn seek_child(&mut self, index: usize) -> bool;

    /// Navigates to this node's parent. Returns true iff the focus changes
    /// (i.e., if `self` was not already pointing to the tree root).
    fn to_parent(&mut self) -> bool;

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

/// Navigable view of a tree, with support for modifying the tree's topology.
///
/// This trait extends [Nav](trait.Nav.html) with support for tree modification
/// operations.
pub trait Editor: Nav {
    /// The type of tree node data, usually the `T` of some `Tree<T>`.
    type Data;

    /// The tree type that is associated with operations that insert or remove
    /// subtrees. This is typically the implementing tree type that the `Editor`
    /// provides a view of.
    type Tree;

    /// Creates a new leaf with the given data at the logical end of the
    /// children of the current focus and focuses on it.
    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    /// Adds `child` to the logical end of the children of the current focus and
    /// focuses on it.
    fn push_child(&mut self, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the given position in the
    /// current focus's children and focuses on it.
    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data) -> bool;

    /// Inserts `child` at the given position in the current focus's children
    /// and focuses on it.
    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree) -> bool;

    /// Inserts a new leaf with the given data at the position an offset by the
    /// given amount from the current focus and focuses on it. Panics if the
    /// offset is invalid.
    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data) -> bool;

    /// Inserts `sibling` at the given offset relative to the current focus and
    /// focuses on it. Panics if the offset is invalid.
    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree) -> bool;

    /// Removes the focus node and returns the subtree rooted at it. Focus
    /// changes to (in order of preference) the focus's left sibling, its right
    /// sibling (if there is no left sibling), or its parent (if there are no
    /// siblings).
    fn remove(&mut self) -> <Self as Editor>::Tree;

    /// Removes the child at the given index and returns the subtree rooted at
    /// it.
    fn remove_child(&mut self, index: usize) -> Option<<Self as Editor>::Tree>;

    /// Removes the sibling at the given offset and returns the subtree rooted
    /// at it.
    fn remove_sibling(&mut self, offset: isize) -> Option<<Self as Editor>::Tree>;

    /// Swaps the focus node and `other`.
    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    /// Swaps the children at the given indices. If the indices are equal, this
    /// is a no-op. If either index corresponds to the focus, focus follows it
    /// after the swap.
    fn swap_children(&mut self, index_a: usize, index_b: usize) -> bool;

    /// Swaps the sibling nodes at the given offsets. If the offsets are equal,
    /// this is a no-op. If either offset is 0 (corresponding to the focus),
    /// focus follows it after the swap.
    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize) -> bool;
}

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<commit_msg>Fix typo in comment.<commit_after>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::rc::try_unwrap.
#![feature(rc_unique)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable, focus-based view of a tree.
///
/// This trait defines a view of a tree that is focused on a node and can be
/// navigated to that node's parent, a sibling, or a child.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should also implement
/// `std::borrow::Deref` or `std::borrow::DerefMut`.
///
/// This trait does not expose methods for mutating the tree, but this does not
/// guarantee immutability or thread safety. Implementing types may permit
/// mutation of tree data (whether by implementing `std::borrow::DerefMut`,
/// implementing `std::borrow::Deref` and having `RefCell` data, or otherwise),
/// which may in turn cause arbitrary modifications in the underlying
/// representation of the tree structure (such as reallocations). The `Editor`
/// trait, which extends this one, has explicit methods for modification of tree
/// topology.
///
/// This trait is usually implemented for borrows of some underlying tree
/// structure.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone` when this is possible. For mutable types that also
/// implement `std::borrow::DerefMut`, which may require a read-write borrow of
/// an underlying structure, this may not be possible.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. (An offset of 0 is a no-op.) Returns true iff `offset` resolves
    /// to an extant sibling.
    fn seek_sibling(&mut self, offset: isize) -> bool;

    // Navigates to the leftmost sibling. This is a no-op if the focus is
    // already at the leftmost sibling.
    fn seek_first_sibling(&mut self) {
        if self.to_parent() {
            self.seek_child(0);
        }
    }

    // Navigates to the rightmost sibling. This is a no-op if the focus is
    // already at the rightmost sibling.
    fn seek_last_sibling(&mut self) {
        if self.to_parent() {
            let last_child_index = self.child_count() - 1;
            self.seek_child(last_child_index);
        }
    }

    /// Navigates to the child at the given index. Returns true iff `index`
    /// resolves to an extant child.
    fn seek_child(&mut self, index: usize) -> bool;

    /// Navigates to this node's parent. Returns true iff the focus changes
    /// (i.e., if `self` was not already pointing to the tree root).
    fn to_parent(&mut self) -> bool;

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

/// Navigable view of a tree, with support for modifying the tree's topology.
///
/// This trait extends [Nav](trait.Nav.html) with support for tree modification
/// operations.
pub trait Editor: Nav {
    /// The type of tree node data, usually the `T` of some `Tree<T>`.
    type Data;

    /// The tree type that is associated with operations that insert or remove
    /// subtrees. This is typically the implementing tree type that the `Editor`
    /// provides a view of.
    type Tree;

    /// Creates a new leaf with the given data at the logical end of the
    /// children of the current focus and focuses on it.
    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    /// Adds `child` to the logical end of the children of the current focus and
    /// focuses on it.
    fn push_child(&mut self, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the given position in the
    /// current focus's children and focuses on it.
    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data) -> bool;

    /// Inserts `child` at the given position in the current focus's children
    /// and focuses on it.
    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree) -> bool;

    /// Inserts a new leaf with the given data at the position an offset by the
    /// given amount from the current focus and focuses on it. Panics if the
    /// offset is invalid.
    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data) -> bool;

    /// Inserts `sibling` at the given offset relative to the current focus and
    /// focuses on it. Panics if the offset is invalid.
    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree) -> bool;

    /// Removes the focus node and returns the subtree rooted at it. Focus
    /// changes to (in order of preference) the focus's left sibling, its right
    /// sibling (if there is no left sibling), or its parent (if there are no
    /// siblings).
    fn remove(&mut self) -> <Self as Editor>::Tree;

    /// Removes the child at the given index and returns the subtree rooted at
    /// it.
    fn remove_child(&mut self, index: usize) -> Option<<Self as Editor>::Tree>;

    /// Removes the sibling at the given offset and returns the subtree rooted
    /// at it.
    fn remove_sibling(&mut self, offset: isize) -> Option<<Self as Editor>::Tree>;

    /// Swaps the focus node and `other`.
    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    /// Swaps the children at the given indices. If the indices are equal, this
    /// is a no-op. If either index corresponds to the focus, focus follows it
    /// after the swap.
    fn swap_children(&mut self, index_a: usize, index_b: usize) -> bool;

    /// Swaps the sibling nodes at the given offsets. If the offsets are equal,
    /// this is a no-op. If either offset is 0 (corresponding to the focus),
    /// focus follows it after the swap.
    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize) -> bool;
}

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<|endoftext|>


<commit_before>//! Algorithmia client library
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, AlgoOutput, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let output: AlgoOutput<Vec<f64>> = moving_avg.pipe(&input).unwrap();
//! println!("Completed in {} seconds with result: {:?}", output.metadata.duration, output.result);
//! ```

#![doc(html_logo_url = "https://algorithmia.com/assets/images/apple-touch-icon.png")]

extern crate hyper;
extern crate rustc_serialize;

pub mod algo;
pub mod data;

use algo::{Algorithm, Version};
use data::{DataDir, DataFile};

use hyper::{Client, Url};
use hyper::client::RequestBuilder;
use hyper::header::{Authorization, UserAgent};
use hyper::method::Method;
use rustc_serialize::{json, Decodable};
use self::AlgorithmiaError::*;
use std::{io, env};
use std::sync::Arc;

static DEFAULT_API_BASE_URL: &'static str = "https://api.algorithmia.com";

/// The top-level struct for instantiating Algorithmia client endpoints
pub struct Algorithmia {
    pub api_key: String,
    pub base_url: String,
    client: Arc<Client>, // Arc to ensure Algorithmia is still marked Send + Sync
}

/// Internal HttpClient to build requests: wraps `hyper` client
struct HttpClient<'a>{
    api_key: String,
    client: &'a Client,
    user_agent: String,
}

/// Errors that may be returned by this library
#[derive(Debug)]
pub enum AlgorithmiaError {
    /// Errors returned by the Algorithmia API, Optional Stacktrace
    AlgorithmiaApiError(ApiError),
    /// HTTP errors encountered by the hyper client
    HttpError(hyper::error::Error),
    /// Errors decoding response json
    DecoderError(json::DecoderError),
    /// Errors decoding response json with additional debugging context
    DecoderErrorWithContext(json::DecoderError, String),
    /// Errors encoding the request
    EncoderError(json::EncoderError),
    /// General IO errors
    IoError(io::Error),
}

#[derive(RustcDecodable, Debug)]
pub struct ApiError {
    pub message: String,
    pub stacktrace: Option<String>,
}

/// Struct for decoding Algorithmia API error responses
#[derive(RustcDecodable, Debug)]
pub struct ApiErrorResponse {
    pub error: ApiError,
}

impl<'a, 'c> Algorithmia {
    /// Instantiate a new client
    pub fn client(api_key: &str) -> Algorithmia {
        Algorithmia {
            api_key: api_key.to_string(),
            base_url: Self::get_base_url(),
            client: Arc::new(Client::new()),
        }
    }

    fn get_base_url() -> String {
        // TODO: memoize
        match env::var("ALGORITHMIA_API") {
            Ok(url) => url,
            Err(_) => DEFAULT_API_BASE_URL.to_string(),
        }
    }

    /// Instantiate a new hyper client - used internally by instantiating new api_client for every request
    fn http_client(&self) -> HttpClient {
        HttpClient::new(self.api_key.clone(), &self.client)
    }

    /// Instantiate an `Algorithm` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo("anowell", "Dijkstra", Version::Latest);
    /// ```
    pub fn algo(self, user: &str, algoname: &str, version: Version<'a>) -> Algorithm {
        let algo_uri = match version {
            Version::Latest => format!("{}/{}", user, algoname),
            ref ver => format!("{}/{}/{}", user, algoname, ver),
        };

        Algorithm::new(self, &*algo_uri)
    }

    /// Instantiate an `Algorithm` from this client using the algorithm's URI
    ///
    /// # Examples
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo_from_str("anowell/Dijkstra/0.1");
    /// ```
    pub fn algo_from_str(self, algo_uri: &str) -> Algorithm {
        Algorithm::new(self, algo_uri)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.dir("data://.my/rustfoo");
    /// ```
    pub fn dir(self, path: &'a str) -> DataDir {
        DataDir::new(self, path)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.file("data://.my/rustfoo");
    /// ```
    pub fn file(self, path: &'a str) -> DataFile {
        DataFile::new(self, path)
    }

    /// Helper to standardize decoding to a specific Algorithmia Result type
    pub fn decode_to_result<T: Decodable>(res_json: String) -> Result<T, AlgorithmiaError> {
        match json::decode::<T>(&res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&res_json) {
                Ok(err_res) => Err(AlgorithmiaError::AlgorithmiaApiError(err_res.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    pub fn decode_to_error(res_json: String) -> AlgorithmiaError {
        match json::decode::<ApiErrorResponse>(&res_json) {
            Ok(err_res) => AlgorithmiaError::AlgorithmiaApiError(err_res.error),
            Err(why) => AlgorithmiaError::DecoderErrorWithContext(why, res_json),
        }
    }

}

impl <'a> HttpClient<'a> {
    /// Instantiate an HttpClient - creates a new `hyper` client
    fn new(api_key: String, client: &'a Client) -> HttpClient {
        HttpClient {
            api_key: api_key,
            client: client,
            user_agent: format!("rust/{} algorithmia.rs/{}", option_env!("CFG_RELEASE").unwrap_or("unknown"), option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")),
        }
    }

    /// Helper to make Algorithmia GET requests with the API key
    fn get(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Get, url)
    }

    /// Helper to make Algorithmia POST requests with the API key
    fn post(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Post, url)
    }

    /// Helper to make Algorithmia PUT requests with the API key
    fn put(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Put, url)
    }

    /// Helper to make Algorithmia POST requests with the API key
    fn delete(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Delete, url)
    }

    fn build_request(&self, verb: Method, url: Url) -> RequestBuilder<Url> {
        let req = self.client.request(verb, url);

        // TODO: Support Secure Auth
        req.header(UserAgent(self.user_agent.clone()))
           .header(Authorization(format!("Simple {}", self.api_key)))
    }
}

/*
* Trait implementations
*/
/// Allow cloning a client in order to reuse the API key for multiple connections
impl std::clone::Clone for Algorithmia {
    fn clone(&self) -> Algorithmia {
        Algorithmia {
            api_key: self.api_key.clone(),
            base_url: self.base_url.clone(),
            client: self.client.clone(),
        }
    }
}

impl From<io::Error> for AlgorithmiaError {
    fn from(err: io::Error) -> AlgorithmiaError {
        IoError(err)
    }
}

impl From<hyper::error::Error> for AlgorithmiaError {
    fn from(err: hyper::error::Error) -> AlgorithmiaError {
        HttpError(err)
    }
}

impl From<json::DecoderError> for AlgorithmiaError {
    fn from(err: json::DecoderError) -> AlgorithmiaError {
        DecoderError(err)
    }
}

impl From<json::EncoderError> for AlgorithmiaError {
    fn from(err: json::EncoderError) -> AlgorithmiaError {
        EncoderError(err)
    }
}<commit_msg>Re-export hyper::mime<commit_after>//! Algorithmia client library
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, AlgoOutput, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let output: AlgoOutput<Vec<f64>> = moving_avg.pipe(&input).unwrap();
//! println!("Completed in {} seconds with result: {:?}", output.metadata.duration, output.result);
//! ```

#![doc(html_logo_url = "https://algorithmia.com/assets/images/apple-touch-icon.png")]

extern crate hyper;
extern crate rustc_serialize;

pub mod algo;
pub mod data;
pub use hyper::mime;

use algo::{Algorithm, Version};
use data::{DataDir, DataFile};

use hyper::{Client, Url};
use hyper::client::RequestBuilder;
use hyper::header::{Authorization, UserAgent};
use hyper::method::Method;
use rustc_serialize::{json, Decodable};
use self::AlgorithmiaError::*;
use std::{io, env};
use std::sync::Arc;

static DEFAULT_API_BASE_URL: &'static str = "https://api.algorithmia.com";

/// The top-level struct for instantiating Algorithmia client endpoints
pub struct Algorithmia {
    pub api_key: String,
    pub base_url: String,
    client: Arc<Client>, // Arc to ensure Algorithmia is still marked Send + Sync
}

/// Internal HttpClient to build requests: wraps `hyper` client
struct HttpClient<'a>{
    api_key: String,
    client: &'a Client,
    user_agent: String,
}

/// Errors that may be returned by this library
#[derive(Debug)]
pub enum AlgorithmiaError {
    /// Errors returned by the Algorithmia API, Optional Stacktrace
    AlgorithmiaApiError(ApiError),
    /// HTTP errors encountered by the hyper client
    HttpError(hyper::error::Error),
    /// Errors decoding response json
    DecoderError(json::DecoderError),
    /// Errors decoding response json with additional debugging context
    DecoderErrorWithContext(json::DecoderError, String),
    /// Errors encoding the request
    EncoderError(json::EncoderError),
    /// General IO errors
    IoError(io::Error),
}

#[derive(RustcDecodable, Debug)]
pub struct ApiError {
    pub message: String,
    pub stacktrace: Option<String>,
}

/// Struct for decoding Algorithmia API error responses
#[derive(RustcDecodable, Debug)]
pub struct ApiErrorResponse {
    pub error: ApiError,
}

impl<'a, 'c> Algorithmia {
    /// Instantiate a new client
    pub fn client(api_key: &str) -> Algorithmia {
        Algorithmia {
            api_key: api_key.to_string(),
            base_url: Self::get_base_url(),
            client: Arc::new(Client::new()),
        }
    }

    fn get_base_url() -> String {
        // TODO: memoize
        match env::var("ALGORITHMIA_API") {
            Ok(url) => url,
            Err(_) => DEFAULT_API_BASE_URL.to_string(),
        }
    }

    /// Instantiate a new hyper client - used internally by instantiating new api_client for every request
    fn http_client(&self) -> HttpClient {
        HttpClient::new(self.api_key.clone(), &self.client)
    }

    /// Instantiate an `Algorithm` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo("anowell", "Dijkstra", Version::Latest);
    /// ```
    pub fn algo(self, user: &str, algoname: &str, version: Version<'a>) -> Algorithm {
        let algo_uri = match version {
            Version::Latest => format!("{}/{}", user, algoname),
            ref ver => format!("{}/{}/{}", user, algoname, ver),
        };

        Algorithm::new(self, &*algo_uri)
    }

    /// Instantiate an `Algorithm` from this client using the algorithm's URI
    ///
    /// # Examples
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo_from_str("anowell/Dijkstra/0.1");
    /// ```
    pub fn algo_from_str(self, algo_uri: &str) -> Algorithm {
        Algorithm::new(self, algo_uri)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.dir("data://.my/rustfoo");
    /// ```
    pub fn dir(self, path: &'a str) -> DataDir {
        DataDir::new(self, path)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.file("data://.my/rustfoo");
    /// ```
    pub fn file(self, path: &'a str) -> DataFile {
        DataFile::new(self, path)
    }

    /// Helper to standardize decoding to a specific Algorithmia Result type
    pub fn decode_to_result<T: Decodable>(res_json: String) -> Result<T, AlgorithmiaError> {
        match json::decode::<T>(&res_json) {
            Ok(result) => Ok(result),
            Err(why) => match json::decode::<ApiErrorResponse>(&res_json) {
                Ok(err_res) => Err(AlgorithmiaError::AlgorithmiaApiError(err_res.error)),
                Err(_) => Err(AlgorithmiaError::DecoderErrorWithContext(why, res_json)),
            }
        }
    }

    pub fn decode_to_error(res_json: String) -> AlgorithmiaError {
        match json::decode::<ApiErrorResponse>(&res_json) {
            Ok(err_res) => AlgorithmiaError::AlgorithmiaApiError(err_res.error),
            Err(why) => AlgorithmiaError::DecoderErrorWithContext(why, res_json),
        }
    }

}

impl <'a> HttpClient<'a> {
    /// Instantiate an HttpClient - creates a new `hyper` client
    fn new(api_key: String, client: &'a Client) -> HttpClient {
        HttpClient {
            api_key: api_key,
            client: client,
            user_agent: format!("rust/{} algorithmia.rs/{}", option_env!("CFG_RELEASE").unwrap_or("unknown"), option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")),
        }
    }

    /// Helper to make Algorithmia GET requests with the API key
    fn get(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Get, url)
    }

    /// Helper to make Algorithmia POST requests with the API key
    fn post(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Post, url)
    }

    /// Helper to make Algorithmia PUT requests with the API key
    fn put(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Put, url)
    }

    /// Helper to make Algorithmia POST requests with the API key
    fn delete(&self, url: Url) -> RequestBuilder<Url> {
        self.build_request(Method::Delete, url)
    }

    fn build_request(&self, verb: Method, url: Url) -> RequestBuilder<Url> {
        let req = self.client.request(verb, url);

        // TODO: Support Secure Auth
        req.header(UserAgent(self.user_agent.clone()))
           .header(Authorization(format!("Simple {}", self.api_key)))
    }
}

/*
* Trait implementations
*/
/// Allow cloning a client in order to reuse the API key for multiple connections
impl std::clone::Clone for Algorithmia {
    fn clone(&self) -> Algorithmia {
        Algorithmia {
            api_key: self.api_key.clone(),
            base_url: self.base_url.clone(),
            client: self.client.clone(),
        }
    }
}

impl From<io::Error> for AlgorithmiaError {
    fn from(err: io::Error) -> AlgorithmiaError {
        IoError(err)
    }
}

impl From<hyper::error::Error> for AlgorithmiaError {
    fn from(err: hyper::error::Error) -> AlgorithmiaError {
        HttpError(err)
    }
}

impl From<json::DecoderError> for AlgorithmiaError {
    fn from(err: json::DecoderError) -> AlgorithmiaError {
        DecoderError(err)
    }
}

impl From<json::EncoderError> for AlgorithmiaError {
    fn from(err: json::EncoderError) -> AlgorithmiaError {
        EncoderError(err)
    }
}<|endoftext|>


<commit_before>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Ok(Some(element)) = builder.push_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        channel.categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        if let Some(element) = element.get_child("title", None) {
            item.title = Some(element.content_str());
        }

        if let Some(element) = element.get_child("link", None) {
            item.link = Some(element.content_str());
        }

        if let Some(element) = element.get_child("description", None) {
            item.description = Some(element.content_str());
        }

        item.categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(item)
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category", None, &[("domain", None, d)]),
            None => Element::new("category", None, &[]),
        };
        category.text(&self.value);
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Simplify from_xml constructors, fewer muts<commit_after>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Ok(Some(element)) = builder.push_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(|e| e.content_str());
        let link = element.get_child("link", None).map(|e| e.content_str());
        let description = element.get_child("description", None).map(|e| e.content_str());

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category", None, &[("domain", None, d)]),
            None => Element::new("category", None, &[]),
        };
        category.text(&self.value);
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>