<commit_before>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```no_run
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    inputs: Vec<Sample>,
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs unless they are manually supplied using
    /// DeviceChain::get_input.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        DeviceChain {
            inputs: vec![0.0; device.num_inputs()],
            devices: vec![AudioNode::new(device)],
            time: 0
        }
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    ///
    /// # Panics
    ///
    /// Panics if the provided device does not have as many inputs as the
    /// previous device has outputs.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].outputs.len() != device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device));
        self
    }

    /// Return a mutable slice to the input of the first device in the chain.
    ///
    /// These inputs never get overwritten, so if you are supplying input you
    /// must manually zero the buffer again.
    pub fn get_input(&mut self) -> &mut[Sample] {
        &mut self.inputs
    }

    /// Returns a slice to the output of the last device in the chain.
    pub fn get_output(&self) -> &[Sample] {
        &self.devices[self.devices.len()-1].outputs
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        self.devices[0].tick(self.time, &self.inputs);
        for i in 1..self.devices.len() {
            let inputs = self.devices[i-1].outputs.clone();
            self.devices[i].tick(self.time, &inputs);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and provide an allocated buffer to
/// contain its output.
struct AudioNode {
    device: Box<AudioDevice>,
    outputs: Vec<Sample>
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate its output
    /// buffer.
    fn new<D>(device: D) -> AudioNode where D: 'static+AudioDevice {
        let n = device.num_outputs();
        AudioNode {
            device: Box::new(device),
            outputs: vec![0.0; n]
        }
    }

    /// Ticks the device one time step.
    ///
    /// `inputs` should be the output of the previous device.
    fn tick(&mut self, t: Time, inputs: &[Sample]) {
        self.device.tick(t, inputs, &mut self.outputs);
    }
}
<commit_msg>Switch chain to use a single audio buffer<commit_after>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```no_run
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    bus: Vec<Sample>,
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs unless they are manually supplied using
    /// DeviceChain::get_input.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        let mut chain = DeviceChain {
            bus: Vec::new(),
            devices: Vec::new(),
            time: 0
        };
        chain.devices.push(AudioNode::new(device, &mut chain.bus));
        chain
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    ///
    /// # Panics
    ///
    /// Panics if the provided device does not have as many inputs as the
    /// previous device has outputs.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].device.num_outputs() !=
                device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device, &mut self.bus));
        self
    }

    /// Return a mutable slice to the input of the first device in the chain.
    ///
    /// These inputs never get overwritten, so if you are supplying input you
    /// must manually zero the buffer again.
    pub fn get_input(&mut self) -> &mut[Sample] {
        &mut self.bus[..self.devices[0].device.num_inputs()]
    }

    /// Returns a slice to the output of the last device in the chain.
    pub fn get_output(&self) -> &[Sample] {
        let outputs = self.devices[self.devices.len()-1].device.num_outputs();
        &self.bus[self.bus.len()-outputs..]
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        for device in self.devices.iter_mut() {
            device.tick(self.time, &mut self.bus);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and stores an index into the bus.
struct AudioNode {
    device: Box<AudioDevice>,
    bus_start: usize,
    bus_end: usize,
    split_point: usize
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate space for it
    /// in the bus.
    fn new<D>(device: D, bus: &mut Vec<Sample>) -> AudioNode
            where D: 'static+AudioDevice {
        let inputs = device.num_inputs();
        let outputs = device.num_outputs();
        let bus_start = bus.len() - inputs;
        for _ in 0..outputs {
            bus.push(0.0);
        }
        AudioNode {
            device: Box::new(device),
            bus_start: bus_start,
            bus_end: bus_start + inputs + outputs,
            split_point: inputs,
        }
    }

    /// Ticks the device one time step.
    fn tick(&mut self, t: Time, bus: &mut [Sample]) {
        let bus_slice = &mut bus[self.bus_start .. self.bus_end];
        let (inputs, outputs) = bus_slice.split_at_mut(self.split_point);
        self.device.tick(t, inputs, outputs);
    }
}
<|endoftext|>


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

#![deny(warnings)]

extern crate build_helper;
extern crate gcc;

use std::env;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
        !target.contains("emscripten") && !target.contains("fuchsia") {
        let _ = build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") || target.contains("mips") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=socket");
        println!("cargo:rustc-link-lib=posix4");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");

        // res_init and friends require -lresolv on macOS/iOS.
        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        // use system-provided libbacktrace
        if cfg!(feature = "backtrace") {
            println!("cargo:rustc-link-lib=backtrace");
        }
        println!("cargo:rustc-link-lib=magenta");
        println!("cargo:rustc-link-lib=mxio");
        println!("cargo:rustc-link-lib=launchpad"); // for std::process
    }
}

fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
    let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
    let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                             .collect::<Vec<_>>().join(" ");
    cflags.push_str(" -fvisibility=hidden");
    run(Command::new("sh")
                .current_dir(&native.out_dir)
                .arg(native.src_dir.join("configure").to_str().unwrap()
                                   .replace("C:\\", "/c/")
                                   .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));

    run(Command::new(build_helper::make(host))
                .current_dir(&native.out_dir)
                .arg(format!("INCDIR={}", native.src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
    Ok(())
}
<commit_msg>Remove incorrect special case of mips-musl<commit_after>// Copyright 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.

#![deny(warnings)]

extern crate build_helper;
extern crate gcc;

use std::env;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
        !target.contains("emscripten") && !target.contains("fuchsia") {
        let _ = build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else if !target.contains("musl") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=socket");
        println!("cargo:rustc-link-lib=posix4");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");

        // res_init and friends require -lresolv on macOS/iOS.
        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
        println!("cargo:rustc-link-lib=resolv");
    } else if target.contains("windows") {
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    } else if target.contains("fuchsia") {
        // use system-provided libbacktrace
        if cfg!(feature = "backtrace") {
            println!("cargo:rustc-link-lib=backtrace");
        }
        println!("cargo:rustc-link-lib=magenta");
        println!("cargo:rustc-link-lib=mxio");
        println!("cargo:rustc-link-lib=launchpad"); // for std::process
    }
}

fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
    let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
    let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                             .collect::<Vec<_>>().join(" ");
    cflags.push_str(" -fvisibility=hidden");
    run(Command::new("sh")
                .current_dir(&native.out_dir)
                .arg(native.src_dir.join("configure").to_str().unwrap()
                                   .replace("C:\\", "/c/")
                                   .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));

    run(Command::new(build_helper::make(host))
                .current_dir(&native.out_dir)
                .arg(format!("INCDIR={}", native.src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
    Ok(())
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,
}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],
        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::And { vr, vy } => self.reg_v[vr] &= self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skner { vr, vy } => {
                if self.reg_v[vr] != self.reg_v[vy] {
                    self.pc += 2;
                }
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Skne { vr, k } => {
                if self.reg_v[vr] != k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                if overflow {
                    self.reg_v[0xF] = 1
                } else {
                    self.reg_v[0xF] = 0
                }
                self.reg_v[vr] = result;
            }
            Instruction::Subr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_sub(old_y);
                self.reg_v[0xF] = if overflow { 0 } else { 1 };
                self.reg_v[vr] = result;
            }
            Instruction::Subn { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_y.overflowing_sub(old_r);
                self.reg_v[0xF] = if overflow { 0 } else { 1 };
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Skipping if key {:x} is pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Sknp { k } => {
                println!("Skipping if key {:x} is not pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => {}
                    _ => self.pc += 2,
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:x}", x);
                        self.reg_v[vr] = x
                    }
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = value % 10;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000 / 60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

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

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<commit_msg>Small cleanup<commit_after>use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{thread, time};
use std::thread::JoinHandle;

use instruction::Instruction;
use peripherals::Peripherals;

use rand::{thread_rng, Rng};

const FONT_BASE_ADDR: usize = 0x0;
const NUM_FONTS: usize = 16;
const FONT_SIZE: usize = 5;
const FONT_MAP: [u8; NUM_FONTS * FONT_SIZE] =
    [0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0,
     0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0,
     0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0,
     0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xE0, 0x90, 0xE0,
     0xF0, 0x80, 0x80, 0x80, 0xF0, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0,
     0xF0, 0x80, 0xF0, 0x80, 0x80];

pub struct Chip8 {
    mem: Vec<u8>,
    reg_v: Vec<u8>,
    reg_i: u16,
    reg_delay_timer: Arc<AtomicUsize>,
    reg_sound_timer: u8,
    pc: usize,
    sp: usize,
    stack: Vec<usize>,
}

impl Chip8 {
    pub fn new(rom: &Vec<u8>) -> Chip8 {
        let mut chip8 = Chip8 {
            mem: vec![0; 0xFFF],
            reg_v: vec![0; 16],
            reg_i: 0,
            reg_delay_timer: Arc::new(AtomicUsize::new(0)),
            reg_sound_timer: 0,
            pc: 0x200,
            sp: 0,
            stack: vec![0; 16],
        };
        chip8.load_fonts();
        chip8.load_rom(rom);
        chip8
    }

    fn load_fonts(&mut self) {
        for i in FONT_BASE_ADDR..FONT_MAP.len() {
            self.mem[i] = FONT_MAP[i - FONT_BASE_ADDR]
        }
    }

    fn load_rom(&mut self, rom: &Vec<u8>) {
        for (b, buf_i) in rom.iter().enumerate() {
            self.mem[0x200 + b] = *buf_i;
        }
    }

    pub fn step(&mut self, peripherals: &mut Peripherals) {
        let hi_nibble = self.mem[self.pc] as u16;
        let lo_nibble = self.mem[self.pc + 1] as u16;
        let opcode = (hi_nibble << 8) | lo_nibble;
        match Instruction::try_from(opcode) {
            Err(msg) => panic!("Error decoding instruction at 0x{0:03x}: {1}", self.pc, msg),
            Ok(instruction) => self.step_instruction(instruction, peripherals),
        }
    }

    fn memory_read(&self, pos: usize) -> u8 {
        self.mem[pos]
    }

    fn memory_write(&mut self, pos: usize, data: u8) {
        self.mem[pos] = data;
        // println!("[W][0x{:03x}] 0x{:03x}", pos, data);
    }

    fn step_instruction(&mut self, instruction: Instruction, peripherals: &mut Peripherals) {
        match instruction {
            Instruction::Cls => peripherals.video_engine.cls(),
            Instruction::Ret => {
                assert!(self.sp > 0);
                self.sp -= 1;
                let old_pc = self.stack[self.sp];
                println!("Resuming execution at PC 0x{:x}", old_pc);
                self.pc = old_pc; // Jump to the instruction immediately after
            }
            Instruction::Jmp { addr } => self.pc = addr - 2, // Correct for pc increment later
            Instruction::Jsr { addr } => {
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr - 2
            } // Correct for pc increment later
            Instruction::Mov { vr, k } => self.reg_v[vr] = k,
            Instruction::Movr { vr, vy } => self.reg_v[vr] = self.reg_v[vy],
            Instruction::And { vr, vy } => self.reg_v[vr] &= self.reg_v[vy],
            Instruction::Shr { vr } => {
                let current_val = self.reg_v[vr];
                self.reg_v[0xF] = current_val & 1;
                self.reg_v[vr] = current_val >> 1;
            }
            Instruction::Skner { vr, vy } => {
                if self.reg_v[vr] != self.reg_v[vy] {
                    self.pc += 2;
                }
            }
            Instruction::Skeq { vr, k } => {
                if self.reg_v[vr] == k {
                    self.pc += 2
                }
            }
            Instruction::Skne { vr, k } => {
                if self.reg_v[vr] != k {
                    self.pc += 2
                }
            }
            Instruction::Add { vr, k } => {
                let old_val = self.reg_v[vr];
                self.reg_v[vr] = old_val.wrapping_add(k);
            }
            Instruction::Addr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_add(old_y);
                self.reg_v[0xF] = if overflow { 1 } else { 0 };
                self.reg_v[vr] = result;
            }
            Instruction::Subr { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_r.overflowing_sub(old_y);
                self.reg_v[0xF] = if overflow { 0 } else { 1 };
                self.reg_v[vr] = result;
            }
            Instruction::Subn { vr, vy } => {
                let old_r = self.reg_v[vr];
                let old_y = self.reg_v[vy];
                let (result, overflow) = old_y.overflowing_sub(old_r);
                self.reg_v[0xF] = if overflow { 0 } else { 1 };
                self.reg_v[vr] = result;
            }
            Instruction::Mvi { k } => self.reg_i = k,
            Instruction::Rnd { vr, k } => {
                let mut buffer = [0u8; 1];
                thread_rng().fill_bytes(&mut buffer);
                self.reg_v[vr] = buffer[0] & k;
            }
            Instruction::Sprite { rx, ry, s } => {
                let x = self.reg_v[rx] as usize;
                let y = self.reg_v[ry] as usize;
                let height = s;
                self.reg_v[0xF] = 0;
                for yline in 0..height {
                    let mem_pos = self.reg_i as usize + yline as usize;
                    let pixel = self.memory_read(mem_pos);
                    for xline in 0..8 {
                        if pixel & (0x80 >> xline) != 0 {
                            let collision = peripherals.video_engine
                                .set_pixel_to_1(x + xline, y + yline);
                            if collision {
                                self.reg_v[0xF] = 1;
                            }
                        }

                    }
                }
            }
            Instruction::Skp { k } => {
                println!("Skipping if key {:x} is pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => self.pc += 2,
                    _ => {}
                }
            }
            Instruction::Sknp { k } => {
                println!("Skipping if key {:x} is not pressed", k);
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) if x == k => {}
                    _ => self.pc += 2,
                }
            }
            Instruction::Key { vr } => {
                println!("Waiting for a key to be pressed");
                let key = peripherals.keypad.get_current_key_input();
                match key {
                    Some(x) => {
                        println!(" ... Got {:x}", x);
                        self.reg_v[vr] = x
                    }
                    _ => {
                        println!(" ... Waiting more");
                        self.pc -= 2; // Emulate a SLEEP
                    }
                }

            }
            Instruction::Adi { vr } => {
                self.reg_i += self.reg_v[vr] as u16;
            }
            Instruction::Font { vr } => {
                let character = self.reg_v[vr] as usize;
                self.reg_i = (FONT_BASE_ADDR + (character * FONT_SIZE)) as u16;
                println!("Font draw for character: {:x}", character);
            }
            Instruction::Bcd { vr } => {
                let value = self.reg_v[vr];
                let i = self.reg_i as usize;
                self.mem[i] = value / 100;
                self.mem[i + 1] = (value / 10) % 10;
                self.mem[i + 2] = value % 10;
            }
            Instruction::Str { vr } => {
                for idx in 0..(vr + 1) {
                    let target_pos = self.reg_i as usize + idx;
                    let data = self.reg_v[idx];
                    self.memory_write(target_pos, data);
                }
            }
            Instruction::Ldr { vr } => {
                for idx in 0..(vr + 1) {
                    self.reg_v[idx] = self.memory_read(self.reg_i as usize + idx)
                }
            }
            Instruction::Gdelay { vr } => {
                let amount = self.reg_delay_timer();
                self.reg_v[vr] = amount;
            }
            Instruction::Sdelay { vr } => {
                let amount = self.reg_v[vr];
                self.reg_delay_timer.store((amount + 1) as _, Ordering::SeqCst);
                let timer_clone = self.reg_delay_timer.clone();
                thread::spawn(move || loop {
                    let ticks_left = timer_clone.fetch_sub(1, Ordering::SeqCst) - 1;
                    if ticks_left > 0 {
                        println!("Still {} ticks left", ticks_left);
                        thread::sleep(time::Duration::from_millis(1000 / 60));
                    } else {
                        break;
                    }
                });
            }
        }
        self.pc += 2;
    }

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

    pub fn mem(&self) -> &Vec<u8> {
        &self.mem
    }

    pub fn reg_v(&self) -> &Vec<u8> {
        &self.reg_v
    }

    pub fn reg_i(&self) -> u16 {
        self.reg_i
    }

    pub fn reg_delay_timer(&self) -> u8 {
        self.reg_delay_timer.load(Ordering::SeqCst) as _
    }

    pub fn reg_sound_timer(&self) -> u8 {
        self.reg_sound_timer
    }

    pub fn stack(&self) -> &Vec<usize> {
        &self.stack
    }

    pub fn sp(&self) -> usize {
        self.sp
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::processor::*;
use sys::process::*;
use sys::Disk;
use sys::disk;
use ::{DiskExt, ProcessExt, SystemExt};
use std::fs::{File, read_link};
use std::io::{self, Read};
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{pid_t, uid_t, sysconf, _SC_CLK_TCK, _SC_PAGESIZE};
use utils::realpath;

/// Structs containing system's information.
pub struct System {
    process_list: Process,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
}

impl System {
    fn clear_procs(&mut self) {
        if !self.processors.is_empty() {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (new - old) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in &mut self.process_list.tasks {
                if !has_been_updated(proc_) {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.tasks.remove(&pid);
            }
        }
    }

    /// **WARNING**: This method is specific to Linux.
    ///
    /// Refresh *only* the process corresponding to `pid`.
    pub fn refresh_process(&mut self, pid: pid_t) -> bool {
        if let Some(proc_) = self.process_list.tasks.get_mut(&pid) {
            _get_process_data(Path::new(&format!("/proc/{}", pid)), proc_, self.page_size_kb, pid);
            true
        } else {
            false
        }
    }
}

impl SystemExt for System {
    fn new() -> System {
        let mut s = System {
            process_list: Process::new(0, None, 0),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: component::get_components(),
            disks: get_all_disks(),
        };
        s.refresh_all();
        s
    }

    fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();

        for component in &mut self.temperatures {
            component.update();
        }
        for line in &lines {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.is_empty();
        for line in &lines {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| !s.is_empty());
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(&mut self.processors[i],
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    fn refresh_processes(&mut self) {
        if refresh_procs(&mut self.process_list, "/proc", self.page_size_kb, 0) {
            self.clear_procs();
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = get_all_disks();
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    fn get_process_list(&self) -> &HashMap<pid_t, Process> {
        &self.process_list.tasks
    }

    fn get_process(&self, pid: pid_t) -> Option<&Process> {
        self.process_list.tasks.get(&pid)
    }

    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.tasks.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }
}

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

pub fn get_all_data(file_path: &str) -> io::Result<String> {
    let mut file = File::open(file_path)?;
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    Ok(data)
}

fn refresh_procs<P: AsRef<Path>>(proc_list: &mut Process, path: P, page_size_kb: u64,
                                 pid: pid_t) -> bool {
    if let Ok(d) = fs::read_dir(&Path::new(path.as_ref())) {
        for entry in d {
            if !entry.is_ok() {
                continue;
            }
            let entry = entry.unwrap();
            let entry = entry.path();

            if entry.is_dir() {
                _get_process_data(entry.as_path(), proc_list, page_size_kb, pid);
            }
        }
        true
    } else {
        false
    }
}

fn update_time_and_memory(path: &Path, entry: &mut Process, parts: &[&str], page_size_kb: u64,
                          parent_memory: u64, pid: pid_t) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss then we add the vsize
    {
        entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb +
                       u64::from_str(parts[22]).unwrap() / 1024;
        if entry.memory >= parent_memory {
            entry.memory -= parent_memory;
        }
        set_time(entry,
                 u64::from_str(parts[13]).unwrap(),
                 u64::from_str(parts[14]).unwrap());
    }
    refresh_procs(entry, path.join(Path::new("task")).as_path(), page_size_kb, pid);
}

fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64, pid: pid_t) {
    if !path.exists() || !path.is_dir() {
        return
    }
    let last = path.to_str().unwrap().split('/').last();
    if last.is_none() {
        return
    }
    if let Ok(nb) = pid_t::from_str(last.unwrap()) {
        if nb == pid {
            return
        }
        let mut tmp = PathBuf::from(path);

        tmp.push("stat");
        let data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // The stat file is "interesting" to parse, because spaces cannot
        // be used as delimiters. The second field stores the command name
        // sourrounded by parentheses. Unfortunately, whitespace and
        // parentheses are legal parts of the command, so parsing has to
        // proceed like this: The first field is delimited by the first
        // whitespace, the second field is everything until the last ')'
        // in the entire string. All other fields are delimited by
        // whitespace.

        let mut parts = Vec::new();
        let mut data_it = data.splitn(2, ' ');
        parts.push(data_it.next().unwrap());
        // The following loses the ) from the input, but that's ok because
        // we're not using it anyway.
        let mut data_it = data_it.next().unwrap().rsplitn(2, ')');
        let data = data_it.next().unwrap();
        parts.push(data_it.next().unwrap());
        parts.extend(data.split_whitespace());
        let parent_memory = proc_list.memory;
        if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) {
            update_time_and_memory(path, entry, &parts, page_size_kb, parent_memory, nb);
            return;
        }

        let parent_pid = if proc_list.pid != 0 {
            Some(proc_list.pid)
        } else {
            match pid_t::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p),
            }
        };

        let mut p = Process::new(nb,
                                 parent_pid,
                                 u64::from_str(parts[21]).unwrap() /
                                 unsafe { sysconf(_SC_CLK_TCK) } as u64);

        p.status = parts[2].chars().next().and_then(|c| Some(ProcessStatus::from(c)));

        tmp = PathBuf::from(path);
        tmp.push("status");
        let status_data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // We're only interested in the lines starting with Uid: and Gid:
        // here. From these lines, we're looking at the second entry to get
        // the effective u/gid.

        let f = |h: &str, n: &str| -> Option<uid_t> {
            if h.starts_with(n) {
                h.split_whitespace().nth(2).unwrap().parse().ok()
            } else {
                None
            }
        };
        let mut set_uid = false;
        let mut set_gid = false;
        for line in status_data.lines() {
            if let Some(u) = f(line, "Uid:") {
                assert!(!set_uid);
                set_uid = true;
                p.uid = u;
            }
            if let Some(g) = f(line, "Gid:") {
                assert!(!set_gid);
                set_gid = true;
                p.gid = g;
            }
        }
        assert!(set_uid && set_gid);

        if proc_list.pid != 0 {
            p.cmd = proc_list.cmd.clone();
            p.name = proc_list.name.clone();
            p.environ = proc_list.environ.clone();
            p.exe = proc_list.exe.clone();
            p.cwd = proc_list.cwd.clone();
            p.root = proc_list.root.clone();
        } else {
            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = copy_from_file(&tmp);
            p.name = p.cmd[0].split('/').last().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
        }

        update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb);
        proc_list.tasks.insert(nb, p);
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            d.split('\0').map(|x| x.to_owned()).collect()
        },
        Err(_) => Vec::new()
    }
}

