<commit_before>// TODO: Make -w flag work with decimals
// TODO: Support -f flag

// spell-checker:ignore (ToDO) istr chiter argptr ilen

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, AppSettings, Arg};
use num_bigint::BigInt;
use num_traits::One;
use num_traits::Zero;
use num_traits::{Num, ToPrimitive};
use std::cmp;
use std::io::{stdout, ErrorKind, Write};
use std::str::FromStr;
use uucore::display::Quotable;

static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
static OPT_SEPARATOR: &str = "separator";
static OPT_TERMINATOR: &str = "terminator";
static OPT_WIDTHS: &str = "widths";

static ARG_NUMBERS: &str = "numbers";

fn usage() -> String {
    format!(
        "{0} [OPTION]... LAST
    {0} [OPTION]... FIRST LAST
    {0} [OPTION]... FIRST INCREMENT LAST",
        uucore::execution_phrase()
    )
}
#[derive(Clone)]
struct SeqOptions {
    separator: String,
    terminator: String,
    widths: bool,
}

enum Number {
    /// Negative zero, as if it were an integer.
    MinusZero,
    BigInt(BigInt),
    F64(f64),
}

impl Number {
    fn is_zero(&self) -> bool {
        match self {
            Number::MinusZero => true,
            Number::BigInt(n) => n.is_zero(),
            Number::F64(n) => n.is_zero(),
        }
    }

    fn into_f64(self) -> f64 {
        match self {
            Number::MinusZero => -0.,
            // BigInt::to_f64() can not return None.
            Number::BigInt(n) => n.to_f64().unwrap(),
            Number::F64(n) => n,
        }
    }

    /// Number of characters needed to print the integral part of the number.
    ///
    /// The number of characters includes one character to represent the
    /// minus sign ("-") if this number is negative.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use num_bigint::{BigInt, Sign};
    ///
    /// assert_eq!(
    ///     Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
    ///     3
    /// );
    /// assert_eq!(
    ///     Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
    ///     4
    /// );
    /// assert_eq!(Number::F64(123.45).num_digits(), 3);
    /// assert_eq!(Number::MinusZero.num_digits(), 2);
    /// ```
    fn num_digits(&self) -> usize {
        match self {
            Number::MinusZero => 2,
            Number::BigInt(n) => n.to_string().len(),
            Number::F64(n) => {
                let s = n.to_string();
                s.find('.').unwrap_or_else(|| s.len())
            }
        }
    }
}

impl FromStr for Number {
    type Err = String;
    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
        s = s.trim_start();
        if s.starts_with('+') {
            s = &s[1..];
        }

        match s.parse::<BigInt>() {
            Ok(n) => {
                // If `s` is '-0', then `parse()` returns
                // `BigInt::zero()`, but we need to return
                // `Number::MinusZero` instead.
                if n == BigInt::zero() && s.starts_with('-') {
                    Ok(Number::MinusZero)
                } else {
                    Ok(Number::BigInt(n))
                }
            }
            Err(_) => match s.parse::<f64>() {
                Ok(value) if value.is_nan() => Err(format!(
                    "invalid 'not-a-number' argument: {}\nTry '{} --help' for more information.",
                    s.quote(),
                    uucore::execution_phrase(),
                )),
                Ok(value) => Ok(Number::F64(value)),
                Err(_) => Err(format!(
                    "invalid floating point argument: {}\nTry '{} --help' for more information.",
                    s.quote(),
                    uucore::execution_phrase(),
                )),
            },
        }
    }
}

/// A range of integers.
///
/// The elements are (first, increment, last).
type RangeInt = (BigInt, BigInt, BigInt);

/// A range of f64.
///
/// The elements are (first, increment, last).
type RangeF64 = (f64, f64, f64);

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let numbers = matches.values_of(ARG_NUMBERS).unwrap().collect::<Vec<_>>();

    let options = SeqOptions {
        separator: matches.value_of(OPT_SEPARATOR).unwrap_or("\n").to_string(),
        terminator: matches.value_of(OPT_TERMINATOR).unwrap_or("\n").to_string(),
        widths: matches.is_present(OPT_WIDTHS),
    };

    let mut largest_dec = 0;
    let first = if numbers.len() > 1 {
        let slice = numbers[0];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = len - dec;
        crash_if_err!(1, slice.parse())
    } else {
        Number::BigInt(BigInt::one())
    };
    let increment = if numbers.len() > 2 {
        let slice = numbers[1];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = cmp::max(largest_dec, len - dec);
        crash_if_err!(1, slice.parse())
    } else {
        Number::BigInt(BigInt::one())
    };
    if increment.is_zero() {
        show_error!(
            "invalid Zero increment value: '{}'\nTry '{} --help' for more information.",
            numbers[1],
            uucore::execution_phrase()
        );
        return 1;
    }
    let last: Number = {
        let slice = numbers[numbers.len() - 1];
        crash_if_err!(1, slice.parse())
    };
    if largest_dec > 0 {
        largest_dec -= 1;
    }

    let padding = first
        .num_digits()
        .max(increment.num_digits())
        .max(last.num_digits());
    let result = match (first, last, increment) {
        (Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
            (BigInt::zero(), increment, last),
            options.separator,
            options.terminator,
            options.widths,
            padding,
            true,
        ),
        (Number::BigInt(first), Number::BigInt(last), Number::BigInt(increment)) => {
            print_seq_integers(
                (first, increment, last),
                options.separator,
                options.terminator,
                options.widths,
                padding,
                false,
            )
        }
        (first, last, increment) => print_seq(
            (first.into_f64(), increment.into_f64(), last.into_f64()),
            largest_dec,
            options.separator,
            options.terminator,
            options.widths,
            padding,
        ),
    };
    match result {
        Ok(_) => 0,
        Err(err) if err.kind() == ErrorKind::BrokenPipe => 0,
        Err(_) => 1,
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .setting(AppSettings::AllowLeadingHyphen)
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(OPT_SEPARATOR)
                .short("s")
                .long("separator")
                .help("Separator character (defaults to \\n)")
                .takes_value(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name(OPT_TERMINATOR)
                .short("t")
                .long("terminator")
                .help("Terminator character (defaults to \\n)")
                .takes_value(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name(OPT_WIDTHS)
                .short("w")
                .long("widths")
                .help("Equalize widths of all numbers by padding with zeros"),
        )
        .arg(
            Arg::with_name(ARG_NUMBERS)
                .multiple(true)
                .takes_value(true)
                .allow_hyphen_values(true)
                .max_values(3)
                .required(true),
        )
}

fn done_printing<T: Num + PartialOrd>(next: &T, increment: &T, last: &T) -> bool {
    if increment >= &T::zero() {
        next > last
    } else {
        next < last
    }
}

/// Floating point based code path
fn print_seq(
    range: RangeF64,
    largest_dec: usize,
    separator: String,
    terminator: String,
    pad: bool,
    padding: usize,
) -> std::io::Result<()> {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let (first, increment, last) = range;
    let mut i = 0isize;
    let mut value = first + i as f64 * increment;
    while !done_printing(&value, &increment, &last) {
        let istr = format!("{:.*}", largest_dec, value);
        let ilen = istr.len();
        let before_dec = istr.find('.').unwrap_or(ilen);
        if pad && before_dec < padding {
            for _ in 0..(padding - before_dec) {
                write!(stdout, "0")?;
            }
        }
        write!(stdout, "{}", istr)?;
        i += 1;
        value = first + i as f64 * increment;
        if !done_printing(&value, &increment, &last) {
            write!(stdout, "{}", separator)?;
        }
    }
    if (first >= last && increment < 0f64) || (first <= last && increment > 0f64) {
        write!(stdout, "{}", terminator)?;
    }
    stdout.flush()?;
    Ok(())
}

/// Print an integer sequence.
///
/// This function prints a sequence of integers defined by `range`,
/// which defines the first integer, last integer, and increment of the
/// range. The `separator` is inserted between each integer and
/// `terminator` is inserted at the end.
///
/// The `pad` parameter indicates whether to pad numbers to the width
/// given in `padding`.
///
/// If `is_first_minus_zero` is `true`, then the `first` parameter is
/// printed as if it were negative zero, even though no such number
/// exists as an integer (negative zero only exists for floating point
/// numbers). Only set this to `true` if `first` is actually zero.
fn print_seq_integers(
    range: RangeInt,
    separator: String,
    terminator: String,
    pad: bool,
    padding: usize,
    is_first_minus_zero: bool,
) -> std::io::Result<()> {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let (first, increment, last) = range;
    let mut value = first;
    let mut is_first_iteration = true;
    while !done_printing(&value, &increment, &last) {
        if !is_first_iteration {
            write!(stdout, "{}", separator)?;
        }
        let mut width = padding;
        if is_first_iteration && is_first_minus_zero {
            write!(stdout, "-")?;
            width -= 1;
        }
        is_first_iteration = false;
        if pad {
            write!(stdout, "{number:>0width$}", number = value, width = width)?;
        } else {
            write!(stdout, "{}", value)?;
        }
        value += &increment;
    }

    if !is_first_iteration {
        write!(stdout, "{}", terminator)?;
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use crate::Number;
    use num_bigint::{BigInt, Sign};

    #[test]
    fn test_number_num_digits() {
        assert_eq!(
            Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
            3
        );
        assert_eq!(
            Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
            4
        );
        assert_eq!(Number::F64(123.45).num_digits(), 3);
        assert_eq!(Number::MinusZero.num_digits(), 2);
    }
}
<commit_msg>seq: add is_first_iteration to avoid comparisons<commit_after>// TODO: Make -w flag work with decimals
// TODO: Support -f flag

// spell-checker:ignore (ToDO) istr chiter argptr ilen

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, AppSettings, Arg};
use num_bigint::BigInt;
use num_traits::One;
use num_traits::Zero;
use num_traits::{Num, ToPrimitive};
use std::cmp;
use std::io::{stdout, ErrorKind, Write};
use std::str::FromStr;
use uucore::display::Quotable;

static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
static OPT_SEPARATOR: &str = "separator";
static OPT_TERMINATOR: &str = "terminator";
static OPT_WIDTHS: &str = "widths";

static ARG_NUMBERS: &str = "numbers";

fn usage() -> String {
    format!(
        "{0} [OPTION]... LAST
    {0} [OPTION]... FIRST LAST
    {0} [OPTION]... FIRST INCREMENT LAST",
        uucore::execution_phrase()
    )
}
#[derive(Clone)]
struct SeqOptions {
    separator: String,
    terminator: String,
    widths: bool,
}

enum Number {
    /// Negative zero, as if it were an integer.
    MinusZero,
    BigInt(BigInt),
    F64(f64),
}

impl Number {
    fn is_zero(&self) -> bool {
        match self {
            Number::MinusZero => true,
            Number::BigInt(n) => n.is_zero(),
            Number::F64(n) => n.is_zero(),
        }
    }

    fn into_f64(self) -> f64 {
        match self {
            Number::MinusZero => -0.,
            // BigInt::to_f64() can not return None.
            Number::BigInt(n) => n.to_f64().unwrap(),
            Number::F64(n) => n,
        }
    }

    /// Number of characters needed to print the integral part of the number.
    ///
    /// The number of characters includes one character to represent the
    /// minus sign ("-") if this number is negative.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use num_bigint::{BigInt, Sign};
    ///
    /// assert_eq!(
    ///     Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
    ///     3
    /// );
    /// assert_eq!(
    ///     Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
    ///     4
    /// );
    /// assert_eq!(Number::F64(123.45).num_digits(), 3);
    /// assert_eq!(Number::MinusZero.num_digits(), 2);
    /// ```
    fn num_digits(&self) -> usize {
        match self {
            Number::MinusZero => 2,
            Number::BigInt(n) => n.to_string().len(),
            Number::F64(n) => {
                let s = n.to_string();
                s.find('.').unwrap_or_else(|| s.len())
            }
        }
    }
}

impl FromStr for Number {
    type Err = String;
    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
        s = s.trim_start();
        if s.starts_with('+') {
            s = &s[1..];
        }

        match s.parse::<BigInt>() {
            Ok(n) => {
                // If `s` is '-0', then `parse()` returns
                // `BigInt::zero()`, but we need to return
                // `Number::MinusZero` instead.
                if n == BigInt::zero() && s.starts_with('-') {
                    Ok(Number::MinusZero)
                } else {
                    Ok(Number::BigInt(n))
                }
            }
            Err(_) => match s.parse::<f64>() {
                Ok(value) if value.is_nan() => Err(format!(
                    "invalid 'not-a-number' argument: {}\nTry '{} --help' for more information.",
                    s.quote(),
                    uucore::execution_phrase(),
                )),
                Ok(value) => Ok(Number::F64(value)),
                Err(_) => Err(format!(
                    "invalid floating point argument: {}\nTry '{} --help' for more information.",
                    s.quote(),
                    uucore::execution_phrase(),
                )),
            },
        }
    }
}

