<commit_before>use std::collections::HashMap;

#[derive(Debug, Default, Deserialize)]
pub struct Error {
    pub detail: String,
}

#[derive(Debug, Deserialize)]
pub struct CrateLinks {
    pub owners: Option<String>,
    pub reverse_dependencies: String,
    pub version_downloads: String,
    pub versions: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct Crate {
    pub created_at: String,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub name: String,
    pub repository: Option<String>,
    pub updated_at: String,
    pub versions: Option<Vec<u64>>,
}

#[derive(Debug, Deserialize)]
pub struct Keyword {
    pub crates_cnt: u64,
    pub created_at: String,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize)]
pub struct Version {
    #[serde(rename="crate")]
    pub krate: String,
    pub created_at: String,
    pub dl_path: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String,
    pub updated_at: String,
    pub yanked: bool,
}

#[derive(Debug, Deserialize)]
pub struct Reply {
    #[serde(default)]
    pub errors: Error,
    #[serde(rename="crate")]
    pub krate: Crate,
    pub keywords: Vec<Keyword>,
    pub versions: Vec<Version>,
}

pub type CratesReply = HashMap<String, String>;

#[derive(Deserialize, Debug)]
struct GenericResponse {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}
<commit_msg>Add formatting trait for Crate<commit_after>use std::collections::HashMap;
use std::fmt;

#[derive(Debug, Default, Deserialize)]
pub struct Error {
    pub detail: String,
}

#[derive(Debug, Deserialize)]
pub struct CrateLinks {
    pub owners: Option<String>,
    pub reverse_dependencies: String,
    pub version_downloads: String,
    pub versions: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct Crate {
    pub created_at: String,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub name: String,
    pub repository: Option<String>,
    pub updated_at: String,
    pub versions: Option<Vec<u64>>,
}

#[derive(Debug, Deserialize)]
pub struct Keyword {
    pub crates_cnt: u64,
    pub created_at: String,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize)]
pub struct Version {
    #[serde(rename="crate")]
    pub krate: String,
    pub created_at: String,
    pub dl_path: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String,
    pub updated_at: String,
    pub yanked: bool,
}

#[derive(Debug, Deserialize)]
pub struct Reply {
    #[serde(default)]
    pub errors: Error,
    #[serde(rename="crate")]
    pub krate: Crate,
    pub keywords: Vec<Keyword>,
    pub versions: Vec<Version>,
}

impl fmt::Display for Crate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ref empty = String::new();
        let description = self.description.as_ref().unwrap_or(empty);

        write!(f, "{}\n{}",
            format_args!("{}:{}", "Crate", self.name),
            format_args!("{}:{}", "Description", description)
        )
    }
}

pub type CratesReply = HashMap<String, String>;

#[derive(Deserialize, Debug)]
struct GenericResponse {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}
<|endoftext|>


<commit_before>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;

/// Iterative orthogonalizer using modified Gram-Schmit procedure
#[derive(Debug, Clone)]
pub struct MGS {
    /// Dimension of base space
    dimension: usize,
    /// Basis of spanned space
    q: Vec<Array1>,
}

/// Q-matrix (unitary)
pub type Q = Array2;
/// R-matrix (upper triangle)
pub type R = Array2;

