<commit_before>use csv;
use slog::Logger;
use std::fs::create_dir;
use std::io;
use std::error;
use std::fmt;
use std::path::Path;
use ndarray;
use ndarray::{Array3, Zip};
use ndarray_parallel::prelude::*;
use grid;
use config::Config;

#[derive(Debug,Deserialize)]
/// A simple struct to parse data from a plain csv file
struct PlainRecord {
    /// Index in *x*
    i: usize,
    /// Index in *y*
    j: usize,
    /// Index in *z*
    k: usize,
    /// Data at this position
    data: f64,
}

/// Error type for handling file output. Effectively a wapper around multiple error types we encounter.
#[derive(Debug)]
pub enum Error {
    /// From disk issues.
    Io(io::Error),
    /// From `csv`.
    Csv(csv::Error),
    /// From `ndarray`.
    Shape(ndarray::ShapeError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Csv(ref err) => err.fmt(f),
            Error::Shape(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Csv(ref err) => err.description(),
            Error::Shape(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Csv(ref err) => Some(err),
            Error::Shape(ref err) => Some(err),
        }
    }
}

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

impl From<csv::Error> for Error {
    fn from(err: csv::Error) -> Error {
        Error::Csv(err)
    }
}

impl From<ndarray::ShapeError> for Error {
    fn from(err: ndarray::ShapeError) -> Error {
        Error::Shape(err)
    }
}

/// Loads potential file from disk. Handles cases where multiple files exist.
///
/// # Arguments
///
/// * `target_size` - Size of the requested work area for this simulation. If the file on disk does
/// not meet these dimensions, it will be scaled.
/// * `binary` - Configuation flag concerning binary /  plain file output. Will be used as an arbitrator
/// when multiple files are detected.
/// * `log` - Reference to the system logger.
pub fn potential(target_size: [usize; 3],
                 bb: usize,
                 binary: bool,
                 log: &Logger)
                 -> Result<Array3<f64>, Error> {
    let plain_path = "./input/potential.csv";
    let binary_path = "./input/potential.mpk";
    let plain_file = if Path::new(&plain_path).exists() {
        Some(plain_path.to_string())
    } else {
        None
    };
    let binary_file = if Path::new(&binary_path).exists() {
        Some(binary_path.to_string())
    } else {
        None
    };

    if plain_file.is_some() && binary_file.is_some() {
        warn!(log,
              "Multiple potential files found in input directory. Chosing 'potential.{}' based on configuration settings.",
              if binary { "mpk" } else { "csv" });
        if binary {
            potential_plain(plain_file, target_size, bb)
        } else {
            potential_binary(binary_file, target_size, bb)
        }
    } else if plain_file.is_some() {
        potential_plain(plain_file, target_size, bb)
    } else {
        potential_binary(binary_file, target_size, bb)
    }
}

/// Loads a potential from a csv file on disk.
fn potential_plain(file: Option<String>,
                   target_size: [usize; 3],
                   bb: usize)
                   -> Result<Array3<f64>, Error> {
    //No need for anything more here, just call the general parser.
    parse_csv_to_array3(file, target_size, bb)
}

/// Loads a potential from a mpk file on disk.
fn potential_binary(file: Option<String>,
                    target_size: [usize; 3],
                    bb: usize)
                    -> Result<Array3<f64>, Error> {
    //TODO: Not implemented yet, for now call plain
    let _none = file;
    potential_plain(Some("./input/potential.csv".to_string()), target_size, bb)
}

/// Loads previously computed wavefunctions from disk.
pub fn load_wavefunctions(config: &Config,
                          log: &Logger,
                          binary: bool,
                          w_store: &mut Vec<Array3<f64>>)
                          -> Result<(), Error> {
    let num = &config.grid.size;
    let bb = config.central_difference.bb();
    let init_size: [usize; 3] = [num.x + bb, num.y + bb, num.z + bb];
    // Load required wavefunctions. If the current state resides on disk as well, we load that later.
    for wnum in 0..config.wavenum {
        let wfn = wavefunction(wnum, init_size, bb, binary, log);
        match wfn {
            Ok(w) => w_store.push(w),
            Err(err) => return Err(err),
            //TODO: Probably need to make these errors a litte more expressive in thier format sections. For example:
            //    panic!("Cannot load any wavefunction_{}* file from input folder: {}", wnum, err)
        }
        info!(log, "Loaded (previous) wavefunction {} from disk", wnum);
    }
    Ok(())
}

/// Loads wavefunction file from disk. Handles cases where multiple files exist.
///
/// # Arguments
///
/// * `wnum` - Excited state level of the wavefunction to load.
/// * `target_size` - Size of the requested work area for this simulation. If the file on disk does
/// not meet these dimensions, it will be scaled.
/// * `binary` - Configuation flag concerning binary /  plain file output. Will be used as an arbitrator
/// when multiple files are detected.
/// * `log` - Reference to the system logger.
pub fn wavefunction(wnum: u8,
                    target_size: [usize; 3],
                    bb: usize,
                    binary: bool,
                    log: &Logger)
                    -> Result<Array3<f64>, Error> {
    let plain_path = format!("./input/wavefunction_{}.csv", wnum);
    let plain_path_partial = format!("./input/wavefunction_{}_partial.csv", wnum);
    let plain_file = if Path::new(&plain_path).exists() {
        Some(plain_path)
    } else if Path::new(&plain_path_partial).exists() {
        Some(plain_path_partial)
    } else {
        None
    };

    let binary_path = format!("./input/wavefunction_{}.mpk", wnum);
    let binary_path_partial = format!("./input/wavefunction_{}_partial.mpk", wnum);
    let binary_file = if Path::new(&binary_path).exists() {
        Some(binary_path)
    } else if Path::new(&binary_path_partial).exists() {
        Some(binary_path_partial)
    } else {
        None
    };

    if plain_file.is_some() && binary_file.is_some() {
        warn!(log,
              "Multiple wavefunction_{} files found in input directory. Chosing '{}' version based on configuration settings.",
              wnum,
              if binary { "mpk" } else { "csv" });
        if binary {
            wavefunction_plain(plain_file, target_size, bb)
        } else {
            wavefunction_binary(binary_file, target_size, bb)
        }
    } else if plain_file.is_some() {
        wavefunction_plain(plain_file, target_size, bb)
    } else {
        wavefunction_binary(binary_file, target_size, bb)
    }
}

/// Loads a wafefunction from a csv file on disk.
fn wavefunction_plain(file: Option<String>,
                      target_size: [usize; 3],
                      bb: usize)
                      -> Result<Array3<f64>, Error> {
    //No more to add here, just parse the file in the generic parser.
    parse_csv_to_array3(file, target_size, bb)
}

/// Loads a wafefunction from a mpk file on disk.
fn wavefunction_binary(file: Option<String>,
                       target_size: [usize; 3],
                       bb: usize)
                       -> Result<Array3<f64>, Error> {
    //TODO: Not implemented yet, call plain
    //NOTE: This will guarentee a failure from the file name.
    wavefunction_plain(file, target_size, bb)
}

/// Checks that the folder `input` exists. If not, creates it.
/// This doesn't specifically need to happen for all instances,
/// but we may want to put restart values in there later on.
pub fn check_input_dir() -> Result<(), Error> {
    //std::io::Error
    if !Path::new("./input").exists() {
        create_dir("./input")?;
    }
    Ok(())
}

/// Given a filename, this funtion reads in the data of a csv file and parses
/// the values into a 3D array. There are a few caveats to this as the file
/// may be of a different shape to the requested size in the configuration file.
/// The routine therefore attempts to resample/interpolate the data to fit the required
/// parameters.
///
/// # Arguments
///
/// * `file` - A filename wrapped in an option. This function is called from filename parsers
/// which may not be able to obtain a valid location.
/// * `target_size` - Requsted size of the resultant array. If this size does not match the data
/// pulled from the file, interpolation or resampling will occur.
///
/// # Returns
///
/// * A 3D array loaded with data from the file and resampled/interpolated if required.
/// If something goes wrong in the parsing or file handling, a `csv::Error` is passed.
fn parse_csv_to_array3(file: Option<String>,
                       target_size: [usize; 3],
                       bb: usize)
                       -> Result<Array3<f64>, Error> {
    match file {
        Some(f) => {
            let mut rdr = csv::ReaderBuilder::new().has_headers(false).from_path(f)?;
            let mut max_i = 0;
            let mut max_j = 0;
            let mut max_k = 0;
            let mut data: Vec<f64> = Vec::new();
            for result in rdr.deserialize() {
                let record: PlainRecord = result?;
                if record.i > max_i {
                    max_i = record.i
                };
                if record.j > max_j {
                    max_j = record.j
                };
                if record.k > max_k {
                    max_k = record.k
                };
                data.push(record.data);
            }
            let numx = max_i + 1;
            let numy = max_j + 1;
            let numz = max_k + 1;
            match Array3::<f64>::from_shape_vec((numx, numy, numz), data) {
                Ok(result) => {
                    //result is now a parsed Array3 with the work area inside.
                    //We must fill this into an array with CD boundaries, provided
                    //it is the correct size. If not, we must scale it.
                    let init_size: [usize; 3] = [numx + bb, numy + bb, numz + bb];
                    let mut complete = Array3::<f64>::zeros(target_size);
                    {
                        let mut work = grid::get_mut_work_area(&mut complete, bb/2); //NOTE: This is a bit of a hack. But it works.
                        let same: bool = init_size
                            .iter()
                            .zip(target_size.iter())
                            .all(|(a, b)| a == b);
                        let smaller: bool =
                            init_size.iter().zip(target_size.iter()).all(|(a, b)| a < b);
                        let larger: bool =
                            init_size.iter().zip(target_size.iter()).all(|(a, b)| a > b);
                        if same {
                            // Input is the same size, copy down.
                            Zip::from(&mut work)
                                .and(result.view())
                                .par_apply(|work, &result| *work = result);
                        } else if smaller {
                            //TODO: Input has lower resolution. Spread it out.
                            panic!("Wavefunction is lower in resolution than requested");
                        } else if larger {
                            //TODO: Input has higer resolution. Sample it.
                            panic!("Wavefunction is higher in resolution than requested");
                        } else {
                            //TODO: Dimensons are all over the shop. Sample and interp
                            panic!("Wavefunction differs in resolution from requested");
                        }
                    }
                    Ok(complete)
                }
                Err(err) => Err(Error::Shape(err)),
            }
        }
        None => Err(Error::Io(io::Error::from(io::ErrorKind::NotFound))),
    }
}
<commit_msg>Input errors are a little more verbose.<commit_after>use csv;
use slog::Logger;
use std::fs::create_dir;
use std::io;
use std::error;
use std::fmt;
use std::path::Path;
use ndarray;
use ndarray::{Array3, Zip};
use ndarray_parallel::prelude::*;
use grid;
use config::Config;

#[derive(Debug,Deserialize)]
/// A simple struct to parse data from a plain csv file
struct PlainRecord {
    /// Index in *x*
    i: usize,
    /// Index in *y*
    j: usize,
    /// Index in *z*
    k: usize,
    /// Data at this position
    data: f64,
}

/// Error type for handling file output. Effectively a wapper around multiple error types we encounter.
#[derive(Debug)]
pub enum Error {
    /// From disk issues.
    Io(io::Error),
    // If files are not found on disk
    NotFound { value: String },
    /// From `csv`.
    Csv(csv::Error),
    /// From `ndarray`.
    Shape(ndarray::ShapeError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::NotFound { value: ref file } => {
                write!(f, "Cannot find {} in input directory.", file)
            }
            Error::Csv(ref err) => err.fmt(f),
            Error::Shape(ref err) => {
                write!(f,
                       "Calculated and actual size of input data is not aligned ══▶ {}",
                       err)
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::NotFound { .. } => "File not found",
            Error::Csv(ref err) => err.description(),
            Error::Shape(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::NotFound { .. } => None,
            Error::Csv(ref err) => Some(err),
            Error::Shape(ref err) => Some(err),
        }
    }
}

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

impl From<csv::Error> for Error {
    fn from(err: csv::Error) -> Error {
        Error::Csv(err)
    }
}

impl From<ndarray::ShapeError> for Error {
    fn from(err: ndarray::ShapeError) -> Error {
        Error::Shape(err)
    }
}

/// Loads potential file from disk. Handles cases where multiple files exist.
///
/// # Arguments
///
/// * `target_size` - Size of the requested work area for this simulation. If the file on disk does
/// not meet these dimensions, it will be scaled.
/// * `binary` - Configuation flag concerning binary /  plain file output. Will be used as an arbitrator
/// when multiple files are detected.
/// * `log` - Reference to the system logger.
pub fn potential(target_size: [usize; 3],
                 bb: usize,
                 binary: bool,
                 log: &Logger)
                 -> Result<Array3<f64>, Error> {
    let plain_path = "./input/potential.csv";
    let binary_path = "./input/potential.mpk";
    let plain_file = if Path::new(&plain_path).exists() {
        Some(plain_path.to_string())
    } else {
        None
    };
    let binary_file = if Path::new(&binary_path).exists() {
        Some(binary_path.to_string())
    } else {
        None
    };
    println!("{:?}, {:?}", plain_file, binary_file);
    if plain_file.is_some() && binary_file.is_some() {
        warn!(log,
              "Multiple potential files found in input directory. Chosing 'potential.{}' based on configuration settings.",
              if binary { "mpk" } else { "csv" });
        if binary {
            potential_plain(plain_file.unwrap(), target_size, bb)
        } else {
            potential_binary(binary_file.unwrap(), target_size, bb)
        }
    } else if plain_file.is_some() {
        potential_plain(plain_file.unwrap(), target_size, bb)
    } else if binary_file.is_some() {
        potential_binary(binary_file.unwrap(), target_size, bb)
    } else {
        Err(Error::NotFound { value: "potential.*".to_string() })
    }
}

/// Loads a potential from a csv file on disk.
fn potential_plain(file: String, target_size: [usize; 3], bb: usize) -> Result<Array3<f64>, Error> {
    //No need for anything more here, just call the general parser.
    parse_csv_to_array3(file, target_size, bb)
}

/// Loads a potential from a mpk file on disk.
fn potential_binary(file: String,
                    target_size: [usize; 3],
                    bb: usize)
                    -> Result<Array3<f64>, Error> {
    //TODO: Not implemented yet, for now call plain
    let _none = file;
    potential_plain("./input/potential.csv".to_string(), target_size, bb)
}

/// Loads previously computed wavefunctions from disk.
pub fn load_wavefunctions(config: &Config,
                          log: &Logger,
                          binary: bool,
                          w_store: &mut Vec<Array3<f64>>)
                          -> Result<(), Error> {
    let num = &config.grid.size;
    let bb = config.central_difference.bb();
    let init_size: [usize; 3] = [num.x + bb, num.y + bb, num.z + bb];
    // Load required wavefunctions. If the current state resides on disk as well, we load that later.
    for wnum in 0..config.wavenum {
        let wfn = wavefunction(wnum, init_size, bb, binary, log);
        match wfn {
            Ok(w) => w_store.push(w),
            Err(err) => return Err(err),
            //TODO: Probably need to make these errors a litte more expressive in thier format sections. For example:
            //    panic!("Cannot load any wavefunction_{}* file from input folder: {}", wnum, err)
        }
        info!(log, "Loaded (previous) wavefunction {} from disk", wnum);
    }
    Ok(())
}

/// Loads wavefunction file from disk. Handles cases where multiple files exist.
///
/// # Arguments
///
/// * `wnum` - Excited state level of the wavefunction to load.
/// * `target_size` - Size of the requested work area for this simulation. If the file on disk does
/// not meet these dimensions, it will be scaled.
/// * `binary` - Configuation flag concerning binary /  plain file output. Will be used as an arbitrator
/// when multiple files are detected.
/// * `log` - Reference to the system logger.
pub fn wavefunction(wnum: u8,
                    target_size: [usize; 3],
                    bb: usize,
                    binary: bool,
                    log: &Logger)
                    -> Result<Array3<f64>, Error> {
    let plain_path = format!("./input/wavefunction_{}.csv", wnum);
    let plain_path_partial = format!("./input/wavefunction_{}_partial.csv", wnum);
    let plain_file = if Path::new(&plain_path).exists() {
        Some(plain_path)
    } else if Path::new(&plain_path_partial).exists() {
        Some(plain_path_partial)
    } else {
        None
    };

    let binary_path = format!("./input/wavefunction_{}.mpk", wnum);
    let binary_path_partial = format!("./input/wavefunction_{}_partial.mpk", wnum);
    let binary_file = if Path::new(&binary_path).exists() {
        Some(binary_path)
    } else if Path::new(&binary_path_partial).exists() {
        Some(binary_path_partial)
    } else {
        None
    };

    if plain_file.is_some() && binary_file.is_some() {
        warn!(log,
              "Multiple wavefunction_{} files found in input directory. Chosing '{}' version based on configuration settings.",
              wnum,
              if binary { "mpk" } else { "csv" });
        if binary {
            wavefunction_plain(plain_file.unwrap(), target_size, bb)
        } else {
            wavefunction_binary(binary_file.unwrap(), target_size, bb)
        }
    } else if plain_file.is_some() {
        wavefunction_plain(plain_file.unwrap(), target_size, bb)
    } else if binary_file.is_some() {
        wavefunction_binary(binary_file.unwrap(), target_size, bb)
    } else {
        let missing = format!("wavefunction_{}*.*", wnum);
        Err(Error::NotFound { value: missing })
    }
}

/// Loads a wafefunction from a csv file on disk.
fn wavefunction_plain(file: String,
                      target_size: [usize; 3],
                      bb: usize)
                      -> Result<Array3<f64>, Error> {
    //No more to add here, just parse the file in the generic parser.
    parse_csv_to_array3(file, target_size, bb)
}

/// Loads a wafefunction from a mpk file on disk.
fn wavefunction_binary(file: String,
                       target_size: [usize; 3],
                       bb: usize)
                       -> Result<Array3<f64>, Error> {
    //TODO: Not implemented yet, call plain
    //NOTE: This will guarentee a failure from the file name.
    wavefunction_plain(file, target_size, bb)
}

/// Checks that the folder `input` exists. If not, creates it.
/// This doesn't specifically need to happen for all instances,
/// but we may want to put restart values in there later on.
pub fn check_input_dir() -> Result<(), Error> {
    //std::io::Error
    if !Path::new("./input").exists() {
        create_dir("./input")?;
    }
    Ok(())
}

/// Given a filename, this funtion reads in the data of a csv file and parses
/// the values into a 3D array. There are a few caveats to this as the file
/// may be of a different shape to the requested size in the configuration file.
/// The routine therefore attempts to resample/interpolate the data to fit the required
/// parameters.
///
/// # Arguments
///
/// * `file` - A filename wrapped in an option. This function is called from filename parsers
/// which may not be able to obtain a valid location.
/// * `target_size` - Requsted size of the resultant array. If this size does not match the data
/// pulled from the file, interpolation or resampling will occur.
///
/// # Returns
///
/// * A 3D array loaded with data from the file and resampled/interpolated if required.
/// If something goes wrong in the parsing or file handling, a `csv::Error` is passed.
fn parse_csv_to_array3(file: String,
                       target_size: [usize; 3],
                       bb: usize)
                       -> Result<Array3<f64>, Error> {
    let mut rdr = csv::ReaderBuilder::new()
        .has_headers(false)
        .from_path(file)?;
    let mut max_i = 0;
    let mut max_j = 0;
    let mut max_k = 0;
    let mut data: Vec<f64> = Vec::new();
    for result in rdr.deserialize() {
        let record: PlainRecord = result?;
        if record.i > max_i {
            max_i = record.i
        };
        if record.j > max_j {
            max_j = record.j
        };
        if record.k > max_k {
            max_k = record.k
        };
        data.push(record.data);
    }
    let numx = max_i + 1;
    let numy = max_j + 1;
    let numz = max_k + 1;
    match Array3::<f64>::from_shape_vec((numx, numy, numz), data) {
        Ok(result) => {
            //result is now a parsed Array3 with the work area inside.
            //We must fill this into an array with CD boundaries, provided
            //it is the correct size. If not, we must scale it.
            let init_size: [usize; 3] = [numx + bb, numy + bb, numz + bb];
            let mut complete = Array3::<f64>::zeros(target_size);
            {
                let mut work = grid::get_mut_work_area(&mut complete, bb / 2); //NOTE: This is a bit of a hack. But it works.
                let same: bool = init_size
                    .iter()
                    .zip(target_size.iter())
                    .all(|(a, b)| a == b);
                let smaller: bool = init_size.iter().zip(target_size.iter()).all(|(a, b)| a < b);
                let larger: bool = init_size.iter().zip(target_size.iter()).all(|(a, b)| a > b);
                if same {
                    // Input is the same size, copy down.
                    Zip::from(&mut work)
                        .and(result.view())
                        .par_apply(|work, &result| *work = result);
                } else if smaller {
                    //TODO: Input has lower resolution. Spread it out.
                    panic!("Wavefunction is lower in resolution than requested");
                } else if larger {
                    //TODO: Input has higer resolution. Sample it.
                    panic!("Wavefunction is higher in resolution than requested");
                } else {
                    //TODO: Dimensons are all over the shop. Sample and interp
                    panic!("Wavefunction differs in resolution from requested");
                }
            }
            Ok(complete)
        }
        Err(err) => Err(Error::Shape(err)),
    }
}
<|endoftext|>


<commit_before>//Implements http://rosettacode.org/wiki/9_billion_names_of_God_the_integer

extern crate num;

use num::bigint::BigUint;
use std::from_str::FromStr;
use std::string::String;
use std::cmp::min;