fn get_all_disks() -> Vec<Disk> {
    #[allow(or_fun_call)]
    let content = get_all_data("/proc/mounts").unwrap_or(String::new());
    let disks: Vec<_> = content.lines()
                               .filter(|line| line.trim_left()
                                                  .starts_with("/dev/sda"))
                               .collect();
    let mut ret = Vec::with_capacity(disks.len());

    if disks.len() == 1 {
        let info: Vec<_> = disks[0].split(' ').collect();
        if info.len() < 3 {
            return ret;
        }
        ret.push(disk::new_disk("sda", info[1], info[2]));
    } else {
        for line in disks {
            let info: Vec<_> = line.split(' ').collect();
            if info.len() < 3 {
                continue
            }
            ret.push(disk::new_disk(&info[0][5..], info[1], info[2]));
        }
    }
    ret
}
<commit_msg>Use RSS for Process::memory on Linux<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::processor::*;
use sys::process::*;
use sys::Disk;
use sys::disk;
use ::{DiskExt, ProcessExt, SystemExt};
use std::fs::{File, read_link};
use std::io::{self, Read};
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{pid_t, uid_t, sysconf, _SC_CLK_TCK, _SC_PAGESIZE};
use utils::realpath;

/// Structs containing system's information.
pub struct System {
    process_list: Process,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
}