impl MGS {
    /// Create empty linear space
    ///
    /// ```rust
    /// # use ndarray_linalg::*;
    /// const N: usize = 5;
    /// let mgs = MGS::<f32>::new(N);
    /// assert_eq!(mgs.dim(), N);
    /// assert_eq!(mgs.len(), 0);
    /// ```
    pub fn new(dimension: usize) -> Self {
        Self {
            dimension,
            q: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dimension
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Orthogonalize given vector using current basis
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    pub fn orthogonalize<S>(&self, a: &mut ArrayBase<S, Ix1>) -> Array1
    where
        A: Lapack,
        S: DataMut<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a (&mut *a), q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        coef
    }

    /// Add new vector if the residual is larger than relative tolerance
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    ///
    /// ```rust
    /// # use ndarray::*;
    /// # use ndarray_linalg::*;
    /// let mut mgs = MGS::new(3);
    /// let coef = mgs.append(array![0.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0], 1e-9);
    ///
    /// let coef = mgs.append(array![1.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0, 1.0], 1e-9);
    ///
    /// assert!(mgs.append(array![1.0, 2.0, 0.0], 1e-9).is_err());  // Fail if the vector is linearly dependend
    ///
    /// if let Err(coef) = mgs.append(array![1.0, 2.0, 0.0], 1e-9) {
    ///     close_l2(&coef, &array![2.0, 1.0, 0.0], 1e-9); // You can get coefficients of dependent vector
    /// }
    /// ```
    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Result<Array1, Array1>
    where
        A: Lapack,
        S: Data<Elem = A>,
    {
        let mut a = a.into_owned();
        let coef = self.orthogonalize(&mut a);
        let nrm = coef[coef.len() - 1].re();
        if nrm < rtol {
            // Linearly dependent
            return Err(coef);
        }
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Ok(coef)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Q {
        hstack(&self.q).unwrap()
    }
}

/// Strategy for linearly dependent vectors appearing in iterative QR decomposition
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Strategy {
    /// Terminate iteration if dependent vector comes
    Terminate,

    /// Skip dependent vector
    Skip,

    /// Orghotonalize dependent vector without adding to Q,
    /// thus R must be non-regular like following:
    ///
    /// ```text
    /// x x x x x
    /// 0 x x x x
    /// 0 0 0 x x
    /// 0 0 0 0 x
    /// 0 0 0 0 0   // 0-filled to be square matrix
    /// ```
    Full,
}

/// Online QR decomposition of vectors using modified Gram-Schmit algorithm
pub fn mgs(
    iter: impl Iterator<Item = ArrayBase<S, Ix1>>,
    dim: usize,
    rtol: A::Real,
    strategy: Strategy,
) -> (Q, R)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    let mut ortho = MGS::new(dim);
    let mut coefs = Vec::new();
    for a in iter {
        match ortho.append(a, rtol) {
            Ok(coef) => coefs.push(coef),
            Err(coef) => match strategy {
                Strategy::Terminate => break,
                Strategy::Skip => continue,
                Strategy::Full => coefs.push(coef),
            },
        }
    }
    let n = ortho.len();
    let m = coefs.len();
    let mut r = Array2::zeros((n, m).f());
    for j in 0..m {
        for i in 0..n {
            if i < coefs[j].len() {
                r[(i, j)] = coefs[j][i];
            }
        }
    }
    (ortho.get_q(), r)
}
<commit_msg>Fix documents<commit_after>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;

/// Iterative orthogonalizer using modified Gram-Schmit procedure
#[derive(Debug, Clone)]
pub struct MGS {
    /// Dimension of base space
    dimension: usize,
    /// Basis of spanned space
    q: Vec<Array1>,
}

/// Q-matrix (unitary)
pub type Q = Array2;
/// R-matrix (upper triangle)
pub type R = Array2;

impl MGS {
    /// Create empty linear space
    ///
    /// ```rust
    /// # use ndarray_linalg::*;
    /// const N: usize = 5;
    /// let mgs = MGS::<f32>::new(N);
    /// assert_eq!(mgs.dim(), N);
    /// assert_eq!(mgs.len(), 0);
    /// ```
    pub fn new(dimension: usize) -> Self {
        Self {
            dimension,
            q: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dimension
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Orthogonalize given vector using current basis
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismatches to the dimension
    ///
    pub fn orthogonalize<S>(&self, a: &mut ArrayBase<S, Ix1>) -> Array1
    where
        A: Lapack,
        S: DataMut<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a (&mut *a), q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        coef
    }

    /// Add new vector if the residual is larger than relative tolerance
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismatches to the dimension
    ///
    /// ```rust
    /// # use ndarray::*;
    /// # use ndarray_linalg::*;
    /// let mut mgs = MGS::new(3);
    /// let coef = mgs.append(array![0.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0], 1e-9);
    ///
    /// let coef = mgs.append(array![1.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0, 1.0], 1e-9);
    ///
    /// assert!(mgs.append(array![1.0, 2.0, 0.0], 1e-9).is_err());  // Fail if the vector is linearly dependent
    ///
    /// if let Err(coef) = mgs.append(array![1.0, 2.0, 0.0], 1e-9) {
    ///     close_l2(&coef, &array![2.0, 1.0, 0.0], 1e-9); // You can get coefficients of dependent vector
    /// }
    /// ```
    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Result<Array1, Array1>
    where
        A: Lapack,
        S: Data<Elem = A>,
    {
        let mut a = a.into_owned();
        let coef = self.orthogonalize(&mut a);
        let nrm = coef[coef.len() - 1].re();
        if nrm < rtol {
            // Linearly dependent
            return Err(coef);
        }
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Ok(coef)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Q {
        hstack(&self.q).unwrap()
    }
}

/// Strategy for linearly dependent vectors appearing in iterative QR decomposition
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Strategy {
    /// Terminate iteration if dependent vector comes
    Terminate,

    /// Skip dependent vector
    Skip,

    /// Orthogonalize dependent vector without adding to Q,
    /// i.e. R must be non-square like following:
    ///
    /// ```text
    /// x x x x x
    /// 0 x x x x
    /// 0 0 0 x x
    /// 0 0 0 0 x
    /// ```
    Full,
}

/// Online QR decomposition of vectors using modified Gram-Schmit algorithm
pub fn mgs(
    iter: impl Iterator<Item = ArrayBase<S, Ix1>>,
    dim: usize,
    rtol: A::Real,
    strategy: Strategy,
) -> (Q, R)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    let mut ortho = MGS::new(dim);
    let mut coefs = Vec::new();
    for a in iter {
        match ortho.append(a, rtol) {
            Ok(coef) => coefs.push(coef),
            Err(coef) => match strategy {
                Strategy::Terminate => break,
                Strategy::Skip => continue,
                Strategy::Full => coefs.push(coef),
            },
        }
    }
    let n = ortho.len();
    let m = coefs.len();
    let mut r = Array2::zeros((n, m).f());
    for j in 0..m {
        for i in 0..n {
            if i < coefs[j].len() {
                r[(i, j)] = coefs[j][i];
            }
        }
    }
    (ortho.get_q(), r)
}
<|endoftext|>


<commit_before>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

/*
 * Single i8259 PIC chip
 */
struct I8259A
{
    imr: u8,
    isr: u8,
    offset: u8,
    mask: u8,
    icw1: u8,
    icw3: u8,
    next_icw: usize,
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            imr: 0,
            isr: 0,
            offset: 0,
            mask: 0xff,
            icw1: ICW1_INIT | ICW1_ICW4,
            icw3: 0,
            next_icw: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /*
             * Start initialization
             * We support only ICW1 + ICW4
             */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.icw1 = cmd;
            self.next_icw = 2;
        }
    }

    fn read(&mut self) -> u8 {
        self.mask
    }

    fn write(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                if self.icw1 & ICW1_ICW4 != 0 {
                    self.next_icw = 4;
                } else {
                    self.next_icw = 1;
                }
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1;
            },