/// A range of integers.
///
/// The elements are (first, increment, last).
type RangeInt = (BigInt, BigInt, BigInt);

/// A range of f64.
///
/// The elements are (first, increment, last).
type RangeF64 = (f64, f64, f64);

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let numbers = matches.values_of(ARG_NUMBERS).unwrap().collect::<Vec<_>>();

    let options = SeqOptions {
        separator: matches.value_of(OPT_SEPARATOR).unwrap_or("\n").to_string(),
        terminator: matches.value_of(OPT_TERMINATOR).unwrap_or("\n").to_string(),
        widths: matches.is_present(OPT_WIDTHS),
    };

    let mut largest_dec = 0;
    let first = if numbers.len() > 1 {
        let slice = numbers[0];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = len - dec;
        crash_if_err!(1, slice.parse())
    } else {
        Number::BigInt(BigInt::one())
    };
    let increment = if numbers.len() > 2 {
        let slice = numbers[1];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = cmp::max(largest_dec, len - dec);
        crash_if_err!(1, slice.parse())
    } else {
        Number::BigInt(BigInt::one())
    };
    if increment.is_zero() {
        show_error!(
            "invalid Zero increment value: '{}'\nTry '{} --help' for more information.",
            numbers[1],
            uucore::execution_phrase()
        );
        return 1;
    }
    let last: Number = {
        let slice = numbers[numbers.len() - 1];
        crash_if_err!(1, slice.parse())
    };
    if largest_dec > 0 {
        largest_dec -= 1;
    }

    let padding = first
        .num_digits()
        .max(increment.num_digits())
        .max(last.num_digits());
    let result = match (first, last, increment) {
        (Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
            (BigInt::zero(), increment, last),
            options.separator,
            options.terminator,
            options.widths,
            padding,
            true,
        ),
        (Number::BigInt(first), Number::BigInt(last), Number::BigInt(increment)) => {
            print_seq_integers(
                (first, increment, last),
                options.separator,
                options.terminator,
                options.widths,
                padding,
                false,
            )
        }
        (first, last, increment) => print_seq(
            (first.into_f64(), increment.into_f64(), last.into_f64()),
            largest_dec,
            options.separator,
            options.terminator,
            options.widths,
            padding,
        ),
    };
    match result {
        Ok(_) => 0,
        Err(err) if err.kind() == ErrorKind::BrokenPipe => 0,
        Err(_) => 1,
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .setting(AppSettings::AllowLeadingHyphen)
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(OPT_SEPARATOR)
                .short("s")
                .long("separator")
                .help("Separator character (defaults to \\n)")
                .takes_value(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name(OPT_TERMINATOR)
                .short("t")
                .long("terminator")
                .help("Terminator character (defaults to \\n)")
                .takes_value(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name(OPT_WIDTHS)
                .short("w")
                .long("widths")
                .help("Equalize widths of all numbers by padding with zeros"),
        )
        .arg(
            Arg::with_name(ARG_NUMBERS)
                .multiple(true)
                .takes_value(true)
                .allow_hyphen_values(true)
                .max_values(3)
                .required(true),
        )
}

fn done_printing<T: Num + PartialOrd>(next: &T, increment: &T, last: &T) -> bool {
    if increment >= &T::zero() {
        next > last
    } else {
        next < last
    }
}

/// Floating point based code path
fn print_seq(
    range: RangeF64,
    largest_dec: usize,
    separator: String,
    terminator: String,
    pad: bool,
    padding: usize,
) -> std::io::Result<()> {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let (first, increment, last) = range;
    let mut i = 0isize;
    let mut value = first + i as f64 * increment;
    let mut is_first_iteration = true;
    while !done_printing(&value, &increment, &last) {
        if !is_first_iteration {
            write!(stdout, "{}", separator)?;
        }
        is_first_iteration = false;
        let istr = format!("{:.*}", largest_dec, value);
        let ilen = istr.len();
        let before_dec = istr.find('.').unwrap_or(ilen);
        if pad && before_dec < padding {
            for _ in 0..(padding - before_dec) {
                write!(stdout, "0")?;
            }
        }
        write!(stdout, "{}", istr)?;
        i += 1;
        value = first + i as f64 * increment;
    }
    if !is_first_iteration {
        write!(stdout, "{}", terminator)?;
    }
    stdout.flush()?;
    Ok(())
}

/// Print an integer sequence.
///
/// This function prints a sequence of integers defined by `range`,
/// which defines the first integer, last integer, and increment of the
/// range. The `separator` is inserted between each integer and
/// `terminator` is inserted at the end.
///
/// The `pad` parameter indicates whether to pad numbers to the width
/// given in `padding`.
///
/// If `is_first_minus_zero` is `true`, then the `first` parameter is
/// printed as if it were negative zero, even though no such number
/// exists as an integer (negative zero only exists for floating point
/// numbers). Only set this to `true` if `first` is actually zero.
fn print_seq_integers(
    range: RangeInt,
    separator: String,
    terminator: String,
    pad: bool,
    padding: usize,
    is_first_minus_zero: bool,
) -> std::io::Result<()> {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let (first, increment, last) = range;
    let mut value = first;
    let mut is_first_iteration = true;
    while !done_printing(&value, &increment, &last) {
        if !is_first_iteration {
            write!(stdout, "{}", separator)?;
        }
        let mut width = padding;
        if is_first_iteration && is_first_minus_zero {
            write!(stdout, "-")?;
            width -= 1;
        }
        is_first_iteration = false;
        if pad {
            write!(stdout, "{number:>0width$}", number = value, width = width)?;
        } else {
            write!(stdout, "{}", value)?;
        }
        value += &increment;
    }

    if !is_first_iteration {
        write!(stdout, "{}", terminator)?;
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use crate::Number;
    use num_bigint::{BigInt, Sign};

    #[test]
    fn test_number_num_digits() {
        assert_eq!(
            Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
            3
        );
        assert_eq!(
            Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
            4
        );
        assert_eq!(Number::F64(123.45).num_digits(), 3);
        assert_eq!(Number::MinusZero.num_digits(), 2);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! The protocol for vhost-user is based on the existing implementation of vhost for the Linux
//! Kernel. The protocol defines two sides of the communication, master and slave. Master is
//! the application that shares its virtqueues. Slave is the consumer of the virtqueues.
//!
//! The communication channel between the master and the slave includes two sub channels. One is
//! used to send requests from the master to the slave and optional replies from the slave to the
//! master. This sub channel is created on master startup by connecting to the slave service
//! endpoint. The other is used to send requests from the slave to the master and optional replies
//! from the master to the slave. This sub channel is created by the master issuing a
//! VHOST_USER_SET_SLAVE_REQ_FD request to the slave with an auxiliary file descriptor.
//!
//! Unix domain socket is used as the underlying communication channel because the master needs to
//! send file descriptors to the slave.
//!
//! Most messages that can be sent via the Unix domain socket implementing vhost-user have an
//! equivalent ioctl to the kernel implementation.

use libc;
use std::io::Error as IOError;

mod connection;
pub mod message;
pub use self::connection::Listener;
#[cfg(feature = "vhost-user-master")]
mod master;
#[cfg(feature = "vhost-user-master")]
pub use self::master::{Master, VhostUserMaster};
#[cfg(feature = "vhost-user-master")]
mod master_req_handler;
#[cfg(feature = "vhost-user-master")]
pub use self::master_req_handler::{MasterReqHandler, VhostUserMasterReqHandler};

#[cfg(feature = "vhost-user-slave")]
mod slave;
#[cfg(feature = "vhost-user-slave")]
pub use self::slave::SlaveListener;
#[cfg(feature = "vhost-user-slave")]
mod slave_req_handler;
#[cfg(feature = "vhost-user-slave")]
pub use self::slave_req_handler::{SlaveReqHandler, VhostUserSlaveReqHandler};
#[cfg(feature = "vhost-user-slave")]
mod slave_fs_cache;
pub use self::slave_fs_cache::SlaveFsCacheReq;

pub mod sock_ctrl_msg;

/// Errors for vhost-user operations
#[derive(Debug)]
pub enum Error {
    /// Invalid parameters.
    InvalidParam,
    /// Unsupported operations due to that the protocol feature hasn't been negotiated.
    InvalidOperation,
    /// Invalid message format, flag or content.
    InvalidMessage,
    /// Only part of a message have been sent or received successfully
    PartialMessage,
    /// Message is too large
    OversizedMsg,
    /// Fd array in question is too big or too small
    IncorrectFds,
    /// Can't connect to peer.
    SocketConnect(std::io::Error),
    /// Generic socket errors.
    SocketError(std::io::Error),
    /// The socket is broken or has been closed.
    SocketBroken(std::io::Error),
    /// Should retry the socket operation again.
    SocketRetry(std::io::Error),
    /// Failure from the slave side.
    SlaveInternalError,
    /// Failure from the master side.
    MasterInternalError,
    /// Virtio/protocol features mismatch.
    FeatureMismatch,
    /// Error from request handler
    ReqHandlerError(IOError),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Error::InvalidParam => write!(f, "invalid parameters"),
            Error::InvalidOperation => write!(f, "invalid operation"),
            Error::InvalidMessage => write!(f, "invalid message"),
            Error::PartialMessage => write!(f, "partial message"),
            Error::OversizedMsg => write!(f, "oversized message"),
            Error::IncorrectFds => write!(f, "wrong number of attached fds"),
            Error::SocketError(e) => write!(f, "socket error: {}", e),
            Error::SocketConnect(e) => write!(f, "can't connect to peer: {}", e),
            Error::SocketBroken(e) => write!(f, "socket is broken: {}", e),
            Error::SocketRetry(e) => write!(f, "temporary socket error: {}", e),
            Error::SlaveInternalError => write!(f, "slave internal error"),
            Error::MasterInternalError => write!(f, "Master internal error"),
            Error::FeatureMismatch => write!(f, "virtio/protocol features mismatch"),
            Error::ReqHandlerError(e) => write!(f, "handler failed to handle request: {}", e),
        }
    }
}

impl Error {
    /// Determine whether to rebuild the underline communication channel.
    pub fn should_reconnect(&self) -> bool {
        match *self {
            // Should reconnect because it may be caused by temporary network errors.
            Error::PartialMessage => true,
            // Should reconnect because the underline socket is broken.
            Error::SocketBroken(_) => true,
            // Slave internal error, hope it recovers on reconnect.
            Error::SlaveInternalError => true,
            // Master internal error, hope it recovers on reconnect.
            Error::MasterInternalError => true,
            // Should just retry the IO operation instead of rebuilding the underline connection.
            Error::SocketRetry(_) => false,
            Error::InvalidParam | Error::InvalidOperation => false,
            Error::InvalidMessage | Error::IncorrectFds | Error::OversizedMsg => false,
            Error::SocketError(_) | Error::SocketConnect(_) => false,
            Error::FeatureMismatch => false,
            Error::ReqHandlerError(_) => false,
        }
    }
}

impl std::convert::From<vmm_sys_util::errno::Error> for Error {
    /// Convert raw socket errors into meaningful vhost-user errors.
    ///
    /// The vmm_sys_util::errno::Error is a simple wrapper over the raw errno, which doesn't means
    /// much to the vhost-user connection manager. So convert it into meaningful errors to simplify
    /// the connection manager logic.
    ///
    /// # Return:
    /// * - Error::SocketRetry: temporary error caused by signals or short of resources.
    /// * - Error::SocketBroken: the underline socket is broken.
    /// * - Error::SocketError: other socket related errors.
    #[allow(unreachable_patterns)] // EWOULDBLOCK equals to EGAIN on linux
    fn from(err: vmm_sys_util::errno::Error) -> Self {
        match err.errno() {
            // The socket is marked nonblocking and the requested operation would block.
            libc::EAGAIN => Error::SocketRetry(IOError::from_raw_os_error(libc::EAGAIN)),
            // The socket is marked nonblocking and the requested operation would block.
            libc::EWOULDBLOCK => Error::SocketRetry(IOError::from_raw_os_error(libc::EWOULDBLOCK)),
            // A signal occurred before any data was transmitted
            libc::EINTR => Error::SocketRetry(IOError::from_raw_os_error(libc::EINTR)),
            // The  output  queue  for  a network interface was full.  This generally indicates
            // that the interface has stopped sending, but may be caused by transient congestion.
            libc::ENOBUFS => Error::SocketRetry(IOError::from_raw_os_error(libc::ENOBUFS)),
            // No memory available.
            libc::ENOMEM => Error::SocketRetry(IOError::from_raw_os_error(libc::ENOMEM)),
            // Connection reset by peer.
            libc::ECONNRESET => Error::SocketBroken(IOError::from_raw_os_error(libc::ECONNRESET)),
            // The local end has been shut down on a connection oriented socket. In this  case the
            // process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
            libc::EPIPE => Error::SocketBroken(IOError::from_raw_os_error(libc::EPIPE)),
            // Write permission is denied on the destination socket file, or search permission is
            // denied for one of the directories the path prefix.
            libc::EACCES => Error::SocketConnect(IOError::from_raw_os_error(libc::EACCES)),
            // Catch all other errors
            e => Error::SocketError(IOError::from_raw_os_error(e)),
        }
    }
}

/// Result of vhost-user operations
pub type Result<T> = std::result::Result<T, Error>;

/// Result of request handler.
pub type HandlerResult<T> = std::result::Result<T, IOError>;

#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod dummy_slave;

#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod tests {
    use super::dummy_slave::{DummySlaveReqHandler, VIRTIO_FEATURES};
    use super::message::*;
    use super::*;
    use crate::backend::VhostBackend;
    use std::sync::{Arc, Barrier, Mutex};
    use std::thread;

    fn create_slave<S: VhostUserSlaveReqHandler>(
        path: &str,
        backend: Arc<Mutex<S>>,
    ) -> (Master, SlaveReqHandler<S>) {
        let mut slave_listener = SlaveListener::new(path, true, backend).unwrap();
        let master = Master::connect(path, 1).unwrap();
        (master, slave_listener.accept().unwrap().unwrap())
    }

    #[test]
    fn create_dummy_slave() {
        let mut slave = DummySlaveReqHandler::new();

        slave.set_owner().unwrap();
        assert!(slave.set_owner().is_err());
    }

    #[test]
    fn test_set_owner() {
        let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
        let (mut master, mut slave) =
            create_slave("/tmp/vhost_user_lib_unit_test_owner", slave_be.clone());

        assert_eq!(slave_be.lock().unwrap().owned, false);
        master.set_owner().unwrap();
        slave.handle_request().unwrap();
        assert_eq!(slave_be.lock().unwrap().owned, true);
        master.set_owner().unwrap();
        assert!(slave.handle_request().is_err());
        assert_eq!(slave_be.lock().unwrap().owned, true);
    }

    #[test]
    fn test_set_features() {
        let mbar = Arc::new(Barrier::new(2));
        let sbar = mbar.clone();
        let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
        let (mut master, mut slave) =
            create_slave("/tmp/vhost_user_lib_unit_test_feature", slave_be.clone());

        thread::spawn(move || {
            slave.handle_request().unwrap();
            assert_eq!(slave_be.lock().unwrap().owned, true);

            slave.handle_request().unwrap();
            slave.handle_request().unwrap();
            assert_eq!(
                slave_be.lock().unwrap().acked_features,
                VIRTIO_FEATURES & !0x1
            );

            slave.handle_request().unwrap();
            slave.handle_request().unwrap();
            assert_eq!(
                slave_be.lock().unwrap().acked_protocol_features,
                VhostUserProtocolFeatures::all().bits()
            );

            sbar.wait();
        });

        master.set_owner().unwrap();

        // set virtio features
        let features = master.get_features().unwrap();
        assert_eq!(features, VIRTIO_FEATURES);
        master.set_features(VIRTIO_FEATURES & !0x1).unwrap();

        // set vhost protocol features
        let features = master.get_protocol_features().unwrap();
        assert_eq!(features.bits(), VhostUserProtocolFeatures::all().bits());
        master.set_protocol_features(features).unwrap();

        mbar.wait();
    }
}
<commit_msg>vhost-user: control SlaveFsCacheReq with feature<commit_after>// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! The protocol for vhost-user is based on the existing implementation of vhost for the Linux
//! Kernel. The protocol defines two sides of the communication, master and slave. Master is
//! the application that shares its virtqueues. Slave is the consumer of the virtqueues.
//!
//! The communication channel between the master and the slave includes two sub channels. One is
//! used to send requests from the master to the slave and optional replies from the slave to the
//! master. This sub channel is created on master startup by connecting to the slave service
//! endpoint. The other is used to send requests from the slave to the master and optional replies
//! from the master to the slave. This sub channel is created by the master issuing a
//! VHOST_USER_SET_SLAVE_REQ_FD request to the slave with an auxiliary file descriptor.
//!
//! Unix domain socket is used as the underlying communication channel because the master needs to
//! send file descriptors to the slave.
//!
//! Most messages that can be sent via the Unix domain socket implementing vhost-user have an
//! equivalent ioctl to the kernel implementation.

use libc;
use std::io::Error as IOError;

mod connection;
pub mod message;
pub use self::connection::Listener;
#[cfg(feature = "vhost-user-master")]
mod master;
#[cfg(feature = "vhost-user-master")]
pub use self::master::{Master, VhostUserMaster};
#[cfg(feature = "vhost-user-master")]
mod master_req_handler;
#[cfg(feature = "vhost-user-master")]
pub use self::master_req_handler::{MasterReqHandler, VhostUserMasterReqHandler};

#[cfg(feature = "vhost-user-slave")]
mod slave;
#[cfg(feature = "vhost-user-slave")]
pub use self::slave::SlaveListener;
#[cfg(feature = "vhost-user-slave")]
mod slave_req_handler;
#[cfg(feature = "vhost-user-slave")]
pub use self::slave_req_handler::{SlaveReqHandler, VhostUserSlaveReqHandler};
#[cfg(feature = "vhost-user-slave")]
mod slave_fs_cache;
#[cfg(feature = "vhost-user-slave")]
pub use self::slave_fs_cache::SlaveFsCacheReq;

pub mod sock_ctrl_msg;

/// Errors for vhost-user operations
#[derive(Debug)]
pub enum Error {
    /// Invalid parameters.
    InvalidParam,
    /// Unsupported operations due to that the protocol feature hasn't been negotiated.
    InvalidOperation,
    /// Invalid message format, flag or content.
    InvalidMessage,
    /// Only part of a message have been sent or received successfully
    PartialMessage,
    /// Message is too large
    OversizedMsg,
    /// Fd array in question is too big or too small
    IncorrectFds,
    /// Can't connect to peer.
    SocketConnect(std::io::Error),
    /// Generic socket errors.
    SocketError(std::io::Error),
    /// The socket is broken or has been closed.
    SocketBroken(std::io::Error),
    /// Should retry the socket operation again.
    SocketRetry(std::io::Error),
    /// Failure from the slave side.
    SlaveInternalError,
    /// Failure from the master side.
    MasterInternalError,
    /// Virtio/protocol features mismatch.
    FeatureMismatch,
    /// Error from request handler
    ReqHandlerError(IOError),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Error::InvalidParam => write!(f, "invalid parameters"),
            Error::InvalidOperation => write!(f, "invalid operation"),
            Error::InvalidMessage => write!(f, "invalid message"),
            Error::PartialMessage => write!(f, "partial message"),
            Error::OversizedMsg => write!(f, "oversized message"),
            Error::IncorrectFds => write!(f, "wrong number of attached fds"),
            Error::SocketError(e) => write!(f, "socket error: {}", e),
            Error::SocketConnect(e) => write!(f, "can't connect to peer: {}", e),
            Error::SocketBroken(e) => write!(f, "socket is broken: {}", e),
            Error::SocketRetry(e) => write!(f, "temporary socket error: {}", e),
            Error::SlaveInternalError => write!(f, "slave internal error"),
            Error::MasterInternalError => write!(f, "Master internal error"),
            Error::FeatureMismatch => write!(f, "virtio/protocol features mismatch"),
            Error::ReqHandlerError(e) => write!(f, "handler failed to handle request: {}", e),
        }
    }
}