impl System {
    fn clear_procs(&mut self) {
        if !self.processors.is_empty() {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (new - old) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in &mut self.process_list.tasks {
                if !has_been_updated(proc_) {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.tasks.remove(&pid);
            }
        }
    }

    /// **WARNING**: This method is specific to Linux.
    ///
    /// Refresh *only* the process corresponding to `pid`.
    pub fn refresh_process(&mut self, pid: pid_t) -> bool {
        if let Some(proc_) = self.process_list.tasks.get_mut(&pid) {
            _get_process_data(Path::new(&format!("/proc/{}", pid)), proc_, self.page_size_kb, pid);
            true
        } else {
            false
        }
    }
}

impl SystemExt for System {
    fn new() -> System {
        let mut s = System {
            process_list: Process::new(0, None, 0),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: component::get_components(),
            disks: get_all_disks(),
        };
        s.refresh_all();
        s
    }

    fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();

        for component in &mut self.temperatures {
            component.update();
        }
        for line in &lines {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.is_empty();
        for line in &lines {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| !s.is_empty());
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(&mut self.processors[i],
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    fn refresh_processes(&mut self) {
        if refresh_procs(&mut self.process_list, "/proc", self.page_size_kb, 0) {
            self.clear_procs();
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = get_all_disks();
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    fn get_process_list(&self) -> &HashMap<pid_t, Process> {
        &self.process_list.tasks
    }

    fn get_process(&self, pid: pid_t) -> Option<&Process> {
        self.process_list.tasks.get(&pid)
    }

    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.tasks.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }
}

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

pub fn get_all_data(file_path: &str) -> io::Result<String> {
    let mut file = File::open(file_path)?;
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    Ok(data)
}

fn refresh_procs<P: AsRef<Path>>(proc_list: &mut Process, path: P, page_size_kb: u64,
                                 pid: pid_t) -> bool {
    if let Ok(d) = fs::read_dir(&Path::new(path.as_ref())) {
        for entry in d {
            if !entry.is_ok() {
                continue;
            }
            let entry = entry.unwrap();
            let entry = entry.path();

            if entry.is_dir() {
                _get_process_data(entry.as_path(), proc_list, page_size_kb, pid);
            }
        }
        true
    } else {
        false
    }
}

fn update_time_and_memory(path: &Path, entry: &mut Process, parts: &[&str], page_size_kb: u64,
                          parent_memory: u64, pid: pid_t) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss
    {
        entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb;
        if entry.memory >= parent_memory {
            entry.memory -= parent_memory;
        }
        set_time(entry,
                 u64::from_str(parts[13]).unwrap(),
                 u64::from_str(parts[14]).unwrap());
    }
    refresh_procs(entry, path.join(Path::new("task")).as_path(), page_size_kb, pid);
}

fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64, pid: pid_t) {
    if !path.exists() || !path.is_dir() {
        return
    }
    let last = path.to_str().unwrap().split('/').last();
    if last.is_none() {
        return
    }
    if let Ok(nb) = pid_t::from_str(last.unwrap()) {
        if nb == pid {
            return
        }
        let mut tmp = PathBuf::from(path);

        tmp.push("stat");
        let data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // The stat file is "interesting" to parse, because spaces cannot
        // be used as delimiters. The second field stores the command name
        // sourrounded by parentheses. Unfortunately, whitespace and
        // parentheses are legal parts of the command, so parsing has to
        // proceed like this: The first field is delimited by the first
        // whitespace, the second field is everything until the last ')'
        // in the entire string. All other fields are delimited by
        // whitespace.

        let mut parts = Vec::new();
        let mut data_it = data.splitn(2, ' ');
        parts.push(data_it.next().unwrap());
        // The following loses the ) from the input, but that's ok because
        // we're not using it anyway.
        let mut data_it = data_it.next().unwrap().rsplitn(2, ')');
        let data = data_it.next().unwrap();
        parts.push(data_it.next().unwrap());
        parts.extend(data.split_whitespace());
        let parent_memory = proc_list.memory;
        if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) {
            update_time_and_memory(path, entry, &parts, page_size_kb, parent_memory, nb);
            return;
        }

        let parent_pid = if proc_list.pid != 0 {
            Some(proc_list.pid)
        } else {
            match pid_t::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p),
            }
        };