            _ => {
                self.mask = data; /* Writes go to mask by default */
            }
        }
    }
}

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

    fn init(offset: u8, mask: u8, cascade: u8, use_icw4: bool) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        if use_icw4 {
            dev.command(super::ICW1_INIT | super::ICW1_ICW4);
        } else {
            dev.command(super::ICW1_INIT);
        }
        assert!(!dev.is_initialized());

        dev.write(offset);
        assert!(!dev.is_initialized());

        dev.write(cascade);

        if use_icw4 {
            assert!(!dev.is_initialized());
            dev.write(super::ICW4_8086);
        }

        assert!(dev.is_initialized());

        dev.write(mask);
        assert!(dev.read() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }

    /* Init without ICW4 */
    #[test] fn init_no_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }
}

struct PIC
{
}

impl PIC
{
    fn new() -> PIC {
        PIC {}
    }
}

///////////////////////////////////////////////////////////////////////////////

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);
        vm::IoOperandType::byte(0)
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        unimplemented!();
    }
}

pub fn init(vm: &mut vm::vm)
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_io_region(vm, dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(vm, dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(vm, dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(vm, dev.clone(), PIC_SLAVE_DATA, 1);
}

<commit_msg>pic: io handling<commit_after>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

/*
 * Single i8259 PIC chip
 */
struct I8259A
{
    imr: u8,
    isr: u8,
    offset: u8,
    mask: u8,
    icw1: u8,
    icw3: u8,
    next_icw: usize,
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            imr: 0,
            isr: 0,
            offset: 0,
            mask: 0xff,
            icw1: ICW1_INIT | ICW1_ICW4,
            icw3: 0,
            next_icw: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /*
             * Start initialization
             * We support only ICW1 + ICW4
             */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.icw1 = cmd;
            self.next_icw = 2;
        }
    }

    fn read(&mut self) -> u8 {
        self.mask
    }

    fn write(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                if self.icw1 & ICW1_ICW4 != 0 {
                    self.next_icw = 4;
                } else {
                    self.next_icw = 1;
                }
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1;
            },

            _ => {
                self.mask = data; /* Writes go to mask by default */
            }
        }
    }
}

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

    fn init(offset: u8, mask: u8, cascade: u8, use_icw4: bool) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        if use_icw4 {
            dev.command(super::ICW1_INIT | super::ICW1_ICW4);
        } else {
            dev.command(super::ICW1_INIT);
        }
        assert!(!dev.is_initialized());

        dev.write(offset);
        assert!(!dev.is_initialized());

        dev.write(cascade);

        if use_icw4 {
            assert!(!dev.is_initialized());
            dev.write(super::ICW4_8086);
        }

        assert!(dev.is_initialized());

        dev.write(mask);
        assert!(dev.read() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }

    /* Init without ICW4 */
    #[test] fn init_no_icw4() {
        let mut dev = init(0x08, 0xAB, 0x02, true);
    }
}

struct PIC
{
    master: I8259A,
    slave: I8259A,
}

impl PIC
{
    fn new() -> PIC {
        PIC {
            master: I8259A::default(),
            slave: I8259A::default(),
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);

        let mut dev = self.pic.borrow_mut();
        vm::IoOperandType::byte(
            match port {
                PIC_MASTER_DATA => dev.master.read(),
                PIC_SLAVE_DATA => dev.slave.read(),
                _ => 0,
            }
        )
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        let mut dev = self.pic.borrow_mut();
        let data8 = data.unwrap_byte();

        match port {
            PIC_MASTER_DATA => dev.master.write(data8),
            PIC_SLAVE_DATA => dev.slave.write(data8),
            PIC_MASTER_CMD => dev.master.command(data8),
            PIC_SLAVE_CMD => dev.slave.command(data8),
            _ => panic!(),
        }
    }
}