impl Error {
    /// Determine whether to rebuild the underline communication channel.
    pub fn should_reconnect(&self) -> bool {
        match *self {
            // Should reconnect because it may be caused by temporary network errors.
            Error::PartialMessage => true,
            // Should reconnect because the underline socket is broken.
            Error::SocketBroken(_) => true,
            // Slave internal error, hope it recovers on reconnect.
            Error::SlaveInternalError => true,
            // Master internal error, hope it recovers on reconnect.
            Error::MasterInternalError => true,
            // Should just retry the IO operation instead of rebuilding the underline connection.
            Error::SocketRetry(_) => false,
            Error::InvalidParam | Error::InvalidOperation => false,
            Error::InvalidMessage | Error::IncorrectFds | Error::OversizedMsg => false,
            Error::SocketError(_) | Error::SocketConnect(_) => false,
            Error::FeatureMismatch => false,
            Error::ReqHandlerError(_) => false,
        }
    }
}

impl std::convert::From<vmm_sys_util::errno::Error> for Error {
    /// Convert raw socket errors into meaningful vhost-user errors.
    ///
    /// The vmm_sys_util::errno::Error is a simple wrapper over the raw errno, which doesn't means
    /// much to the vhost-user connection manager. So convert it into meaningful errors to simplify
    /// the connection manager logic.
    ///
    /// # Return:
    /// * - Error::SocketRetry: temporary error caused by signals or short of resources.
    /// * - Error::SocketBroken: the underline socket is broken.
    /// * - Error::SocketError: other socket related errors.
    #[allow(unreachable_patterns)] // EWOULDBLOCK equals to EGAIN on linux
    fn from(err: vmm_sys_util::errno::Error) -> Self {
        match err.errno() {
            // The socket is marked nonblocking and the requested operation would block.
            libc::EAGAIN => Error::SocketRetry(IOError::from_raw_os_error(libc::EAGAIN)),
            // The socket is marked nonblocking and the requested operation would block.
            libc::EWOULDBLOCK => Error::SocketRetry(IOError::from_raw_os_error(libc::EWOULDBLOCK)),
            // A signal occurred before any data was transmitted
            libc::EINTR => Error::SocketRetry(IOError::from_raw_os_error(libc::EINTR)),
            // The  output  queue  for  a network interface was full.  This generally indicates
            // that the interface has stopped sending, but may be caused by transient congestion.
            libc::ENOBUFS => Error::SocketRetry(IOError::from_raw_os_error(libc::ENOBUFS)),
            // No memory available.
            libc::ENOMEM => Error::SocketRetry(IOError::from_raw_os_error(libc::ENOMEM)),
            // Connection reset by peer.
            libc::ECONNRESET => Error::SocketBroken(IOError::from_raw_os_error(libc::ECONNRESET)),
            // The local end has been shut down on a connection oriented socket. In this  case the
            // process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
            libc::EPIPE => Error::SocketBroken(IOError::from_raw_os_error(libc::EPIPE)),
            // Write permission is denied on the destination socket file, or search permission is
            // denied for one of the directories the path prefix.
            libc::EACCES => Error::SocketConnect(IOError::from_raw_os_error(libc::EACCES)),
            // Catch all other errors
            e => Error::SocketError(IOError::from_raw_os_error(e)),
        }
    }
}