        let mut p = Process::new(nb,
                                 parent_pid,
                                 u64::from_str(parts[21]).unwrap() /
                                 unsafe { sysconf(_SC_CLK_TCK) } as u64);

        p.status = parts[2].chars().next().and_then(|c| Some(ProcessStatus::from(c)));

        tmp = PathBuf::from(path);
        tmp.push("status");
        let status_data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // We're only interested in the lines starting with Uid: and Gid:
        // here. From these lines, we're looking at the second entry to get
        // the effective u/gid.

        let f = |h: &str, n: &str| -> Option<uid_t> {
            if h.starts_with(n) {
                h.split_whitespace().nth(2).unwrap().parse().ok()
            } else {
                None
            }
        };
        let mut set_uid = false;
        let mut set_gid = false;
        for line in status_data.lines() {
            if let Some(u) = f(line, "Uid:") {
                assert!(!set_uid);
                set_uid = true;
                p.uid = u;
            }
            if let Some(g) = f(line, "Gid:") {
                assert!(!set_gid);
                set_gid = true;
                p.gid = g;
            }
        }
        assert!(set_uid && set_gid);

        if proc_list.pid != 0 {
            p.cmd = proc_list.cmd.clone();
            p.name = proc_list.name.clone();
            p.environ = proc_list.environ.clone();
            p.exe = proc_list.exe.clone();
            p.cwd = proc_list.cwd.clone();
            p.root = proc_list.root.clone();
        } else {
            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = copy_from_file(&tmp);
            p.name = p.cmd[0].split('/').last().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
        }