pub fn init(vm: &mut vm::vm)
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_io_region(vm, dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(vm, dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(vm, dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(vm, dev.clone(), PIC_SLAVE_DATA, 1);
}

<|endoftext|>


<commit_before>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all(format!("{:6} {:6} \
                         {:11} {:11} {:11} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {:15} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {}\n",
                        "HB", "Tag",
                        "Global_Work", "Window_Work", "Work",
                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
                        "Global_Perf", "Window_Perf", "Instant_Perf",
                        "Global_Energy", "Window_Energy", "Start_Energy", "End_Energy",
                        "Global_Pwr", "Window_Pwr", "Instant_Pwr").as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{:<6} {:<6} \
                         {:<11} {:<11} {:<11} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<15.6} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<.6}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<commit_msg>format log output<commit_after>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all(format!("{:6} {:6} \
                         {:11} {:11} {:11} \
                         {:15} {:15} {:20} {:20} \
                         {:15} {:15} {:15} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {}\n",
                        "HB", "Tag",
                        "Global_Work", "Window_Work", "Work",
                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
                        "Global_Perf", "Window_Perf", "Instant_Perf",
                        "Global_Energy", "Window_Energy", "Start_Energy", "End_Energy",
                        "Global_Pwr", "Window_Pwr", "Instant_Pwr").as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{:<6} {:<6} \
                         {:<11} {:<11} {:<11} \
                         {:<15} {:<15} {:<20} {:<20} \
                         {:<15.6} {:<15.6} {:<15.6} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<.6}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub struct SymbolTable {
    levels: Vec<Level>
}

impl SymbolTable {
    pub fn new() -> SymbolTable {
        SymbolTable { levels: vec![Level::new()] }
    }

    pub fn push_level(&mut self) {
        self.levels.push(Level::new());
    }

    pub fn pop_level(&mut self) {
        self.levels.pop()
    }

    pub fn get(&self, name: &str) -> Option<&Sym> {
        for level in self.levels.iter().rev() {
            let found = level.get(name);
            if found.is_some() { return found; }
        }

        None
    }

    pub fn insert(&mut self, name: String, sym: Sym) {
        self.levels.last_mut().unwrap().insert(name, sym);
    }
}

struct Level {
    map: HashMap<String,Sym>
}

impl Level {
    fn new() -> Level {
        Level { map: HashMap::new() }
    }

    fn get(&self, name: &str) -> Option<&Sym> {
        self.map.get(name)
    }

    fn insert(&mut self, name: String, sym: Sym) {
        let old = self.map.insert(name, sym);
        assert!(old.is_none());
    }
}

#[derive(Debug)]
pub enum Sym {
    SymLocalVar,
}
<commit_msg>fixed syntax error<commit_after>use std::collections::HashMap;

pub struct SymbolTable {
    levels: Vec<Level>
}

impl SymbolTable {
    pub fn new() -> SymbolTable {
        SymbolTable { levels: vec![Level::new()] }
    }

    pub fn push_level(&mut self) {
        self.levels.push(Level::new());
    }

    pub fn pop_level(&mut self) {
        self.levels.pop();
    }

    pub fn get(&self, name: &str) -> Option<&Sym> {
        for level in self.levels.iter().rev() {
            let found = level.get(name);
            if found.is_some() { return found; }
        }

        None
    }

    pub fn insert(&mut self, name: String, sym: Sym) {
        self.levels.last_mut().unwrap().insert(name, sym);
    }
}

struct Level {
    map: HashMap<String,Sym>
}

impl Level {
    fn new() -> Level {
        Level { map: HashMap::new() }
    }

    fn get(&self, name: &str) -> Option<&Sym> {
        self.map.get(name)
    }

    fn insert(&mut self, name: String, sym: Sym) {
        let old = self.map.insert(name, sym);
        assert!(old.is_none());
    }
}

#[derive(Debug)]
pub enum Sym {
    SymLocalVar,
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::ops::{
    Add,
    Mul,
};
use std::vec::Vec as StdVec;
use self::blas::Vector;
use self::blas::default::Default;
use self::blas::matrix_vector::ops::{
    Ger,
    Gerc,
};
use self::blas::vector::ops::{Copy, Axpy, Scal, Dot, Dotc};
use mat::Mat;

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

pub enum TransVec<T> {
    T(Vec<T>),
    H(Vec<T>),
}

impl<T> Vec<T> {
    pub fn from_vec(vec: StdVec<T>) -> Vec<T> {
        Vec {
            inc: 1i32,
            data: vec,
        }
    }

    pub fn as_vec(&self) -> &StdVec<T> {
        &self.data
    }
}

impl<T> TransVec<T> {
    pub fn as_vec(&self) -> &Vec<T> {
        match self {
            &TransVec::T(ref v) => v,
            &TransVec::H(ref v) => v,
        }
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(self.data.len());
        l.unwrap()
    }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl<T: Copy> Clone for Vec<T> {
    fn clone(&self) -> Vec<T> {
        let n = self.data.len();
        let mut result = Vec {
            inc: self.inc,
            data: StdVec::with_capacity(n),
        };
        Copy::copy(self, &mut result);
        unsafe { result.data.set_len(n); }

        result
    }
}

impl<T: Copy + Axpy + Default> Add<Vec<T>, Vec<T>> for Vec<T> {
    fn add(&self, x: &Vec<T>) -> Vec<T> {
        let mut result = self.clone();
        let one: T = Default::one();
        Axpy::axpy(&one, x, &mut result);
        result
    }
}

impl<T: Copy + Scal> Mul<T, Vec<T>> for Vec<T> {
    fn mul(&self, alpha: &T) -> Vec<T> {
        let mut result = self.clone();
        Scal::scal(alpha, &mut result);
        result
    }
}

impl<T: Copy + Ger + Gerc + Default> Mul<TransVec<T>, Mat<T>> for Vec<T> {
    fn mul(&self, x: &TransVec<T>) -> Mat<T> {
        let v = x.as_vec();
        let rows = self.data.len();
        let cols = v.data.len();
        let one = Default::one();
        let mut result = Mat::zero(rows, cols);

        match x {
            &TransVec::T(_) => Ger::ger(&one, self, v, &mut result),
            &TransVec::H(_) => Gerc::gerc(&one, self, v, &mut result),
        }

        result
    }
}

impl<T: Copy + Dot + Dotc> Mul<Vec<T>, T> for TransVec<T> {
    fn mul(&self, x: &Vec<T>) -> T {
        match *self {
            TransVec::T(ref v) => Dot::dot(v, x),
            TransVec::H(ref v) => Dotc::dotc(v, x),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate num;

    use self::num::complex::Complex;
    use vec::Vec;
    use vec::TransVec::{
        T,
        H,
    };

    #[test]
    fn add() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = Vec::from_vec(vec![-1f32, 2f32]);

        assert_eq!((x + y).as_vec(), &vec![0f32, 4f32]);
    }

    #[test]
    fn scalar_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);

        assert_eq!((x * 3.0).as_vec(), &vec![3f32, 6f32]);
    }

    #[test]
    fn dot_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = Vec::from_vec(vec![-1f32, 2f32]);

        assert_eq!(T(x) * y, 3.0);
    }

    #[test]
    fn complex_conj() {
        let x = Vec::from_vec(vec![Complex::new(1f32, -1f32), Complex::new(1f32, -3f32)]);
        let y = Vec::from_vec(vec![Complex::new(1f32, 2f32), Complex::new(1f32, 3f32)]);

        assert_eq!(H(x) * y, Complex::new(-9f32, 9f32));
    }
}
<commit_msg>Clean Vec impls<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate blas;
extern crate num;

use std::num::NumCast;
use std::ops::{
    Add,
    Mul,
};
use std::vec::Vec as StdVec;
use self::blas::Vector;
use self::blas::default::Default;
use self::blas::matrix_vector::ops::{
    Ger,
    Gerc,
};
use self::blas::vector::ops::{
    Axpy,
    Copy,
    Dot,
    Dotc,
    Scal,
};
use mat::Mat;

pub struct Vec<T> {
    inc: i32,
    data: StdVec<T>,
}

pub enum TransVec<T> {
    T(Vec<T>),
    H(Vec<T>),
}

impl<T> Vec<T> {
    pub fn from_vec(vec: StdVec<T>) -> Vec<T> {
        Vec {
            inc: 1i32,
            data: vec,
        }
    }

    pub fn as_vec(&self) -> &StdVec<T> {
        &self.data
    }
}

impl<T> TransVec<T> {
    pub fn as_vec(&self) -> &Vec<T> {
        match self {
            &TransVec::T(ref v) => v,
            &TransVec::H(ref v) => v,
        }
    }
}

impl<T> Vector<T> for Vec<T> {
    #[inline]
    fn inc(&self) -> i32 { self.inc }

    #[inline]
    fn len(&self) -> i32 {
        let l: Option<i32> = NumCast::from(self.data.len());
        l.unwrap()
    }

    #[inline]
    fn as_ptr(&self) -> *const T { self.data.as_slice().as_ptr() }

    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T { self.data.as_mut_slice().as_mut_ptr() }
}

impl<T: Copy> Clone for Vec<T> {
    fn clone(&self) -> Vec<T> {
        let n = self.data.len();
        let mut result = Vec {
            inc: self.inc,
            data: StdVec::with_capacity(n),
        };
        Copy::copy(self, &mut result);
        unsafe { result.data.set_len(n); }

        result
    }
}

impl<T> Add<Vec<T>, Vec<T>> for Vec<T>
where T: Axpy + Copy + Default {
    fn add(&self, x: &Vec<T>) -> Vec<T> {
        let mut result = self.clone();
        let one: T = Default::one();
        Axpy::axpy(&one, x, &mut result);
        result
    }
}

impl<T> Mul<T, Vec<T>> for Vec<T>
where T: Copy + Scal {
    fn mul(&self, alpha: &T) -> Vec<T> {
        let mut result = self.clone();
        Scal::scal(alpha, &mut result);
        result
    }
}

impl<T> Mul<TransVec<T>, Mat<T>> for Vec<T>
where T: Copy + Default + Ger + Gerc {
    fn mul(&self, x: &TransVec<T>) -> Mat<T> {
        let v = x.as_vec();
        let rows = self.data.len();
        let cols = v.data.len();
        let one = Default::one();
        let mut result = Mat::zero(rows, cols);

        match x {
            &TransVec::T(_) => Ger::ger(&one, self, v, &mut result),
            &TransVec::H(_) => Gerc::gerc(&one, self, v, &mut result),
        }

        result
    }
}

impl<T> Mul<Vec<T>, T> for TransVec<T>
where T: Copy + Dot + Dotc {
    fn mul(&self, x: &Vec<T>) -> T {
        match *self {
            TransVec::T(ref v) => Dot::dot(v, x),
            TransVec::H(ref v) => Dotc::dotc(v, x),
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate num;

    use self::num::complex::Complex;
    use vec::Vec;
    use vec::TransVec::{
        T,
        H,
    };

    #[test]
    fn add() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = Vec::from_vec(vec![-1f32, 2f32]);

        assert_eq!((x + y).as_vec(), &vec![0f32, 4f32]);
    }

    #[test]
    fn scalar_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);

        assert_eq!((x * 3.0).as_vec(), &vec![3f32, 6f32]);
    }

    #[test]
    fn dot_mul() {
        let x = Vec::from_vec(vec![1f32, 2f32]);
        let y = Vec::from_vec(vec![-1f32, 2f32]);

        assert_eq!(T(x) * y, 3.0);
    }

    #[test]
    fn complex_conj() {
        let x = Vec::from_vec(vec![Complex::new(1f32, -1f32), Complex::new(1f32, -3f32)]);
        let y = Vec::from_vec(vec![Complex::new(1f32, 2f32), Complex::new(1f32, 3f32)]);

        assert_eq!(H(x) * y, Complex::new(-9f32, 9f32));
    }
}
<|endoftext|>