/// Result of vhost-user operations
pub type Result<T> = std::result::Result<T, Error>;

/// Result of request handler.
pub type HandlerResult<T> = std::result::Result<T, IOError>;

#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod dummy_slave;

#[cfg(all(test, feature = "vhost-user-master", feature = "vhost-user-slave"))]
mod tests {
    use super::dummy_slave::{DummySlaveReqHandler, VIRTIO_FEATURES};
    use super::message::*;
    use super::*;
    use crate::backend::VhostBackend;
    use std::sync::{Arc, Barrier, Mutex};
    use std::thread;

    fn create_slave<S: VhostUserSlaveReqHandler>(
        path: &str,
        backend: Arc<Mutex<S>>,
    ) -> (Master, SlaveReqHandler<S>) {
        let mut slave_listener = SlaveListener::new(path, true, backend).unwrap();
        let master = Master::connect(path, 1).unwrap();
        (master, slave_listener.accept().unwrap().unwrap())
    }

    #[test]
    fn create_dummy_slave() {
        let mut slave = DummySlaveReqHandler::new();

        slave.set_owner().unwrap();
        assert!(slave.set_owner().is_err());
    }

    #[test]
    fn test_set_owner() {
        let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
        let (mut master, mut slave) =
            create_slave("/tmp/vhost_user_lib_unit_test_owner", slave_be.clone());

        assert_eq!(slave_be.lock().unwrap().owned, false);
        master.set_owner().unwrap();
        slave.handle_request().unwrap();
        assert_eq!(slave_be.lock().unwrap().owned, true);
        master.set_owner().unwrap();
        assert!(slave.handle_request().is_err());
        assert_eq!(slave_be.lock().unwrap().owned, true);
    }