        update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb);
        proc_list.tasks.insert(nb, p);
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            d.split('\0').map(|x| x.to_owned()).collect()
        },
        Err(_) => Vec::new()
    }
}

fn get_all_disks() -> Vec<Disk> {
    #[allow(or_fun_call)]
    let content = get_all_data("/proc/mounts").unwrap_or(String::new());
    let disks: Vec<_> = content.lines()
                               .filter(|line| line.trim_left()
                                                  .starts_with("/dev/sda"))
                               .collect();
    let mut ret = Vec::with_capacity(disks.len());

    if disks.len() == 1 {
        let info: Vec<_> = disks[0].split(' ').collect();
        if info.len() < 3 {
            return ret;
        }
        ret.push(disk::new_disk("sda", info[1], info[2]));
    } else {
        for line in disks {
            let info: Vec<_> = line.split(' ').collect();
            if info.len() < 3 {
                continue
            }
            ret.push(disk::new_disk(&info[0][5..], info[1], info[2]));
        }
    }
    ret
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// 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;
use std::fmt::{self, Display};
use std::iter::FromIterator;

use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};

use buffer::Cursor;
use thread::ThreadBound;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Debug)]
pub struct Error {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test where Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: struct.ParseBuffer.html#method.error
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate syn;
    ///
    /// use syn::{Ident, LitStr};
    /// use syn::parse::{Error, ParseStream, Result};
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// #
    /// # fn main() {}
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            span: ThreadBound::new(span),
            message: message.to_string(),
        }
    }

    pub fn span(&self) -> Span {
        match self.span.get() {
            Some(span) => *span,
            None => Span::call_site(),
        }
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
    /// [`parse_macro_input!`]: ../macro.parse_macro_input.html
    pub fn to_compile_error(&self) -> TokenStream {
        let span = self.span();

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", span)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(span);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(span);
                        string
                    })])
                });
                group.set_span(span);
                group
            }),
        ])
    }
}

pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        Error::new(cursor.span(), message)
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        Error {
            span: ThreadBound::new(self.span()),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        "parse error"
    }
}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}
<commit_msg>Document thread behavior of error spans<commit_after>// Copyright 2018 Syn Developers
//
// 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;
use std::fmt::{self, Display};
use std::iter::FromIterator;

use proc_macro2::{
    Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};

use buffer::Cursor;
use thread::ThreadBound;

/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;

/// Error returned when a Syn parser cannot parse the input tokens.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Debug)]
pub struct Error {
    // Span is implemented as an index into a thread-local interner to keep the
    // size small. It is not safe to access from a different thread. We want
    // errors to be Send and Sync to play nicely with the Failure crate, so pin
    // the span we're given to its original thread and assume it is
    // Span::call_site if accessed from any other thread.
    span: ThreadBound<Span>,
    message: String,
}

#[cfg(test)]
struct _Test where Error: Send + Sync;

impl Error {
    /// Usually the [`ParseStream::error`] method will be used instead, which
    /// automatically uses the correct span from the current position of the
    /// parse stream.
    ///
    /// Use `Error::new` when the error needs to be triggered on some span other
    /// than where the parse stream is currently positioned.
    ///
    /// [`ParseStream::error`]: struct.ParseBuffer.html#method.error
    ///
    /// # Example
    ///
    /// ```
    /// #[macro_use]
    /// extern crate syn;
    ///
    /// use syn::{Ident, LitStr};
    /// use syn::parse::{Error, ParseStream, Result};
    ///
    /// // Parses input that looks like `name = "string"` where the key must be
    /// // the identifier `name` and the value may be any string literal.
    /// // Returns the string literal.
    /// fn parse_name(input: ParseStream) -> Result<LitStr> {
    ///     let name_token: Ident = input.parse()?;
    ///     if name_token != "name" {
    ///         // Trigger an error not on the current position of the stream,
    ///         // but on the position of the unexpected identifier.
    ///         return Err(Error::new(name_token.span(), "expected `name`"));
    ///     }
    ///     input.parse::<Token![=]>()?;
    ///     let s: LitStr = input.parse()?;
    ///     Ok(s)
    /// }
    /// #
    /// # fn main() {}
    /// ```
    pub fn new<T: Display>(span: Span, message: T) -> Self {
        Error {
            span: ThreadBound::new(span),
            message: message.to_string(),
        }
    }