 fn cumu<'a>(num: uint, cache: &'a mut Vec<Vec<BigUint>>) -> &'a Vec<BigUint> {

    let mut len =0;
    for num in cache.iter()
    {
    	len = len+1;
    }

    for l in range(len, num+1)
    {
	    let initial_value:BigUint = FromStr::from_str("0").unwrap();
	    let mut r: Vec<BigUint> = vec!(initial_value);

	    for x in range(1, l+1)
	    {
		 let y = r.get(x -1).clone();
		 let z = cache.get(l-x).get(min(x, l-x)).clone();
		 let w = y+z;

		 r.push(w)

	    }

	    cache.push(r);

    }

    cache.get(num)
}

// Returns a line
#[cfg(not(test))]
fn row(num: uint,  cache: &mut Vec<Vec<BigUint>>) -> String {

	let r = cumu(num,cache);
	let mut returned_string = String::new();
	for i in range(0,num)
	{
		let i = *r.get(i+1) - *r.get (i);
		let z = i.to_str();
		let y = z.as_slice();
		returned_string.push_str(y);
		returned_string.push_str(", ");
	}
	returned_string

}

#[cfg(not(test))]
fn main()
{

	    let mut cache: Vec<Vec<BigUint>> = Vec::new();

	    let initial_value:BigUint = FromStr::from_str("1").unwrap();

	    let initial_vector : Vec<BigUint> = vec!(initial_value);
	    cache.push(initial_vector);

	    println!("rows");
	    for n in range(1, 11)
	    {
			let x = n as uint;
			println!("{}: {}", n, row(x,&mut cache));
	    }

	    println!("sums");

	    let x: Vec<uint> = vec!(23, 123, 1234, 12345);
	    for y in x.iter()
	    {
			let z = cumu(*y,&mut cache);
			let w = z.last();
			println!("{}: {}", y, w.unwrap());

	   }

}