    #[test]
    fn test_set_features() {
        let mbar = Arc::new(Barrier::new(2));
        let sbar = mbar.clone();
        let slave_be = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
        let (mut master, mut slave) =
            create_slave("/tmp/vhost_user_lib_unit_test_feature", slave_be.clone());

        thread::spawn(move || {
            slave.handle_request().unwrap();
            assert_eq!(slave_be.lock().unwrap().owned, true);

            slave.handle_request().unwrap();
            slave.handle_request().unwrap();
            assert_eq!(
                slave_be.lock().unwrap().acked_features,
                VIRTIO_FEATURES & !0x1
            );

            slave.handle_request().unwrap();
            slave.handle_request().unwrap();
            assert_eq!(
                slave_be.lock().unwrap().acked_protocol_features,
                VhostUserProtocolFeatures::all().bits()
            );

            sbar.wait();
        });

        master.set_owner().unwrap();

        // set virtio features
        let features = master.get_features().unwrap();
        assert_eq!(features, VIRTIO_FEATURES);
        master.set_features(VIRTIO_FEATURES & !0x1).unwrap();

        // set vhost protocol features
        let features = master.get_protocol_features().unwrap();
        assert_eq!(features.bits(), VhostUserProtocolFeatures::all().bits());
        master.set_protocol_features(features).unwrap();

        mbar.wait();
    }
}
<|endoftext|>


<commit_before>//option1.rs
//Make me compile! Execute `rustlings hint option1` for hints

//I AM NOT DONE

//you can modify anything EXCEPT for this function's sig
fn print_number(maybe_number: Option<u16>) {
    println!("printing: {}", maybe_number.unwrap());
}

fn main() {
    print_number(13);
    print_number(99);

    let mut numbers: [Option<u16>; 5];
    for iter in 0..5 {
        let number_to_add: u16 = {
            ((iter * 5) + 2) / (4 * 16);
        };

        numbers[iter] = number_to_add;
    }
}
<commit_msg>Update option1.rs<commit_after>//option1.rs
//Make me compile! Execute `rustlings hint option1` for hints

//I AM NOT DONE

//you can modify anything EXCEPT for this function's sig
fn print_number(maybe_number: Option<u16>) {
    println!("printing: {}", maybe_number.unwrap());
}

fn main() {
    print_number(13);
    print_number(99);

    let mut numbers: [Option<u16>; 5];
    for iter in 0..5 {
        let number_to_add: u16 = {
            ((iter * 5) + 2) / (4 * 16)
        };

        numbers[iter] = number_to_add;
    }
}
<|endoftext|>


<commit_before>use uni;
use xen;

use xen::memory::MapFlags;

use xen::defs::{Ulong, StartInfo, SharedInfo, ConsoleInterface};

#[macro_use]
mod page;
mod mapper;

pub mod traps;
pub mod defs;

extern {
    // Start info is not present on all architecture, this is why this
    // was made a global variable only for x86_*
    pub static start_info: *const StartInfo;
}

pub fn init() {
    unsafe {
        let console_vaddr: self::page::Vaddr;

        map_shared_info();

        console_vaddr = page::mfn_to_vaddr((*start_info).domu_console.mfn);

        uni::console::init(console_vaddr as *mut ConsoleInterface,
                           (*start_info).domu_console.evtchn);

        self::traps::init();
    }
}

pub unsafe fn init_memory() -> (usize, usize) {
    let pt_base: page::Vaddr = (*start_info).pt_base;
    let nr_pt_frames: usize = (*start_info).nr_pt_frames;
    let nr_pages: usize = (*start_info).nr_pages;

    let mut mapper = mapper::IdentityMapper::new(pt_base, nr_pt_frames,
                                                 nr_pages);

    println!("start info: 0x{:x}", start_info as usize);
    println!("number of pages: {}", (*start_info).nr_pages);
    println!("pt_base: 0x{:x}", (*start_info).pt_base);
    println!("nr_pt_frames: {}", (*start_info).nr_pt_frames);

    println!("Allocating heap 0x{:x}-0x{:x} ({} kB)", mapper.area_start,
             mapper.area_end,
             (mapper.area_end - mapper.area_start) / 1024);

    mapper.map();

    (mapper.area_start, mapper.area_end - mapper.area_start)
}

unsafe fn map_shared_info() {
    let shared_info_pte = pte!((*start_info).shared_info);
    let shared_info_ptr: *const SharedInfo = &xen::shared_info;

    // Map shared info
    xen::memory::update_va_mapping(shared_info_ptr as Ulong, shared_info_pte,
                                   MapFlags::InvlpgLocal);
}
<commit_msg>libboot: Add an assert to verify shared_info mapping<commit_after>use uni;
use xen;

use xen::memory::MapFlags;

use xen::defs::{Ulong, StartInfo, SharedInfo, ConsoleInterface};

#[macro_use]
mod page;
mod mapper;

pub mod traps;
pub mod defs;

extern {
    // Start info is not present on all architecture, this is why this
    // was made a global variable only for x86_*
    pub static start_info: *const StartInfo;
}

pub fn init() {
    unsafe {
        let console_vaddr: self::page::Vaddr;

        map_shared_info();

        console_vaddr = page::mfn_to_vaddr((*start_info).domu_console.mfn);

        uni::console::init(console_vaddr as *mut ConsoleInterface,
                           (*start_info).domu_console.evtchn);

        self::traps::init();
    }
}

pub unsafe fn init_memory() -> (usize, usize) {
    let pt_base: page::Vaddr = (*start_info).pt_base;
    let nr_pt_frames: usize = (*start_info).nr_pt_frames;
    let nr_pages: usize = (*start_info).nr_pages;

    let mut mapper = mapper::IdentityMapper::new(pt_base, nr_pt_frames,
                                                 nr_pages);

    println!("start info: 0x{:x}", start_info as usize);
    println!("number of pages: {}", (*start_info).nr_pages);
    println!("pt_base: 0x{:x}", (*start_info).pt_base);
    println!("nr_pt_frames: {}", (*start_info).nr_pt_frames);

    println!("Allocating heap 0x{:x}-0x{:x} ({} kB)", mapper.area_start,
             mapper.area_end,
             (mapper.area_end - mapper.area_start) / 1024);

    mapper.map();

    (mapper.area_start, mapper.area_end - mapper.area_start)
}

unsafe fn map_shared_info() {
    let shared_info_pte = pte!((*start_info).shared_info);
    let shared_info_ptr: *const SharedInfo = &xen::shared_info;

    // Map shared info
    assert_eq!(xen::memory::update_va_mapping(shared_info_ptr as Ulong,
                                              shared_info_pte,
                                              MapFlags::InvlpgLocal), 0)
}
<|endoftext|>