    /// The source location of the error.
    ///
    /// Spans are not thread-safe so this function returns `Span::call_site()`
    /// if called from a different thread than the one on which the `Error` was
    /// originally created.
    pub fn span(&self) -> Span {
        match self.span.get() {
            Some(span) => *span,
            None => Span::call_site(),
        }
    }

    /// Render the error as an invocation of [`compile_error!`].
    ///
    /// The [`parse_macro_input!`] macro provides a convenient way to invoke
    /// this method correctly in a procedural macro.
    ///
    /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
    /// [`parse_macro_input!`]: ../macro.parse_macro_input.html
    pub fn to_compile_error(&self) -> TokenStream {
        let span = self.span();

        // compile_error!($message)
        TokenStream::from_iter(vec![
            TokenTree::Ident(Ident::new("compile_error", span)),
            TokenTree::Punct({
                let mut punct = Punct::new('!', Spacing::Alone);
                punct.set_span(span);
                punct
            }),
            TokenTree::Group({
                let mut group = Group::new(Delimiter::Brace, {
                    TokenStream::from_iter(vec![TokenTree::Literal({
                        let mut string = Literal::string(&self.message);
                        string.set_span(span);
                        string
                    })])
                });
                group.set_span(span);
                group
            }),
        ])
    }
}

pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
    if cursor.eof() {
        Error::new(scope, format!("unexpected end of input, {}", message))
    } else {
        Error::new(cursor.span(), message)
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&self.message)
    }
}

impl Clone for Error {
    fn clone(&self) -> Self {
        Error {
            span: ThreadBound::new(self.span()),
            message: self.message.clone(),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        "parse error"
    }
}

impl From<LexError> for Error {
    fn from(err: LexError) -> Self {
        Error::new(Span::call_site(), format!("{:?}", err))
    }
}
<|endoftext|>