<commit_before>
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
struct ColorCode(u8);

impl ColorCode {
    fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

#[repr(transparent)]
struct Buffer {
    chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: &'static mut Buffer,
}

impl Writer {
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;
                self.buffer.chars[row][col] = ScreenChar {
                    ascii_character: byte,
                    color_code,
                };
                self.column_position += 1;
            }
        }
    }

    fn new_line(&mut self) {
        todo!()
    }

    pub fn write_string(&mut self, s: &str) {
        for byte in s.bytes() {
            match byte {
                // printable ASCII byte or newline
                0x20..=0x7e | b'\n' => self.write_byte(byte),
                // not part of printable ASCII range
                _ => self.write_byte(0xfe),
            }
        }
    }
}

pub fn print_something() {
    let mut writer = Writer {
        column_position: 0,
        color_code: ColorCode::new(Color::Yellow, Color::Black),
        buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
    };

    writer.write_byte(b'H');
    writer.write_string("ello ");
    writer.write_string("Wörld!");
}
<commit_msg>vga: mark the VGA buffer as volatile<commit_after>use volatile::Volatile;

#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
struct ColorCode(u8);

impl ColorCode {
    fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;

#[repr(transparent)]
struct Buffer {
    chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: &'static mut Buffer,
}

impl Writer {
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;
                self.buffer.chars[row][col].write(ScreenChar {
                    ascii_character: byte,
                    color_code,
                });
                self.column_position += 1;
            }
        }
    }

    fn new_line(&mut self) {
        todo!()
    }

    pub fn write_string(&mut self, s: &str) {
        for byte in s.bytes() {
            match byte {
                // printable ASCII byte or newline
                0x20..=0x7e | b'\n' => self.write_byte(byte),
                // not part of printable ASCII range
                _ => self.write_byte(0xfe),
            }
        }
    }
}