<commit_before>#![crate_name = "jit_macros"]
#![comment = "Macros for LibJIT Bindings"]
#![crate_type = "dylib"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types)]
#![deny(unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, unused_must_use)]
#![feature(globs, plugin_registrar, quote)]
#![experimental]
//! This crate provides some macros for better LibJIT interop
//! For example, here's a quick example of automatic struct compilation to a LibJIT value:
//!
//! ```rust
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macros;
//! use jit::{C_DECL, Context, Function, Type, Types, get_type};
//!
//! #[jit_compile]
//! struct Pos {
//!     x: f64,
//!     y: f64,
//!     z: f64
//! }
//! fn main() {
//!     let cx = Context::new();
//!     cx.build(|| {
//!         // build the IR
//!         let sig = get_type(fn() -> Pos);
//!         let func = Function::new(cx, sig);
//!         let result = Pos {
//!             x: -10,
//!             y: 0,
//!             z: 10
//!         }.compile();
//!         func.insn_return(&result);
//!         /// run the IR
//!         func.compile();
//!         let rfunc:fn() -> Pos = func.closure0();
//!         assert_eq(rfunc().x, -10)
//!     });
//! }
//! ```
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::{Gc, GC};
use syntax::ast::*;
use syntax::codemap::*;
use syntax::ext::base::*;
use syntax::ext::build::*;
use syntax::ext::quote::rt::*;
use syntax::parse::token::*;
use syntax::owned_slice::OwnedSlice;

fn gen_compile(cx:&mut ExtCtxt, pos:Span, _:Gc<MetaItem>, item:Gc<Item>, cb:|Gc<Item>|) {
    let fields:Vec<(Option<String>, P<Expr>)> = match item.node {
        ItemStruct(def, _) if def.is_virtual => {
            cx.span_err(pos, "Virtual structs cannot be JIT compiled");
            fail!("...")
        },
        ItemStruct(def, _) => {
            def.fields.iter().map(|field| {
                let name:Option<String> = match field.node.kind {
                    NamedField(id, _) => Some(id.to_source()),
                    UnnamedField(_) => None
                };
                let ty = field.node.ty;
                let ty_expr = quote_expr!(&*cx, &::jit::get_type::<$ty>());
                (name, ty_expr)
            }).collect()
        },
        _ => {
            cx.span_err(pos, "Compile can only be automatically implemented for structs");
            fail!("...")
        }
    };
    let jit_type_t = cx.ty_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"))), None);
    let create_struct = cx.expr_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"), cx.ident_of("create_struct"))));
    let jit_type_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), {
            let mut fields = cx.expr_vec(pos, fields.iter().map(|&(_, ex)| ex).collect());
            fields = cx.expr_method_call(pos, fields, cx.ident_of("as_mut_slice"), vec!());
            cx.expr_call(pos, create_struct, vec!(fields))
        }),
    ), Some(cx.expr_ident(pos, cx.ident_of("ty"))));
    let curr_item = cx.ty_ident(pos, item.ident);
    let jit_type = Method {
        ident: cx.ident_of("jit_type"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfStatic,
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                cx.arg(pos, cx.ident_of("_"), cx.ty_option(curr_item))
            ),
            jit_type_t
        ),
        body: jit_type_body,
        span: pos,
        id: item.id,
        vis: Inherited
    };
    let lifetime = cx.lifetime(pos, cx.ident_of("'a").name);
    let compile_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), cx.expr_call(pos, quote_expr!(&*cx, ::jit::get_type::<$curr_item>), vec!())),
        cx.stmt_let(pos, false, cx.ident_of("val"), cx.expr_call(pos, quote_expr!(&*cx, ::jit::Value::new), vec!(
            cx.expr_ident(pos, cx.ident_of("func")),
            cx.expr_addr_of(pos, cx.expr_ident(pos, cx.ident_of("ty")))
        )))
    ), Some(cx.expr_ident(pos, cx.ident_of("val"))));
    let jit_func_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Function")), vec!(lifetime.clone()), vec!()), None);
    let jit_val_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Value")), vec!(lifetime.clone()), vec!()), None);
    let compile = Method {
        ident: cx.ident_of("compile"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(
                lifetime.clone()
            ),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfRegion(None, MutImmutable),
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                Arg::new_self(pos, MutImmutable),
                cx.arg(pos, cx.ident_of("func"), cx.ty_rptr(pos, jit_func_t, None, MutImmutable))
            ),
            jit_val_t
        ),
        body: compile_body,
        span: pos,
        id: item.id,
        vis: Inherited
    };
    let methods = vec!(
        box(GC) jit_type,
        box(GC) compile
    );
    let node = ItemImpl(
        Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        Some(cx.trait_ref(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Compile"))))),
        cx.ty_path(cx.path_ident(pos, item.ident), None),
        methods
    );
    cb(cx.item(pos, cx.ident_of("Compile"), vec!(), node));
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("jit_compile"), ItemDecorator(gen_compile));
}<commit_msg>Update for latest Rust<commit_after>#![crate_name = "jit_macros"]
#![comment = "Macros for LibJIT Bindings"]
#![crate_type = "dylib"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types)]
#![deny(unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, unused_must_use)]
#![feature(globs, plugin_registrar, quote)]
#![experimental]
//! This crate provides some macros for better LibJIT interop
//! For example, here's a quick example of automatic struct compilation to a LibJIT value:
//!
//! ```rust
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macros;
//! use jit::{C_DECL, Context, Function, Type, Types, get_type};
//!
//! #[jit_compile]
//! struct Pos {
//!     x: f64,
//!     y: f64,
//!     z: f64
//! }
//! fn main() {
//!     let cx = Context::new();
//!     cx.build(|| {
//!         // build the IR
//!         let sig = get_type(fn() -> Pos);
//!         let func = Function::new(cx, sig);
//!         let result = Pos {
//!             x: -10,
//!             y: 0,
//!             z: 10
//!         }.compile();
//!         func.insn_return(&result);
//!         /// run the IR
//!         func.compile();
//!         let rfunc:fn() -> Pos = func.closure0();
//!         assert_eq(rfunc().x, -10)
//!     });
//! }
//! ```
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::{Gc, GC};
use syntax::ast::*;
use syntax::codemap::*;
use syntax::ext::base::*;
use syntax::ext::build::*;
use syntax::ext::quote::rt::*;
use syntax::parse::token::*;
use syntax::owned_slice::OwnedSlice;

fn gen_compile(cx:&mut ExtCtxt, pos:Span, _:Gc<MetaItem>, item:Gc<Item>, cb:|Gc<Item>|) {
    let fields:Vec<(Option<String>, P<Expr>)> = match item.node {
        ItemStruct(def, _) if def.is_virtual => {
            cx.span_err(pos, "Virtual structs cannot be JIT compiled");
            fail!("...")
        },
        ItemStruct(def, _) => {
            def.fields.iter().map(|field| {
                let name:Option<String> = match field.node.kind {
                    NamedField(id, _) => Some(id.to_source()),
                    UnnamedField(_) => None
                };
                let ty = field.node.ty;
                let ty_expr = quote_expr!(&*cx, &::jit::get_type::<$ty>());
                (name, ty_expr)
            }).collect()
        },
        _ => {
            cx.span_err(pos, "Compile can only be automatically implemented for structs");
            fail!("...")
        }
    };
    let jit_type_t = cx.ty_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"))), None);
    let create_struct = cx.expr_path(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Type"), cx.ident_of("create_struct"))));
    let jit_type_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), {
            let mut fields = cx.expr_vec(pos, fields.iter().map(|&(_, ex)| ex).collect());
            fields = cx.expr_method_call(pos, fields, cx.ident_of("as_mut_slice"), vec!());
            cx.expr_call(pos, create_struct, vec!(fields))
        }),
    ), Some(cx.expr_ident(pos, cx.ident_of("ty"))));
    let curr_item = cx.ty_ident(pos, item.ident);
    let jit_type = Method {
        ident: cx.ident_of("jit_type"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfStatic,
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                cx.arg(pos, cx.ident_of("_"), cx.ty_option(curr_item))
            ),
            jit_type_t
        ),
        body: jit_type_body,
        span: pos,
        id: item.id,
        vis: Inherited
    };
    let lifetime = cx.lifetime(pos, cx.ident_of("'a").name);
    let compile_body = cx.block(pos, vec!(
        cx.stmt_let(pos, false, cx.ident_of("ty"), cx.expr_call(pos, quote_expr!(&*cx, ::jit::get_type::<$curr_item>), vec!())),
        cx.stmt_let(pos, false, cx.ident_of("val"), cx.expr_call(pos, quote_expr!(&*cx, ::jit::Value::new), vec!(
            cx.expr_ident(pos, cx.ident_of("func")),
            cx.expr_addr_of(pos, cx.expr_ident(pos, cx.ident_of("ty")))
        )))
    ), Some(cx.expr_ident(pos, cx.ident_of("val"))));
    let jit_func_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Function")), vec!(lifetime.clone()), vec!()), None);
    let jit_val_t = cx.ty_path(cx.path_all(pos, true, vec!(cx.ident_of("jit"), cx.ident_of("Value")), vec!(lifetime.clone()), vec!()), None);
    let compile = Method {
        ident: cx.ident_of("compile"),
        attrs: vec!(
            cx.attribute(pos, cx.meta_word(pos, InternedString::new("inline")))
        ),
        generics: Generics {
            lifetimes: vec!(
                lifetime.clone()
            ),
            ty_params: OwnedSlice::empty()
        },
        explicit_self: Spanned {
            node: SelfRegion(None, MutImmutable, cx.ident_of("self")),
            span: pos
        },
        fn_style: NormalFn,
        decl: cx.fn_decl(
            vec!(
                Arg::new_self(pos, MutImmutable, cx.ident_of("func")),
                cx.arg(pos, cx.ident_of("func"), cx.ty_rptr(pos, jit_func_t, None, MutImmutable))
            ),
            jit_val_t
        ),
        body: compile_body,
        span: pos,
        id: item.id,
        vis: Inherited
    };
    let methods = vec!(
        box(GC) jit_type,
        box(GC) compile
    );
    let node = ItemImpl(
        Generics {
            lifetimes: vec!(),
            ty_params: OwnedSlice::empty()
        },
        Some(cx.trait_ref(cx.path_global(pos, vec!(cx.ident_of("jit"), cx.ident_of("Compile"))))),
        cx.ty_path(cx.path_ident(pos, item.ident), None),
        methods
    );
    cb(cx.item(pos, cx.ident_of("Compile"), vec!(), node));
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("jit_compile"), ItemDecorator(gen_compile));
}<|endoftext|>


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

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::{c_int, c_char};
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