#[test]
fn test_cumu()
{

	    let mut cache: Vec<Vec<BigUint>> = Vec::new();

	    let initial_value:BigUint = FromStr::from_str("1").unwrap();

	    let initial_vector : Vec<BigUint> = vec!(initial_value);
	    cache.push(initial_vector);

	    let a: Vec<uint> = vec!(23, 123, 1234);
	    let b: Vec<BigUint> = vec!(FromStr::from_str("1255").unwrap(), FromStr::from_str("2552338241").unwrap(), FromStr::from_str("156978797223733228787865722354959930").unwrap());
	    let mut n=0;
	    for y in a.iter()
	    {
			let z = cumu(*y,&mut cache);
			let w = z.last().unwrap();
			assert!(w == b.get(n));
			n= n+1;

	   }
}

<commit_msg>Fixes and another test<commit_after>//Implements http://rosettacode.org/wiki/9_billion_names_of_God_the_integer

extern crate num;

use num::bigint::BigUint;
use std::from_str::FromStr;
use std::string::String;
use std::cmp::min;

 fn cumu<'a>(num: uint, cache: &'a mut Vec<Vec<BigUint>>) -> &'a Vec<BigUint> {

    let len = cache.len();

    for l in range(len, num+1)
    {
	    let initial_value:BigUint = FromStr::from_str("0").unwrap();
	    let mut r: Vec<BigUint> = vec!(initial_value);

	    for x in range(1, l+1)
	    {
		 let y = r.get(x -1).clone();
		 let z = cache.get(l-x).get(min(x, l-x)).clone();
		 let w = y+z;

		 r.push(w)

	    }

	    cache.push(r);

    }

    cache.get(num)
}