pub fn print_something() {
    let mut writer = Writer {
        column_position: 0,
        color_code: ColorCode::new(Color::Yellow, Color::Black),
        buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
    };

    writer.write_byte(b'H');
    writer.write_string("ello ");
    writer.write_string("Wörld!");
}
<|endoftext|>


<commit_before>// Copyright 2013-2015 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.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

extern crate kernel32;
extern crate winapi;

use std::ffi::OsStr;
use std::io::prelude::*;
use std::io;
use std::os::windows::ffi::OsStrExt;
use std::ptr;

use Attr;
use color;
use Terminal;

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let color = match bits & 0x7 {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!()
    };

    color | (bits & 0x8) // copy the hi-intensity bit
}

// Just get a handle to the current console buffer whatever it is
fn conout() -> io::Result<winapi::HANDLE> {
    let name: &OsStr = "CONOUT$\0".as_ref();
    let name: Vec<u16> = name.encode_wide().collect();
    let handle = unsafe {
        kernel32::CreateFileW(
            name.as_ptr(),
            winapi::GENERIC_READ | winapi::GENERIC_WRITE,
            winapi::FILE_SHARE_WRITE,
            ptr::null_mut(),
            winapi::OPEN_EXISTING,
            0,
            ptr::null_mut(),
        )
    };
    if handle == winapi::INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else {
        Ok(handle)
    }
}

// This test will only pass if it is running in an actual console, probably
#[test]
fn test_conout() {
    assert!(conout().is_ok())
}

impl<T: Write+Send> WinConsole<T> {
    fn apply(&mut self) -> io::Result<()> {
        let out = try!(conout());
        let _unused = self.buf.flush();
        let mut accum: winapi::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;
        unsafe {
            kernel32::SetConsoleTextAttribute(out, accum);
        }
        Ok(())
    }

    /// Returns `None` whenever the terminal cannot be created for some
    /// reason.
    pub fn new(out: T) -> io::Result<WinConsole<T>> {
        let fg;
        let bg;
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                fg = bits_to_color(buffer_info.wAttributes);
                bg = bits_to_color(buffer_info.wAttributes >> 4);
            } else {
                return Err(io::Error::last_os_error())
            }
        }
        Ok(WinConsole {
            buf: out,
            def_foreground: fg,
            def_background: bg,
            foreground: fg,
            background: bg,
        })
    }
}

impl<T: Write> Write for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl<T: Write+Send> Terminal for WinConsole<T> {
    type Output = T;

    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        self.foreground = color;
        try!(self.apply());

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        self.background = color;
        try!(self.apply());

        Ok(true)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(f) => {
                self.foreground = f;
                try!(self.apply());
                Ok(true)
            },
            Attr::BackgroundColor(b) => {
                self.background = b;
                try!(self.apply());
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        self.foreground = self.def_foreground;
        self.background = self.def_background;
        try!(self.apply());

        Ok(true)
    }

    fn cursor_up(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y);
                if y == 0 {
                    Ok(false)
                } else {
                    let pos = winapi::COORD { X: x, Y: y - 1 };
                    if kernel32::SetConsoleCursorPosition(handle, pos) != 0 {
                        Ok(true)
                    } else {
                        Err(io::Error::last_os_error())
                    }
                }
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    fn delete_line(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
                return Err(io::Error::last_os_error())
            }
            let pos = buffer_info.dwCursorPosition;
            let size = buffer_info.dwSize;
            let num = (size.X - pos.X) as winapi::DWORD;
            let mut written = 0;
            if kernel32::FillConsoleOutputCharacterW(handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error())
            }
            if kernel32::FillConsoleOutputAttribute(handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error())
            }
            Ok(written != 0)
        }
    }

    fn carriage_return(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y);
                if x == 0 {
                    Ok(false)
                } else {
                    let pos = winapi::COORD { X: 0, Y: y };
                    if kernel32::SetConsoleCursorPosition(handle, pos) != 0 {
                        Ok(true)
                    } else {
                        Err(io::Error::last_os_error())
                    }
                }
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }

    fn into_inner(self) -> T where Self: Sized { self.buf }
}
<commit_msg>Avoid unnecessary allocation and conversions.<commit_after>// Copyright 2013-2015 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.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

extern crate kernel32;
extern crate winapi;

use std::io::prelude::*;
use std::io;
use std::ptr;

use Attr;
use color;
use Terminal;

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let color = match bits & 0x7 {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!()
    };

    color | (bits & 0x8) // copy the hi-intensity bit
}