pub fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        static POISONED: AtomicBool = AtomicBool::new(false);
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
                                                 "xsave\0", "xsaveopt\0", "xsavec\0",
                                                 "xsaves\0",
                                                 "avx512bw\0", "avx512cd\0",
                                                 "avx512dq\0", "avx512er\0",
                                                 "avx512f\0", "avx512ifma\0",
                                                 "avx512pf\0", "avx512vbmi\0",
                                                 "avx512vl\0", "avx512vpopcntdq\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };

    let mut features = Vec::new();
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            features.push(Symbol::intern(&feat[..feat.len() - 1]));
        }
    }
    features
}

pub fn print_version() {
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub fn print(req: PrintRequest, sess: &Session) {
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}

pub fn enable_llvm_debug() {
    unsafe { llvm::LLVMRustSetDebug(1); }
}
<commit_msg>Rollup merge of #46322 - gnzlbg:mmx, r=alexcrichton<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::{c_int, c_char};
use std::ffi::CString;

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

pub fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        static POISONED: AtomicBool = AtomicBool::new(false);
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
                                                 "xsave\0", "xsaveopt\0", "xsavec\0",
                                                 "xsaves\0",
                                                 "avx512bw\0", "avx512cd\0",
                                                 "avx512dq\0", "avx512er\0",
                                                 "avx512f\0", "avx512ifma\0",
                                                 "avx512pf\0", "avx512vbmi\0",
                                                 "avx512vl\0", "avx512vpopcntdq\0", "mmx\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_target_machine(sess);

    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };

    let mut features = Vec::new();
    for feat in whitelist {
        assert_eq!(feat.chars().last(), Some('\0'));
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } {
            features.push(Symbol::intern(&feat[..feat.len() - 1]));
        }
    }
    features
}

pub fn print_version() {
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub fn print(req: PrintRequest, sess: &Session) {
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}

pub fn enable_llvm_debug() {
    unsafe { llvm::LLVMRustSetDebug(1); }
}
<|endoftext|>


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

use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::str;

#[derive(Clone)]
pub struct ExternalHtml{
    /// Content that will be included inline in the <head> section of a
    /// rendered Markdown file or generated documentation
    pub in_header: String,
    /// Content that will be included inline between <body> and the content of
    /// a rendered Markdown file or generated documentation
    pub before_content: String,
    /// Content that will be included inline between the content and </body> of
    /// a rendered Markdown file or generated documentation
    pub after_content: String
}

impl ExternalHtml {
    pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
            -> Option<ExternalHtml> {
        load_external_files(in_header)
            .and_then(|ih|
                load_external_files(before_content)
                    .map(|bc| (ih, bc))
            )
            .and_then(|(ih, bc)|
                load_external_files(after_content)
                    .map(|ac| (ih, bc, ac))
            )
            .map(|(ih, bc, ac)|
                ExternalHtml {
                    in_header: ih,
                    before_content: bc,
                    after_content: ac,
                }
            )
    }
}

pub enum LoadStringError {
    ReadFail,
    BadUtf8,
}

pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
    let file_path = file_path.as_ref();
    let mut contents = vec![];
    let result = File::open(file_path)
                      .and_then(|mut f| f.read_to_end(&mut contents));
    if let Err(e) = result {
        let _ = writeln!(&mut io::stderr(),
                         "error reading `{}`: {}",
                         file_path.display(), e);
        return Err(LoadStringError::ReadFail);
    }
    match str::from_utf8(&contents) {
        Ok(s) => Ok(s.to_string()),
        Err(_) => {
            let _ = writeln!(&mut io::stderr(),
                             "error reading `{}`: not UTF-8",
                             file_path.display());
            Err(LoadStringError::BadUtf8)
        }
    }
}

pub fn load_external_files(names: &[String]) -> Option<String> {
    let mut out = String::new();
    for name in names {
        let s = match load_string(name) {
            Ok(s) => s,
            Err(_) => return None,
        };
        out.push_str(&s);
        out.push('\n');
    }
    Some(out)
}
<commit_msg>Remove unnecessary `pub` function classifier.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::str;

#[derive(Clone)]
pub struct ExternalHtml{
    /// Content that will be included inline in the <head> section of a
    /// rendered Markdown file or generated documentation
    pub in_header: String,
    /// Content that will be included inline between <body> and the content of
    /// a rendered Markdown file or generated documentation
    pub before_content: String,
    /// Content that will be included inline between the content and </body> of
    /// a rendered Markdown file or generated documentation
    pub after_content: String
}

impl ExternalHtml {
    pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
            -> Option<ExternalHtml> {
        load_external_files(in_header)
            .and_then(|ih|
                load_external_files(before_content)
                    .map(|bc| (ih, bc))
            )
            .and_then(|(ih, bc)|
                load_external_files(after_content)
                    .map(|ac| (ih, bc, ac))
            )
            .map(|(ih, bc, ac)|
                ExternalHtml {
                    in_header: ih,
                    before_content: bc,
                    after_content: ac,
                }
            )
    }
}

pub enum LoadStringError {
    ReadFail,
    BadUtf8,
}

pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
    let file_path = file_path.as_ref();
    let mut contents = vec![];
    let result = File::open(file_path)
                      .and_then(|mut f| f.read_to_end(&mut contents));
    if let Err(e) = result {
        let _ = writeln!(&mut io::stderr(),
                         "error reading `{}`: {}",
                         file_path.display(), e);
        return Err(LoadStringError::ReadFail);
    }
    match str::from_utf8(&contents) {
        Ok(s) => Ok(s.to_string()),
        Err(_) => {
            let _ = writeln!(&mut io::stderr(),
                             "error reading `{}`: not UTF-8",
                             file_path.display());
            Err(LoadStringError::BadUtf8)
        }
    }
}

fn load_external_files(names: &[String]) -> Option<String> {
    let mut out = String::new();
    for name in names {
        let s = match load_string(name) {
            Ok(s) => s,
            Err(_) => return None,
        };
        out.push_str(&s);
        out.push('\n');
    }
    Some(out)
}
<|endoftext|>


<commit_before>/// Memory buffers for the benefit of `std::rt::io::net` which has slow read/write.

use std::rt::io::{Reader, Writer};
use std::cast::transmute_mut;
use std::cmp::min;
use std::ptr;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

struct BufferedReader<'self, T> {
    wrapped: &'self mut T,
    buffer: [u8, ..READ_BUF_SIZE],
    // The current position in the buffer
    pos: uint,
    // The last valid position in the reader
    max: uint,
}

impl<'self, T: Reader> BufferedReader<'self, T> {
    pub fn new<'a>(reader: &'a mut T/*, buffer_size: uint*/) -> BufferedReader<'a, T> {
        BufferedReader {
            wrapped: reader,
            buffer: [0u8, ..READ_BUF_SIZE], //[0u8, ..buffer_size],
            pos: 0u,
            max: 0u,
        }
    }

    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.pos, self.max) {
            (0, 0) => self.max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.pos -= 1,
        }
        self.buffer[self.pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> bool {
        assert_eq!(self.pos, self.max);
        match self.wrapped.read(self.buffer) {
            None => {
                self.pos = 0;
                self.max = 0;
                false
            },
            Some(i) => {
                self.pos = 0;
                self.max = i;
                true
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> Option<u8> {
        if self.pos == self.max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        self.pos += 1;
        Some(self.buffer[self.pos - 1])
    }
}

impl<'self, T: Reader> Reader for ~BufferedReader<'self, T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        if self.pos == self.max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        let size = min(self.max - self.pos, buf.len());
        unsafe {
            do buf.as_mut_buf |p_dst, _len_dst| {
                do self.buffer.as_imm_buf |p_src, _len_src| {
                    // Note that copy_memory works on bytes; good, u8 is byte-sized
                    ptr::copy_memory(p_dst, ptr::offset(p_src, self.pos), size)
                }
            }
        }
        self.pos += size;
        Some(size)
    }

    /// Return whether the Reader has reached the end of the stream AND exhausted its buffer.
    fn eof(&mut self) -> bool {
        self.pos == self.max && self.wrapped.eof()
    }
}

struct BufferedWriter<'self, T> {
    wrapped: &'self mut T,
    buffer: [u8, ..WRITE_BUF_SIZE],
    buflen: uint,

    /// Some things being written may not like flush() being called yet (e.g. explicitly fail!())
    /// The BufferedReader may need to be flushed for good control, but let it provide for such
    /// cases by not calling the wrapped object's flush method in turn.
    call_wrapped_flush: bool,
}