// Returns a line

fn row(num: uint,  cache: &mut Vec<Vec<BigUint>>) -> String {

	let r = cumu(num,cache);
	let mut returned_string = String::new();
	for i in range(0,num)
	{
		let i = *r.get(i+1) - *r.get (i);
		let z = i.to_str();
		let y = z.as_slice();
		returned_string.push_str(y);
		returned_string.push_str(", ");
	}
	returned_string

}

#[cfg(not(test))]
fn main()
{

	    let mut cache: Vec<Vec<BigUint>> = Vec::new();

	    let initial_value:BigUint = FromStr::from_str("1").unwrap();

	    let initial_vector : Vec<BigUint> = vec!(initial_value);
	    cache.push(initial_vector);

	    println!("rows");
	    for n in range(1, 11)
	    {
			let x = n as uint;
			println!("{}: {}", n, row(x,&mut cache));
	    }

	    println!("sums");

	    let x: Vec<uint> = vec!(23, 123, 1234, 12345);
	    for y in x.iter()
	    {
			let z = cumu(*y,&mut cache);
			let w = z.last();
			println!("{}: {}", y, w.unwrap());

	   }

}

#[test]
fn test_cumu()
{

	    let mut cache: Vec<Vec<BigUint>> = Vec::new();

	    let initial_value:BigUint = FromStr::from_str("1").unwrap();

	    let initial_vector : Vec<BigUint> = vec!(initial_value);
	    cache.push(initial_vector);

	    let a: Vec<uint> = vec!(23, 123, 1234);
	    let b: Vec<BigUint> = vec!(FromStr::from_str("1255").unwrap(), FromStr::from_str("2552338241").unwrap(), FromStr::from_str("156978797223733228787865722354959930").unwrap());
	    let mut n=0;
	    for y in a.iter()
	    {
			let z = cumu(*y,&mut cache);
			let w = z.last().unwrap();
			assert!(w == b.get(n));
			n= n+1;

	   }
}

#[test]
fn test_row()
{

	    let mut cache: Vec<Vec<BigUint>> = Vec::new();

	    let initial_value:BigUint = FromStr::from_str("1").unwrap();

	    let initial_vector : Vec<BigUint> = vec!(initial_value);
	    cache.push(initial_vector);

	    let a: String = FromStr::from_str("1, 2, 1, 1, ").unwrap();

		let x = 4;
			assert!(a == row(x,&mut cache));

}

<|endoftext|>


<commit_before>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use record::Record;
use record::FluentError;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag, time, record);
        let message = try!(record.make_forwardable_json());
        let mut stream = try!(net::TcpStream::connect(self.addr));
        let _ = stream.write(&message.into_bytes());
        drop(stream);

        Ok(())
    }
}

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

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn post_to_fluentd() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }
}
<commit_msg>fluent: Handle error properly<commit_after>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use record::Record;
use record::FluentError;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag, time, record);
        let message = try!(record.make_forwardable_json());
        let mut stream = try!(net::TcpStream::connect(self.addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

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

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn post_to_fluentd() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }
}
<|endoftext|>


<commit_before>//! This module contains the code representing Mastodon nodes and API Clients
//!
use errors::*;
use futures::{Future, Stream};
use hyper::Client as WebClient;
use hyper::{Body, Uri, Method};
use hyper::Method::{Get, Patch, Post};
use hyper::client::Request;
use hyper::header::{Headers, ContentType, Authorization, Bearer};
use hyper_tls::HttpsConnector;
use mastodon::ApiHandler;
use serde_json;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use super::entities;
use super::methods;
use super::methods::{
    AccountID,
    APIEndpoint,
    APIEndpointRequest,
    HomeTimelineQuery,
    NotificationID,
    RelationshipsQuery,
    SearchAccountsQuery,
    SearchContentsQuery,
    StatusID,
    TagID,
    TimelineQuery,
    UserFormData
};
use tokio_core::reactor::Core;
use url::Url;

/// The API Client, currently works for version 1 of the Mastodon API.
pub struct Client {
    pub url_base: Url,
    pub token: Bearer
}

impl ApiHandler for Client {
    fn endpoint_url(&self, path: &str) -> Result<Url> {
        self.url_base.clone().join(path).chain_err(|| "could not join path with URL")
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).unwrap().into_string()
    }
}