// Just get a handle to the current console buffer whatever it is
fn conout() -> io::Result<winapi::HANDLE> {
    let name = b"CONOUT$\0";
    let handle = unsafe {
        kernel32::CreateFileA(
            name.as_ptr() as *const i8,
            winapi::GENERIC_READ | winapi::GENERIC_WRITE,
            winapi::FILE_SHARE_WRITE,
            ptr::null_mut(),
            winapi::OPEN_EXISTING,
            0,
            ptr::null_mut(),
        )
    };
    if handle == winapi::INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else {
        Ok(handle)
    }
}

// This test will only pass if it is running in an actual console, probably
#[test]
fn test_conout() {
    assert!(conout().is_ok())
}

impl<T: Write+Send> WinConsole<T> {
    fn apply(&mut self) -> io::Result<()> {
        let out = try!(conout());
        let _unused = self.buf.flush();
        let mut accum: winapi::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;
        unsafe {
            kernel32::SetConsoleTextAttribute(out, accum);
        }
        Ok(())
    }

    /// Returns `None` whenever the terminal cannot be created for some
    /// reason.
    pub fn new(out: T) -> io::Result<WinConsole<T>> {
        let fg;
        let bg;
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                fg = bits_to_color(buffer_info.wAttributes);
                bg = bits_to_color(buffer_info.wAttributes >> 4);
            } else {
                return Err(io::Error::last_os_error())
            }
        }
        Ok(WinConsole {
            buf: out,
            def_foreground: fg,
            def_background: bg,
            foreground: fg,
            background: bg,
        })
    }
}

impl<T: Write> Write for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl<T: Write+Send> Terminal for WinConsole<T> {
    type Output = T;

    fn fg(&mut self, color: color::Color) -> io::Result<bool> {
        self.foreground = color;
        try!(self.apply());

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> io::Result<bool> {
        self.background = color;
        try!(self.apply());

        Ok(true)
    }

    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
        match attr {
            Attr::ForegroundColor(f) => {
                self.foreground = f;
                try!(self.apply());
                Ok(true)
            },
            Attr::BackgroundColor(b) => {
                self.background = b;
                try!(self.apply());
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> io::Result<bool> {
        self.foreground = self.def_foreground;
        self.background = self.def_background;
        try!(self.apply());

        Ok(true)
    }

    fn cursor_up(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y);
                if y == 0 {
                    Ok(false)
                } else {
                    let pos = winapi::COORD { X: x, Y: y - 1 };
                    if kernel32::SetConsoleCursorPosition(handle, pos) != 0 {
                        Ok(true)
                    } else {
                        Err(io::Error::last_os_error())
                    }
                }
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    fn delete_line(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
                return Err(io::Error::last_os_error())
            }
            let pos = buffer_info.dwCursorPosition;
            let size = buffer_info.dwSize;
            let num = (size.X - pos.X) as winapi::DWORD;
            let mut written = 0;
            if kernel32::FillConsoleOutputCharacterW(handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error())
            }
            if kernel32::FillConsoleOutputAttribute(handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error())
            }
            Ok(written != 0)
        }
    }

    fn carriage_return(&mut self) -> io::Result<bool> {
        let _unused = self.buf.flush();
        let handle = try!(conout());
        unsafe {
            let mut buffer_info = ::std::mem::uninitialized();
            if kernel32::GetConsoleScreenBufferInfo(handle, &mut buffer_info) != 0 {
                let (x, y) = (buffer_info.dwCursorPosition.X, buffer_info.dwCursorPosition.Y);
                if x == 0 {
                    Ok(false)
                } else {
                    let pos = winapi::COORD { X: 0, Y: y };
                    if kernel32::SetConsoleCursorPosition(handle, pos) != 0 {
                        Ok(true)
                    } else {
                        Err(io::Error::last_os_error())
                    }
                }
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }

    fn into_inner(self) -> T where Self: Sized { self.buf }
}
<|endoftext|>


<commit_before>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(Pattern, usize)>,
    pub error_matches: Vec<ErrorMatch>,
    /// Ignore diagnostics below this level.
    /// `None` means pick the lowest level from the `error_pattern`s.
    pub require_annotations_for_level: Option<Level>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
    /// Tests that the target is the host.
    OnHost,
}