impl<'self, T: Writer> BufferedWriter<'self, T> {
    pub fn new<'a>(writer: &'a mut T, call_wrapped_flush: bool/*, buffer_size: uint*/)
    -> BufferedWriter<'a, T> {
        BufferedWriter {
            wrapped: writer,
            buffer: [0u8, ..WRITE_BUF_SIZE], //[0u8, ..buffer_size],
            buflen: 0u,
            call_wrapped_flush: call_wrapped_flush,
        }
    }
}

#[unsafe_destructor]
impl<'self, T: Writer> Drop for BufferedWriter<'self, T> {
    fn drop(&self) {
        // Clearly wouldn't be a good idea to finish without flushing!

        // TODO: blocked on https://github.com/mozilla/rust/issues/4252
        // Also compare usage of response.flush() in server.rs
        //unsafe { transmute_mut(self) }.flush();
    }
}

impl<'self, T: Writer> Writer for BufferedWriter<'self, T> {
    fn write(&mut self, buf: &[u8]) {
        if buf.len() + self.buflen > self.buffer.len() {
            // This is the lazy approach which may involve two writes where it's really not
            // warranted. Maybe deal with that later.
            if self.buflen > 0 {
                self.wrapped.write(self.buffer.slice_to(self.buflen));
                self.buflen = 0;
            }
            self.wrapped.write(buf);
            self.buflen = 0;
        } else {
            // Safely copy buf onto the "end" of self.buffer
            unsafe {
                do buf.as_imm_buf |p_src, len_src| {
                    do self.buffer.as_mut_buf |p_dst, _len_dst| {
                        // Note that copy_memory works on bytes; good, u8 is byte-sized
                        ptr::copy_memory(ptr::mut_offset(p_dst, self.buflen), p_src, len_src)
                    }
                }
            }
            self.buflen += buf.len();
            if self.buflen == self.buffer.len() {
                self.wrapped.write(self.buffer);
                self.buflen = 0;
            }
        }
    }

    fn flush(&mut self) {
        if self.buflen > 0 {
            self.wrapped.write(self.buffer.slice_to(self.buflen));
            self.buflen = 0;
        }
        if self.call_wrapped_flush {
            self.wrapped.flush();
        }
    }
}
<commit_msg>Update ptr::offset calls (now takes an int instead of a uint).<commit_after>/// Memory buffers for the benefit of `std::rt::io::net` which has slow read/write.

use std::rt::io::{Reader, Writer};
use std::cast::transmute_mut;
use std::cmp::min;
use std::ptr;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

struct BufferedReader<'self, T> {
    wrapped: &'self mut T,
    buffer: [u8, ..READ_BUF_SIZE],
    // The current position in the buffer
    pos: uint,
    // The last valid position in the reader
    max: uint,
}

impl<'self, T: Reader> BufferedReader<'self, T> {
    pub fn new<'a>(reader: &'a mut T/*, buffer_size: uint*/) -> BufferedReader<'a, T> {
        BufferedReader {
            wrapped: reader,
            buffer: [0u8, ..READ_BUF_SIZE], //[0u8, ..buffer_size],
            pos: 0u,
            max: 0u,
        }
    }

    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.pos, self.max) {
            (0, 0) => self.max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.pos -= 1,
        }
        self.buffer[self.pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> bool {
        assert_eq!(self.pos, self.max);
        match self.wrapped.read(self.buffer) {
            None => {
                self.pos = 0;
                self.max = 0;
                false
            },
            Some(i) => {
                self.pos = 0;
                self.max = i;
                true
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> Option<u8> {
        if self.pos == self.max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        self.pos += 1;
        Some(self.buffer[self.pos - 1])
    }
}

impl<'self, T: Reader> Reader for ~BufferedReader<'self, T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        if self.pos == self.max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        let size = min(self.max - self.pos, buf.len());
        unsafe {
            do buf.as_mut_buf |p_dst, _len_dst| {
                do self.buffer.as_imm_buf |p_src, _len_src| {
                    // Note that copy_memory works on bytes; good, u8 is byte-sized
                    ptr::copy_memory(p_dst, ptr::offset(p_src, self.pos as int), size)
                }
            }
        }
        self.pos += size;
        Some(size)
    }

    /// Return whether the Reader has reached the end of the stream AND exhausted its buffer.
    fn eof(&mut self) -> bool {
        self.pos == self.max && self.wrapped.eof()
    }
}

struct BufferedWriter<'self, T> {
    wrapped: &'self mut T,
    buffer: [u8, ..WRITE_BUF_SIZE],
    buflen: uint,

    /// Some things being written may not like flush() being called yet (e.g. explicitly fail!())
    /// The BufferedReader may need to be flushed for good control, but let it provide for such
    /// cases by not calling the wrapped object's flush method in turn.
    call_wrapped_flush: bool,
}

impl<'self, T: Writer> BufferedWriter<'self, T> {
    pub fn new<'a>(writer: &'a mut T, call_wrapped_flush: bool/*, buffer_size: uint*/)
    -> BufferedWriter<'a, T> {
        BufferedWriter {
            wrapped: writer,
            buffer: [0u8, ..WRITE_BUF_SIZE], //[0u8, ..buffer_size],
            buflen: 0u,
            call_wrapped_flush: call_wrapped_flush,
        }
    }
}

#[unsafe_destructor]
impl<'self, T: Writer> Drop for BufferedWriter<'self, T> {
    fn drop(&self) {
        // Clearly wouldn't be a good idea to finish without flushing!

        // TODO: blocked on https://github.com/mozilla/rust/issues/4252
        // Also compare usage of response.flush() in server.rs
        //unsafe { transmute_mut(self) }.flush();
    }
}

impl<'self, T: Writer> Writer for BufferedWriter<'self, T> {
    fn write(&mut self, buf: &[u8]) {
        if buf.len() + self.buflen > self.buffer.len() {
            // This is the lazy approach which may involve two writes where it's really not
            // warranted. Maybe deal with that later.
            if self.buflen > 0 {
                self.wrapped.write(self.buffer.slice_to(self.buflen));
                self.buflen = 0;
            }
            self.wrapped.write(buf);
            self.buflen = 0;
        } else {
            // Safely copy buf onto the "end" of self.buffer
            unsafe {
                do buf.as_imm_buf |p_src, len_src| {
                    do self.buffer.as_mut_buf |p_dst, _len_dst| {
                        // Note that copy_memory works on bytes; good, u8 is byte-sized
                        ptr::copy_memory(ptr::mut_offset(p_dst, self.buflen as int), p_src, len_src)
                    }
                }
            }
            self.buflen += buf.len();
            if self.buflen == self.buffer.len() {
                self.wrapped.write(self.buffer);
                self.buflen = 0;
            }
        }
    }

    fn flush(&mut self) {
        if self.buflen > 0 {
            self.wrapped.write(self.buffer.slice_to(self.buflen));
            self.buflen = 0;
        }
        if self.call_wrapped_flush {
            self.wrapped.flush();
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Add;

pub struct Throttler<T, S = T>
    // where T: Add<S> + PartialOrd, <T as Add<S>>::Output = T
{
    next_send: T,
    interval: S,
}

// impl<T, S> Throttler<T, S>
    // where T: Add<S> + PartialOrd, <T as Add<S>>::Output = T
impl Throttler<f64, f64>
{
    pub fn new(now: f64, interval: f64) -> Throttler<f64, f64> {
        Throttler {
            next_send: now + interval,
            interval: interval,
        }
    }

    pub fn update(&mut self, now: f64) -> bool {
        if now > self.next_send {
            self.next_send = self.next_send + self.interval;
            true
        } else {
            false
        }
    }
}
<commit_msg>Do a temporary fix for throttler<commit_after>// use std::ops::Add;

pub struct Throttler<T, S = T>
    // where T: Add<S> + PartialOrd, <T as Add<S>>::Output = T
{
    next_send: T,
    interval: S,
}

// impl<T, S> Throttler<T, S>
    // where T: Add<S> + PartialOrd, <T as Add<S>>::Output = T
impl Throttler<f64, f64>
{
    pub fn new(now: f64, interval: f64) -> Throttler<f64, f64> {
        Throttler {
            next_send: now + interval,
            interval: interval,
        }
    }

    pub fn update(&mut self, now: f64) -> bool {
        if now > self.next_send {
            self.next_send = self.next_send + self.interval;
            true
        } else {
            false
        }
    }
}
<|endoftext|>