impl APIEndpointRequest for Client {
    fn bearer_token_request(&self, method: Method, uri: Uri) -> Result<Request<Body>> {
        let mut req = Request::new(method, uri);
        req.headers_mut().set(Authorization(self.token.clone()));
        Ok(req)
    }
    fn build_request(&self, endpoint: APIEndpoint) -> Result<Request<Body>> {
        match endpoint {
            APIEndpoint::FetchAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetCurrentUser => {
                let url = self.endpoint_url("/api/v1/accounts/verify_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::UpdateCurrentUser(d) => {
                let url = self.endpoint_url("/api/v1/accounts/update_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Patch, uri)
            },
            APIEndpoint::GetAccountFollowers(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/followers", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetFollowing(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/following", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetAccountStatuses(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/statuses", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::FollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/follow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnfollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unfollow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::BlockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/block", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnblockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unblock", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::MuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/mute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnmuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unmute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::GetAccountRelationships(query) => {
                let mut url = self.endpoint_url("/api/v1/accounts/relationships").unwrap();
                match query {
                    RelationshipsQuery::SingleAccount(account) => {
                        url.query_pairs_mut().append_pair("id", &format!("{}", account.id));
                    },
                    RelationshipsQuery::MultipleAccounts(accounts) => {
                        for account in &accounts {
                            url.query_pairs_mut()
                                .append_pair("id[]", &format!("{}", account.id));
                        }
                    }
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::SearchAccounts(q) => {
                let mut url = self.endpoint_url("/api/v1/accounts/search").unwrap();
                url.query_pairs_mut().append_pair("q", &q.q);
                if let Some(limit) = q.limit {
                    url.query_pairs_mut().append_pair("limit", &format!("{}", limit));
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            }
        }
    }

    fn send(&self, endpoint: APIEndpoint, dst: Arc<Mutex<Vec<u8>>>) -> Result<()> {
        let mut core = Core::new().chain_err(|| "Could not start client reactor")?;
        let client = WebClient::configure()
            .connector(HttpsConnector::new(4, &core.handle()))
            .build(&core.handle());

        let req: Request<Body> = self.build_request(endpoint).chain_err(|| "Could not build request")?;
        //req.headers_mut().set(ContentType::form_url_encoded());
        //req.set_body(Body::from(self.form_encode()));

        let mut dst = dst.lock().unwrap();
        let work = client.request(req)
            .and_then(|res| {
                res.body().for_each(|chunk| {
                    dst.extend_from_slice(&chunk);
                    Ok(())
                })
            });
        core.run(work).chain_err(|| "Failed to run registration")?;
        Ok(())
    }
}

impl methods::Accounts for Client {
    fn fetch_account(&self, account_id: AccountID) -> Result<entities::Account> {
        let api_method = APIMethodRequest {
            uri: Uri::from_str(&format!("/api/v1/accounts/{}", account_id.id)).unwrap(),
            ..APIMethodRequest::default()
        };
        println!("FETCH ACCOUNT: {:?}", api_method);
        Ok(entities::Account::default())
    }
    fn get_current_user(&self) -> Result<entities::Account> {
        unimplemented!();
    }
    fn update_current_user(&self, form_data: UserFormData) -> Result<entities::Account> {
        unimplemented!()
    }
    fn get_account_followers(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_following(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_statutes(&self, account_id: AccountID) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn follow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unfollow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn block_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn unblock_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn mute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unmute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn get_account_relationships(&self, query: RelationshipsQuery) -> Result<Vec<entities::Relationship>> {
        unimplemented!()
    }
    fn search_accounts(&self, query: SearchAccountsQuery) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Blocks for Client {
    fn fetch_blocks(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Favourites for Client {
    fn fetch_favourites(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::FollowRequests for Client {
    fn fetch_follow_requests(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn authorize_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
    fn reject_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Follows for Client {
    fn follow_remote_user(&self, form_data: String) -> Result<entities::Account> {
        unimplemented!()
    }
}

impl methods::Instances for Client {
    fn get_instance(&self) -> Result<entities::Instance> {
        unimplemented!()
    }
}

impl methods::Media for Client {
    fn upload_media(&self, form_data: String) -> Result<entities::Attachment> {
        unimplemented!()
    }
}

impl methods::Mutes for Client {
    fn fetch_mutes(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}

impl methods::Notifications for Client {
    fn fetch_notifications(&self, query: String) -> Result<Vec<entities::Notification>> {
        unimplemented!()
    }
    fn get_notification(&self, notification_id: NotificationID) -> Result<entities::Notification> {
        unimplemented!()
    }
    fn clear_notifications(&self) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Reports for Client {
    fn fetching_reports(&self) -> Result<Vec<entities::Report>> {
        unimplemented!()
    }
    fn reporting_user(&self, form_data: String) -> Result<entities::Report> {
        unimplemented!()
    }
}

impl methods::Search for Client {
    fn search_content(&self, query: SearchContentsQuery) -> Result<entities::Results> {
        unimplemented!()
    }
}

impl methods::Statuses for Client {
    fn fetch_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_context(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_card(&self, status_id: StatusID) -> Result<entities::Card> {
        unimplemented!()
    }
    fn reblogged_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn favourited_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn post_status(&self, form_data: String) -> Result<entities::Status> {
        unimplemented!()
    }
    fn delete_status(&self, status_id: StatusID) -> Result<()> {
        unimplemented!()
    }
    fn reblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unreblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn favourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unfavourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
}

impl methods::Timelines for Client {
    fn home_timeline(&self, query: HomeTimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn public_timeline(&self, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn tag_timeline(&self, hashtag: TagID, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
}
<commit_msg>implement a few of the Accounts trait methods<commit_after>//! This module contains the code representing Mastodon nodes and API Clients
//!
use errors::*;
use futures::{Future, Stream};
use hyper::Client as WebClient;
use hyper::{Body, Uri, Method};
use hyper::Method::{Get, Patch, Post};
use hyper::client::Request;
use hyper::header::{Headers, ContentType, Authorization, Bearer};
use hyper_tls::HttpsConnector;
use mastodon::ApiHandler;
use serde_json;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use super::entities;
use super::methods;
use super::methods::{
    AccountID,
    APIEndpoint,
    APIEndpointRequest,
    HomeTimelineQuery,
    NotificationID,
    RelationshipsQuery,
    SearchAccountsQuery,
    SearchContentsQuery,
    StatusID,
    TagID,
    TimelineQuery,
    UserFormData
};
use tokio_core::reactor::Core;
use url::Url;

/// The API Client, currently works for version 1 of the Mastodon API.
pub struct Client {
    pub url_base: Url,
    pub token: Bearer
}

impl ApiHandler for Client {
    fn endpoint_url(&self, path: &str) -> Result<Url> {
        self.url_base.clone().join(path).chain_err(|| "could not join path with URL")
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).unwrap().into_string()
    }
}

impl APIEndpointRequest for Client {
    fn bearer_token_request(&self, method: Method, uri: Uri) -> Result<Request<Body>> {
        let mut req = Request::new(method, uri);
        req.headers_mut().set(Authorization(self.token.clone()));
        Ok(req)
    }
    fn build_request(&self, endpoint: APIEndpoint) -> Result<Request<Body>> {
        match endpoint {
            APIEndpoint::FetchAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetCurrentUser => {
                let url = self.endpoint_url("/api/v1/accounts/verify_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::UpdateCurrentUser(d) => {
                let url = self.endpoint_url("/api/v1/accounts/update_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Patch, uri)
            },
            APIEndpoint::GetAccountFollowers(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/followers", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetFollowing(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/following", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetAccountStatuses(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/statuses", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::FollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/follow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnfollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unfollow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::BlockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/block", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnblockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unblock", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::MuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/mute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnmuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unmute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::GetAccountRelationships(query) => {
                let mut url = self.endpoint_url("/api/v1/accounts/relationships").unwrap();
                match query {
                    RelationshipsQuery::SingleAccount(account) => {
                        url.query_pairs_mut().append_pair("id", &format!("{}", account.id));
                    },
                    RelationshipsQuery::MultipleAccounts(accounts) => {
                        for account in &accounts {
                            url.query_pairs_mut()
                                .append_pair("id[]", &format!("{}", account.id));
                        }
                    }
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::SearchAccounts(q) => {
                let mut url = self.endpoint_url("/api/v1/accounts/search").unwrap();
                url.query_pairs_mut().append_pair("q", &q.q);
                if let Some(limit) = q.limit {
                    url.query_pairs_mut().append_pair("limit", &format!("{}", limit));
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            }
        }
    }

    fn send(&self, endpoint: APIEndpoint, dst: Arc<Mutex<Vec<u8>>>) -> Result<()> {
        let mut core = Core::new().chain_err(|| "Could not start client reactor")?;
        let client = WebClient::configure()
            .connector(HttpsConnector::new(4, &core.handle()))
            .build(&core.handle());

        let req: Request<Body> = self.build_request(endpoint).chain_err(|| "Could not build request")?;
        //req.headers_mut().set(ContentType::form_url_encoded());
        //req.set_body(Body::from(self.form_encode()));

        let mut dst = dst.lock().unwrap();
        let work = client.request(req)
            .and_then(|res| {
                res.body().for_each(|chunk| {
                    dst.extend_from_slice(&chunk);
                    Ok(())
                })
            });
        core.run(work).chain_err(|| "Failed to run registration")?;
        Ok(())
    }
}

impl methods::Accounts for Client {
    fn fetch_account(&self, account_id: AccountID) -> Result<entities::Account> {
        let data = Arc::new(Mutex::new(Vec::new()));
        let endpoint = APIEndpoint::FetchAccount(account_id);
        self.send(endpoint, data.clone()).unwrap();
        let data = data.lock().unwrap();
        serde_json::from_slice(&data).chain_err(|| "Unexpected JSON error fetching account.")
    }
    fn get_current_user(&self) -> Result<entities::Account> {
        let data = Arc::new(Mutex::new(Vec::new()));
        let endpoint = APIEndpoint::GetCurrentUser;
        self.send(endpoint, data.clone()).unwrap();
        let data = data.lock().unwrap();
        serde_json::from_slice(&data).chain_err(|| "Unexpected JSON error getting current user.")
    }
    fn update_current_user(&self, form_data: UserFormData) -> Result<entities::Account> {
        let data = Arc::new(Mutex::new(Vec::new()));
        let endpoint = APIEndpoint::UpdateCurrentUser(form_data);;
        self.send(endpoint, data.clone()).unwrap();
        let data = data.lock().unwrap();
        serde_json::from_slice(&data).chain_err(|| "Unexpected JSON error updating current user.")
    }
    fn get_account_followers(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        let data = Arc::new(Mutex::new(Vec::new()));
        let endpoint = APIEndpoint::GetAccountFollowers(account_id);;
        self.send(endpoint, data.clone()).unwrap();
        let data = data.lock().unwrap();
        serde_json::from_slice(&data).chain_err(|| "Unexpected JSON error getting account followers.")
    }
    fn get_account_following(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        let data = Arc::new(Mutex::new(Vec::new()));
        let endpoint = APIEndpoint::GetFollowing(account_id);;
        self.send(endpoint, data.clone()).unwrap();
        let data = data.lock().unwrap();
        serde_json::from_slice(&data).chain_err(|| "Unexpected JSON error getting account's following.")
    }
    fn get_account_statutes(&self, account_id: AccountID) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn follow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unfollow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn block_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn unblock_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn mute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unmute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn get_account_relationships(&self, query: RelationshipsQuery) -> Result<Vec<entities::Relationship>> {
        unimplemented!()
    }
    fn search_accounts(&self, query: SearchAccountsQuery) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Blocks for Client {
    fn fetch_blocks(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Favourites for Client {
    fn fetch_favourites(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::FollowRequests for Client {
    fn fetch_follow_requests(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn authorize_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
    fn reject_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Follows for Client {
    fn follow_remote_user(&self, form_data: String) -> Result<entities::Account> {
        unimplemented!()
    }
}

impl methods::Instances for Client {
    fn get_instance(&self) -> Result<entities::Instance> {
        unimplemented!()
    }
}

impl methods::Media for Client {
    fn upload_media(&self, form_data: String) -> Result<entities::Attachment> {
        unimplemented!()
    }
}

impl methods::Mutes for Client {
    fn fetch_mutes(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}

impl methods::Notifications for Client {
    fn fetch_notifications(&self, query: String) -> Result<Vec<entities::Notification>> {
        unimplemented!()
    }
    fn get_notification(&self, notification_id: NotificationID) -> Result<entities::Notification> {
        unimplemented!()
    }
    fn clear_notifications(&self) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Reports for Client {
    fn fetching_reports(&self) -> Result<Vec<entities::Report>> {
        unimplemented!()
    }
    fn reporting_user(&self, form_data: String) -> Result<entities::Report> {
        unimplemented!()
    }
}

impl methods::Search for Client {
    fn search_content(&self, query: SearchContentsQuery) -> Result<entities::Results> {
        unimplemented!()
    }
}

impl methods::Statuses for Client {
    fn fetch_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_context(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_card(&self, status_id: StatusID) -> Result<entities::Card> {
        unimplemented!()
    }
    fn reblogged_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn favourited_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn post_status(&self, form_data: String) -> Result<entities::Status> {
        unimplemented!()
    }
    fn delete_status(&self, status_id: StatusID) -> Result<()> {
        unimplemented!()
    }
    fn reblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unreblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn favourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unfavourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
}

impl methods::Timelines for Client {
    fn home_timeline(&self, query: HomeTimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn public_timeline(&self, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn tag_timeline(&self, hashtag: TagID, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use bincode::{SizeLimit, serde as bincode};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use futures::{Async, Poll};
use serde;
use std::io::{self, Cursor};
use std::marker::PhantomData;
use std::mem;
use tokio_core::easy::{self, EasyBuf, EasyFramed};
use tokio_core::io::{FramedIo, Io};
use tokio_proto::multiplex::{self, RequestId};
use util::Never;

/// Handles the IO of tarpc messages.
pub struct Framed<I, In, Out> {
    inner: EasyFramed<I, Parser<Out>, Serializer<In>>,
}

impl<I, In, Out> Framed<I, In, Out> {
    /// Constructs a new tarpc FramedIo
    pub fn new(upstream: I) -> Framed<I, In, Out>
        where I: Io,
              In: serde::Serialize,
              Out: serde::Deserialize
    {
        Framed { inner: EasyFramed::new(upstream, Parser::new(), Serializer::new()) }
    }
}

/// The type of message sent and received by the transport.
pub type Frame<T> = multiplex::Frame<T, Never, io::Error>;

impl<I, In, Out> FramedIo for Framed<I, In, Out>
    where I: Io,
          In: serde::Serialize,
          Out: serde::Deserialize
{
    type In = (RequestId, In);
    type Out = Option<(RequestId, Result<Out, bincode::DeserializeError>)>;

    fn poll_read(&mut self) -> Async<()> {
        self.inner.poll_read()
    }

    fn poll_write(&mut self) -> Async<()> {
        self.inner.poll_write()
    }

    fn read(&mut self) -> Poll<Self::Out, io::Error> {
        self.inner.read()
    }

    fn write(&mut self, req: Self::In) -> Poll<(), io::Error> {
        self.inner.write(req)
    }

    fn flush(&mut self) -> Poll<(), io::Error> {
        self.inner.flush()
    }
}

// `T` is the type that `Parser` parses.
struct Parser<T> {
    state: ParserState,
    _phantom_data: PhantomData<T>,
}

enum ParserState {
    Id,
    Len { id: u64 },
    Payload { id: u64, len: u64 },
}

impl<T> Parser<T> {
    fn new() -> Self {
        Parser {
            state: ParserState::Id,
            _phantom_data: PhantomData,
        }
    }
}

impl<T> easy::Parse for Parser<T>
    where T: serde::Deserialize
{
    type Out = (RequestId, Result<T, bincode::DeserializeError>);

    fn parse(&mut self, buf: &mut EasyBuf) -> Poll<Self::Out, io::Error> {
        use self::ParserState::*;

        loop {
            match self.state {
                Id if buf.len() < mem::size_of::<u64>() => return Ok(Async::NotReady),
                Id => {
                    self.state = Len { id: Cursor::new(&*buf.get_mut()).read_u64::<BigEndian>()? };
                    *buf = buf.split_off(mem::size_of::<u64>());
                }
                Len { .. } if buf.len() < mem::size_of::<u64>() => return Ok(Async::NotReady),
                Len { id } => {
                    self.state = Payload {
                        id: id,
                        len: Cursor::new(&*buf.get_mut()).read_u64::<BigEndian>()?,
                    };
                    *buf = buf.split_off(mem::size_of::<u64>());
                }
                Payload { len, .. } if buf.len() < len as usize => return Ok(Async::NotReady),
                Payload { id, .. } => {
                    let mut buf = buf.get_mut();
                    let result = bincode::deserialize_from(&mut Cursor::new(&mut *buf),
                                                           SizeLimit::Infinite);
                    // Clear any unread bytes so we don't read garbage on next request.
                    buf.clear();
                    // Reset the state machine because, either way, we're done processing this
                    // message.
                    self.state = Id;

                    return Ok(Async::Ready((id, result)));
                }
            }
        }
    }
}

struct Serializer<T>(PhantomData<T>);

impl<T> Serializer<T> {
    fn new() -> Self {
        Serializer(PhantomData)
    }
}

impl<T> easy::Serialize for Serializer<T>
    where T: serde::Serialize
{
    type In = (RequestId, T);

    fn serialize(&mut self, (id, message): Self::In, buf: &mut Vec<u8>) {
        buf.write_u64::<BigEndian>(id).unwrap();
        buf.write_u64::<BigEndian>(bincode::serialized_size(&message)).unwrap();
        bincode::serialize_into(buf,
                                &message,
                                SizeLimit::Infinite)
                 // TODO(tikue): handle err
                 .expect("In bincode::serialize_into");
    }
}

#[test]
fn serialize() {
    use tokio_core::easy::{Parse, Serialize};

    const MSG: (u64, (char, char, char)) = (4, ('a', 'b', 'c'));
    let mut buf = EasyBuf::new();
    let mut vec = Vec::new();

    // Serialize twice to check for idempotence.
    for _ in 0..2 {
        Serializer::new().serialize(MSG, &mut vec);
        buf.get_mut().append(&mut vec);
        let actual: Poll<(u64, Result<(char, char, char), bincode::DeserializeError>), io::Error> =
            Parser::new().parse(&mut buf);

        match actual {
            Ok(Async::Ready((id, ref v))) if id == MSG.0 && *v.as_ref().unwrap() == MSG.1 => {}
            bad => panic!("Expected {:?}, but got {:?}", Some(MSG), bad),
        }

        assert!(buf.get_mut().is_empty(),
                "Expected empty buf but got {:?}",
                *buf.get_mut());
    }
}
<commit_msg>Elaborate in the doc comment for Framed<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use bincode::{SizeLimit, serde as bincode};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use futures::{Async, Poll};
use serde;
use std::io::{self, Cursor};
use std::marker::PhantomData;
use std::mem;
use tokio_core::easy::{self, EasyBuf, EasyFramed};
use tokio_core::io::{FramedIo, Io};
use tokio_proto::multiplex::{self, RequestId};
use util::Never;

/// Handles the IO of tarpc messages. Similar to `tokio_core::easy::EasyFramed` except that it
/// hardcodes a parser and serializer suitable for tarpc messages.
pub struct Framed<I, In, Out> {
    inner: EasyFramed<I, Parser<Out>, Serializer<In>>,
}

impl<I, In, Out> Framed<I, In, Out> {
    /// Constructs a new tarpc FramedIo
    pub fn new(upstream: I) -> Framed<I, In, Out>
        where I: Io,
              In: serde::Serialize,
              Out: serde::Deserialize
    {
        Framed { inner: EasyFramed::new(upstream, Parser::new(), Serializer::new()) }
    }
}

/// The type of message sent and received by the transport.
pub type Frame<T> = multiplex::Frame<T, Never, io::Error>;

impl<I, In, Out> FramedIo for Framed<I, In, Out>
    where I: Io,
          In: serde::Serialize,
          Out: serde::Deserialize
{
    type In = (RequestId, In);
    type Out = Option<(RequestId, Result<Out, bincode::DeserializeError>)>;

    fn poll_read(&mut self) -> Async<()> {
        self.inner.poll_read()
    }

    fn poll_write(&mut self) -> Async<()> {
        self.inner.poll_write()
    }

    fn read(&mut self) -> Poll<Self::Out, io::Error> {
        self.inner.read()
    }

    fn write(&mut self, req: Self::In) -> Poll<(), io::Error> {
        self.inner.write(req)
    }

    fn flush(&mut self) -> Poll<(), io::Error> {
        self.inner.flush()
    }
}

// `T` is the type that `Parser` parses.
struct Parser<T> {
    state: ParserState,
    _phantom_data: PhantomData<T>,
}

enum ParserState {
    Id,
    Len { id: u64 },
    Payload { id: u64, len: u64 },
}

impl<T> Parser<T> {
    fn new() -> Self {
        Parser {
            state: ParserState::Id,
            _phantom_data: PhantomData,
        }
    }
}

impl<T> easy::Parse for Parser<T>
    where T: serde::Deserialize
{
    type Out = (RequestId, Result<T, bincode::DeserializeError>);

    fn parse(&mut self, buf: &mut EasyBuf) -> Poll<Self::Out, io::Error> {
        use self::ParserState::*;

        loop {
            match self.state {
                Id if buf.len() < mem::size_of::<u64>() => return Ok(Async::NotReady),
                Id => {
                    self.state = Len { id: Cursor::new(&*buf.get_mut()).read_u64::<BigEndian>()? };
                    *buf = buf.split_off(mem::size_of::<u64>());
                }
                Len { .. } if buf.len() < mem::size_of::<u64>() => return Ok(Async::NotReady),
                Len { id } => {
                    self.state = Payload {
                        id: id,
                        len: Cursor::new(&*buf.get_mut()).read_u64::<BigEndian>()?,
                    };
                    *buf = buf.split_off(mem::size_of::<u64>());
                }
                Payload { len, .. } if buf.len() < len as usize => return Ok(Async::NotReady),
                Payload { id, .. } => {
                    let mut buf = buf.get_mut();
                    let result = bincode::deserialize_from(&mut Cursor::new(&mut *buf),
                                                           SizeLimit::Infinite);
                    // Clear any unread bytes so we don't read garbage on next request.
                    buf.clear();
                    // Reset the state machine because, either way, we're done processing this
                    // message.
                    self.state = Id;

                    return Ok(Async::Ready((id, result)));
                }
            }
        }
    }
}

struct Serializer<T>(PhantomData<T>);

impl<T> Serializer<T> {
    fn new() -> Self {
        Serializer(PhantomData)
    }
}

impl<T> easy::Serialize for Serializer<T>
    where T: serde::Serialize
{
    type In = (RequestId, T);

    fn serialize(&mut self, (id, message): Self::In, buf: &mut Vec<u8>) {
        buf.write_u64::<BigEndian>(id).unwrap();
        buf.write_u64::<BigEndian>(bincode::serialized_size(&message)).unwrap();
        bincode::serialize_into(buf,
                                &message,
                                SizeLimit::Infinite)
                 // TODO(tikue): handle err
                 .expect("In bincode::serialize_into");
    }
}

#[test]
fn serialize() {
    use tokio_core::easy::{Parse, Serialize};

    const MSG: (u64, (char, char, char)) = (4, ('a', 'b', 'c'));
    let mut buf = EasyBuf::new();
    let mut vec = Vec::new();

    // Serialize twice to check for idempotence.
    for _ in 0..2 {
        Serializer::new().serialize(MSG, &mut vec);
        buf.get_mut().append(&mut vec);
        let actual: Poll<(u64, Result<(char, char, char), bincode::DeserializeError>), io::Error> =
            Parser::new().parse(&mut buf);

        match actual {
            Ok(Async::Ready((id, ref v))) if id == MSG.0 && *v.as_ref().unwrap() == MSG.1 => {}
            bad => panic!("Expected {:?}, but got {:?}", Some(MSG), bad),
        }

        assert!(buf.get_mut().is_empty(),
                "Expected empty buf but got {:?}",
                *buf.get_mut());
    }
}
<|endoftext|>


<commit_before>use libc::{c_char, c_int, c_ulong};
use std::io::{self, Error};

#[cfg(target_os = "linux")]
use libc::{
    c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t, AF_AX25, AF_PACKET, SOCK_RAW,
};
#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
#[cfg(target_os = "linux")]
use std::mem;

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

#[cfg(target_os = "linux")]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        use std::fs::File;
        use std::io::{BufRead, BufReader};

        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }
}

#[cfg(not(target_os = "linux"))]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        Ok(Vec::new())
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        Err(Error::new(
            ErrorKind::NotConnected,
            "only supported on linux",
        ))
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        Err(Error::new(
            ErrorKind::NotConnected,
            "only supported on linux",
        ))
    }
}

#[cfg(target_os = "linux")]
fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Ok(addr) = String::from_utf8(addr_utf8) {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<commit_msg>Reorganise the cfg much more clearly<commit_after>#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
use std::io::{self, Error};

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    #[cfg(target_os = "linux")]
    fd: i32,
}

#[cfg(target_os = "linux")]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_new()
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_close(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_list_ax25_interfaces(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Ok(Vec::new())
        }
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_send_frame(self, frame, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_receive_frame(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }
}

/// Keeps all the linux interface-specific code in one place
#[cfg(target_os = "linux")]
mod sys {
    use super::*;
    use libc::{c_char, c_int, c_ulong};
    use libc::{
        c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t, AF_AX25, AF_PACKET,
        SOCK_RAW,
    };
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::mem;

    const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
    const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
    const SIOCGIFINDEX: c_ulong = 0x8933;

    pub fn socket_new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    pub fn socket_close(socket: &mut Ax25RawSocket) -> io::Result<()> {
        match unsafe { close(socket.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_list_ax25_interfaces(socket: &Ax25RawSocket) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, socket.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    pub fn socket_send_frame(socket: &Ax25RawSocket, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                socket.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_receive_frame(socket: &Ax25RawSocket) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                socket.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }

    fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
        let mut req = ifreq::default();
        let if_name = name.to_owned();
        for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
            *d = *s as c_char;
        }

        if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
            return None;
        }
        if req.data.address_family() as i32 != AF_AX25 {
            return None;
        }
        let hw_addr = match req.data.ax25_address() {
            Some(addr) => addr,
            None => return None,
        };

        if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
            return None;
        }
        let ifindex = req.data.ifindex();

        Some(NetDev {
            name: hw_addr,
            ifindex,
        })
    }

    extern "C" {
        fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
    }

    #[repr(C)]
    struct ifreq {
        ifr_name: [c_char; 16],
        data: ifreq_union,
    }

    impl Default for ifreq {
        fn default() -> ifreq {
            ifreq {
                ifr_name: [0; 16],
                data: ifreq_union::default(),
            }
        }
    }

    #[repr(C)]
    struct ifreq_union {
        data: [u8; 24],
    }

    impl Default for ifreq_union {
        fn default() -> ifreq_union {
            ifreq_union { data: [0; 24] }
        }
    }

    impl ifreq_union {
        fn ifindex(&self) -> c_int {
            c_int::from_be(
                ((self.data[0] as c_int) << 24)
                    + ((self.data[1] as c_int) << 16)
                    + ((self.data[2] as c_int) << 8)
                    + (self.data[3] as c_int),
            )
        }

        fn address_family(&self) -> u16 {
            u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
        }

        fn ax25_address(&self) -> Option<String> {
            let mut addr_utf8: Vec<u8> = self.data[2..8]
                .iter()
                .rev()
                .map(|&c| c >> 1)
                .skip_while(|&c| c == 0)
                .collect::<Vec<u8>>();
            addr_utf8.reverse();
            let ssid = (self.data[8] >> 1) & 0x0f;
            if let Ok(addr) = String::from_utf8(addr_utf8) {
                return Some(format!("{}-{}", addr, ssid));
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::SocketAddr;
use std::any::Any;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;

use tokio_core::reactor;
use tokio_io::AsyncRead;
use tokio_io::AsyncWrite;

use futures::stream::Stream;
use futures::Future;

use server_conf::ServerConf;

pub trait ToSocketListener {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send>;

    fn cleanup(&self);
}

#[derive(Clone)]
pub enum AnySocketAddr {
    Inet(SocketAddr),
    #[cfg(unix)]
    Unix(String)
}

impl Display for AnySocketAddr {
    fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
          match *self {
            AnySocketAddr::Inet(ref inet_addr) => Display::fmt(inet_addr, f),
            #[cfg(unix)]
            AnySocketAddr::Unix(ref unix_addr) => Display::fmt(unix_addr, f),
        }
    }
}

impl AnySocketAddr {
    pub fn port(&self) -> io::Result<u16> {
         match self {
            &AnySocketAddr::Inet(ref inet_addr) => Ok(inet_addr.port()),
            #[cfg(unix)]
            &AnySocketAddr::Unix(_) =>
                Err(io::Error::new(io::ErrorKind::Other, "Cannot get port from unix domain socket"))
        }
    }
}

impl ToSocketListener for AnySocketAddr {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send> {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.to_listener(conf),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.to_listener(conf)
        }
    }

    fn cleanup(&self) {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.cleanup(),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.cleanup(),
        }
    }
}

impl ToClientStream for AnySocketAddr {
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>
    {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.connect(handle),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.connect(handle),
        }
    }
}

pub trait ToTokioListener {
    fn to_tokio_listener(self: Box<Self>, handle: &reactor::Handle) -> Box<ToServerStream>;

    fn local_addr(&self) -> io::Result<AnySocketAddr>;
}

pub trait ToServerStream {
    fn incoming(self: Box<Self>)
        -> Box<Stream<Item=(Box<StreamItem>, Box<Any>), Error=io::Error>>;
}

pub trait ToClientStream:
        Display +
        Send + Sync
{
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>;
}

pub trait StreamItem:
        AsyncRead +
        AsyncWrite +
        io::Read +
        io::Write +
        Debug +
        Send + Sync
{
    fn is_tcp(&self) -> bool;

    fn set_nodelay(&self, no_delay: bool) -> io::Result<()>;
}
<commit_msg>Use AnySocketAddr::Unix available anywhere<commit_after>use std::io;
use std::net::SocketAddr;
use std::any::Any;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;

use tokio_core::reactor;
use tokio_io::AsyncRead;
use tokio_io::AsyncWrite;

use futures::stream::Stream;
use futures::Future;

use server_conf::ServerConf;

pub trait ToSocketListener {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send>;

    fn cleanup(&self);
}

#[derive(Clone)]
pub enum AnySocketAddr {
    Inet(SocketAddr),
    Unix(String)
}

impl Display for AnySocketAddr {
    fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
          match *self {
            AnySocketAddr::Inet(ref inet_addr) => Display::fmt(inet_addr, f),
            AnySocketAddr::Unix(ref unix_addr) => Display::fmt(unix_addr, f),
        }
    }
}

impl AnySocketAddr {
    pub fn port(&self) -> io::Result<u16> {
         match self {
            &AnySocketAddr::Inet(ref inet_addr) => Ok(inet_addr.port()),
            &AnySocketAddr::Unix(_) =>
                Err(io::Error::new(io::ErrorKind::Other, "Cannot get port from unix domain socket"))
        }
    }
}

impl ToSocketListener for AnySocketAddr {
    fn to_listener(&self, conf: &ServerConf) -> Box<ToTokioListener + Send> {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.to_listener(conf),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.to_listener(conf),
            #[cfg(not(unix))]
            // TODO: error instead of panic
            &AnySocketAddr::Unix(..) => panic!("cannot use unix sockets on non-unix"),
        }
    }

    fn cleanup(&self) {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.cleanup(),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.cleanup(),
            #[cfg(not(unix))]
            &AnySocketAddr::Unix(..) => {},
        }
    }
}

impl ToClientStream for AnySocketAddr {
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>
    {
        match self {
            &AnySocketAddr::Inet(ref inet_addr) => inet_addr.connect(handle),
            #[cfg(unix)]
            &AnySocketAddr::Unix(ref unix_addr) => unix_addr.connect(handle),
            #[cfg(not(unix))]
            &AnySocketAddr::Unix(..) => panic!("cannot use unix sockets on non-unix"),
        }
    }
}

pub trait ToTokioListener {
    fn to_tokio_listener(self: Box<Self>, handle: &reactor::Handle) -> Box<ToServerStream>;

    fn local_addr(&self) -> io::Result<AnySocketAddr>;
}

pub trait ToServerStream {
    fn incoming(self: Box<Self>)
        -> Box<Stream<Item=(Box<StreamItem>, Box<Any>), Error=io::Error>>;
}

pub trait ToClientStream:
        Display +
        Send + Sync
{
    fn connect(&self, handle: &reactor::Handle)
        -> Box<Future<Item=Box<StreamItem>, Error=io::Error> + Send>;
}

pub trait StreamItem:
        AsyncRead +
        AsyncWrite +
        io::Read +
        io::Write +
        Debug +
        Send + Sync
{
    fn is_tcp(&self) -> bool;

    fn set_nodelay(&self, no_delay: bool) -> io::Result<()>;
}
<|endoftext|>