#[derive(Debug, Clone)]
pub(crate) enum Pattern {
    SubString(String),
    Regex(Regex),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub pattern: Pattern,
    pub revision: Option<String>,
    pub level: Level,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Result<Self> {
        if c == "on-host" {
            Ok(Condition::OnHost)
        } else if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Ok(Condition::Bitwidth(bits))
        } else if let Some(target) = c.strip_prefix("target-") {
            Ok(Condition::Target(target.to_owned()))
        } else {
            Err(eyre!("invalid ignore/only condition {c:?}"))
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    ensure!(next == ':', "test command must be followed by : (or end the line)");
                    (command, args.as_str().trim())
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is
                /// returned in the first component. `\` can be used to escape arbitrary character.
                /// Second return component is the rest of the string with leading whitespace removed.
                fn parse_str(s: &str) -> Result<(&str, &str)> {
                    let mut chars = s.char_indices();
                    match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 {
                        '"' => {
                            let s = chars.as_str();
                            let mut escaped = false;
                            for (i, c) in chars {
                                if escaped {
                                    // Accept any character as literal after a `\`.
                                    escaped = false;
                                } else if c == '"' {
                                    return Ok((&s[..(i - 1)], s[i..].trim_start()));
                                } else {
                                    escaped = c == '\\';
                                }
                            }
                            bail!("no closing quotes found for {s}")
                        }
                        c => bail!("expected '\"', got {c}"),
                    }
                }

                let (from, rest) = parse_str(args)?;

                let to = rest.strip_prefix("->").ok_or_else(|| {
                    eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`")
                })?.trim_start();
                let (to, rest) = parse_str(to)?;

                ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}");

                let from = Regex::new(from)?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((Pattern::parse(args.trim())?, l));
            }
            "stderr-per-bitwidth" => {
                // args are ignored (can be used as comment)
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            "require-annotations-for-level" => {
                ensure!(
                    self.require_annotations_for_level.is_none(),
                    "cannot specify `require-annotations-for-level` twice"
                );
                self.require_annotations_for_level = Some(args.trim().parse()?);
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    // args are ignored (can be sue as comment)
                    self.ignore.push(Condition::parse(s)?);
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    // args are ignored (can be sue as comment)
                    self.only.push(Condition::parse(s)?);
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE): (?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let pattern = pattern.trim_start();
        let offset = pattern
            .chars()
            .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z'))
            .ok_or_else(|| eyre!("pattern without level"))?;

        let level = pattern[..offset].parse()?;
        let pattern = &pattern[offset..];
        let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?;

        let pattern = pattern.trim();

        ensure!(!pattern.is_empty(), "no pattern specified");

        let pattern = Pattern::parse(pattern)?;

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            pattern,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}

impl Pattern {
    pub(crate) fn matches(&self, message: &str) -> bool {
        match self {
            Pattern::SubString(s) => message.contains(s),
            Pattern::Regex(r) => r.is_match(message),
        }
    }

    pub(crate) fn parse(pattern: &str) -> Result<Self> {
        if let Some(pattern) = pattern.strip_prefix('/') {
            let regex =
                pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?;
            Ok(Pattern::Regex(Regex::new(regex)?))
        } else {
            Ok(Pattern::SubString(pattern.to_string()))
        }
    }
}
<commit_msg>make an expect into proper error reporting<commit_after>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(Pattern, usize)>,
    pub error_matches: Vec<ErrorMatch>,
    /// Ignore diagnostics below this level.
    /// `None` means pick the lowest level from the `error_pattern`s.
    pub require_annotations_for_level: Option<Level>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
    /// Tests that the target is the host.
    OnHost,
}

#[derive(Debug, Clone)]
pub(crate) enum Pattern {
    SubString(String),
    Regex(Regex),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub pattern: Pattern,
    pub revision: Option<String>,
    pub level: Level,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Result<Self> {
        if c == "on-host" {
            Ok(Condition::OnHost)
        } else if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().map_err(|_err| {
                eyre!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith")
            })?;
            Ok(Condition::Bitwidth(bits))
        } else if let Some(target) = c.strip_prefix("target-") {
            Ok(Condition::Target(target.to_owned()))
        } else {
            Err(eyre!("invalid ignore/only condition {c:?}"))
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    ensure!(next == ':', "test command must be followed by : (or end the line)");
                    (command, args.as_str().trim())
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is
                /// returned in the first component. `\` can be used to escape arbitrary character.
                /// Second return component is the rest of the string with leading whitespace removed.
                fn parse_str(s: &str) -> Result<(&str, &str)> {
                    let mut chars = s.char_indices();
                    match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 {
                        '"' => {
                            let s = chars.as_str();
                            let mut escaped = false;
                            for (i, c) in chars {
                                if escaped {
                                    // Accept any character as literal after a `\`.
                                    escaped = false;
                                } else if c == '"' {
                                    return Ok((&s[..(i - 1)], s[i..].trim_start()));
                                } else {
                                    escaped = c == '\\';
                                }
                            }
                            bail!("no closing quotes found for {s}")
                        }
                        c => bail!("expected '\"', got {c}"),
                    }
                }

                let (from, rest) = parse_str(args)?;

                let to = rest.strip_prefix("->").ok_or_else(|| {
                    eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`")
                })?.trim_start();
                let (to, rest) = parse_str(to)?;

                ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}");

                let from = Regex::new(from)?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((Pattern::parse(args.trim())?, l));
            }
            "stderr-per-bitwidth" => {
                // args are ignored (can be used as comment)
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            "require-annotations-for-level" => {
                ensure!(
                    self.require_annotations_for_level.is_none(),
                    "cannot specify `require-annotations-for-level` twice"
                );
                self.require_annotations_for_level = Some(args.trim().parse()?);
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    // args are ignored (can be sue as comment)
                    self.ignore.push(Condition::parse(s)?);
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    // args are ignored (can be sue as comment)
                    self.only.push(Condition::parse(s)?);
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE): (?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let pattern = pattern.trim_start();
        let offset = pattern
            .chars()
            .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z'))
            .ok_or_else(|| eyre!("pattern without level"))?;

        let level = pattern[..offset].parse()?;
        let pattern = &pattern[offset..];
        let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?;

        let pattern = pattern.trim();

        ensure!(!pattern.is_empty(), "no pattern specified");

        let pattern = Pattern::parse(pattern)?;

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            pattern,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}

impl Pattern {
    pub(crate) fn matches(&self, message: &str) -> bool {
        match self {
            Pattern::SubString(s) => message.contains(s),
            Pattern::Regex(r) => r.is_match(message),
        }
    }

    pub(crate) fn parse(pattern: &str) -> Result<Self> {
        if let Some(pattern) = pattern.strip_prefix('/') {
            let regex =
                pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?;
            Ok(Pattern::Regex(Regex::new(regex)?))
        } else {
            Ok(Pattern::SubString(pattern.to_string()))
        }
    }
}
<|endoftext|>