<commit_before>use super::ConcurrentDevice;

extern crate memmap;
use z80e_core_rust::{ IoDevice };
use self::memmap::{ Mmap };
pub use self::memmap::{ MmapView, Protection };

use std::sync::{ Arc, Condvar, Mutex };
use std::sync::atomic::{ AtomicBool, AtomicUsize, Ordering };
use std::io::{ self, ErrorKind, Write };
use std::path::Path;
use std::{ str, mem, ptr };

// Sector size must be a power of two
const SECTOR_SIZE: u16 = 128;

// Max disk must be a power of two <= 16. If changed, you must insert/delete Nones in DiskController::run()
const MAX_DISK: u8 = 16;

// Status port bitflags.
//     8-bit values, but "must" be usize to avoid overly-verbose casts for AtomicUsize calls.
const COMMAND_READY: usize = 1 << 0;
const DATA_READY: usize = 1 << 1;
const ERROR: usize = 1 << 7;

// Commands.
const NOP: u8 = 0;
const SEL_DSK: u8 = 1;
const SEL_TRK: u8 = 2;
const SEL_SEC: u8 = 3;
const READ: u8 = 4;
const WRITE: u8 = 5;
const RESET: u8 = 6;
const OPEN: u8 = 7;
const CLOSE: u8 = 8;
const DPB: u8 = 9;

#[derive(Clone)]
pub struct DiskController {
    pub status: Arc<AtomicUsize>,
    command_cond: Arc<Condvar>,
    buffer: Arc<Mutex<Buffer>>,
    parameters: Arc<Mutex<Parameters>>,
}

impl DiskController {
    pub fn new() -> DiskController {
        DiskController {
            status: Arc::new(AtomicUsize::new(DATA_READY)),
            command_cond: Arc::new(Condvar::new()),
            buffer: Arc::new(Mutex::new(Buffer::new())),
            parameters: Arc::new(Mutex::new(Parameters::new())),
        }
    }
    pub fn status_port(&self) -> StatusPort {
        StatusPort::new(self.clone())
    }
    pub fn data_port(&self) -> DataPort {
        DataPort::new(self.clone())
    }
}

struct Buffer {
    bytes: [u8; SECTOR_SIZE as usize],
    i: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer {
            bytes: [0; SECTOR_SIZE as usize],
            i: 0,
        }
    }
}

struct Parameters {
    disk: u8,
    track: u16,
    sector: u16,
    command: u8,
    do_command: bool,
}

impl Parameters {
    fn new() -> Parameters {
        Parameters {
            disk: 0,
            track: 0,
            sector: 0,
            command: NOP,
            do_command: false,
        }
    }
}

struct StatusPort {
    controller: DiskController,
}

impl StatusPort {
    fn new(controller: DiskController) -> StatusPort {
        StatusPort {
            controller: controller,
        }
    }
}

impl IoDevice for StatusPort {
    fn read_in(&self) -> u8 {
        (self.controller.status.load(Ordering::SeqCst) & 0xff) as u8
    }
    fn write_out(&mut self, value: u8) {
        if (self.controller.status.fetch_and(!COMMAND_READY, Ordering::SeqCst) & COMMAND_READY) != 0 {
            let mut params = self.controller.parameters.lock().unwrap();
            params.command = value;
            params.do_command = true;
            self.controller.command_cond.notify_one();
        } else {
            self.controller.status.fetch_or(COMMAND_READY | ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to write command register when not ready.");
        }
    }
}

struct DataPort {
    controller: DiskController,
}

impl DataPort {
    fn new(controller: DiskController) -> DataPort {
        DataPort {
            controller: controller,
        }
    }
}

impl IoDevice for DataPort {
    fn read_in (&self) -> u8 {
        if (self.controller.status.fetch_and(!DATA_READY, Ordering::SeqCst) & DATA_READY) != 0 {
            let byte;
            {
                let mut buffer = self.controller.buffer.lock().unwrap();
                buffer.i = ((buffer.i as usize + 1) & (SECTOR_SIZE - 1) as usize) as u16;
                byte = buffer.bytes[buffer.i as usize];
            }
            self.controller.status.fetch_or(DATA_READY, Ordering::SeqCst);
            byte
        } else {
            self.controller.status.fetch_or(ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to read data register when not ready.");
            0
        }
    }
    fn write_out(&mut self, value: u8) {
        if (self.controller.status.fetch_and(!DATA_READY, Ordering::SeqCst) & DATA_READY) != 0 {
            {
                let mut buffer = self.controller.buffer.lock().unwrap();
                buffer.bytes[buffer.i as usize] = value;
                buffer.i = ((buffer.i as usize + 1) & (SECTOR_SIZE - 1) as usize) as u16;
            }
            self.controller.status.fetch_or(DATA_READY, Ordering::SeqCst);
        } else {
            self.controller.status.fetch_or(ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to write data register when not ready.");
        }
    }
}

pub struct Disk {
    view: MmapView,
    pub tracks: u16,
    pub spt: u16,
    dpb: [u8; 16],
}

impl Disk {
    pub fn open<T: AsRef<Path>>(path: &T, protection: Protection) -> io::Result<Disk> {
        let mut file = try!(Mmap::open_path(path, protection)).into_view();
        let (header, image) = try!(file.split_at(128));
        let header = unsafe { header.as_slice() };
        if match str::from_utf8(&header[0..10]) {
            Ok(x) => x,
            Err(err) => return Err(io::Error::new(ErrorKind::InvalidData, "Invalid image header encoding.")),
        }!= "<CPM_Disk>" {
            return Err(io::Error::new(ErrorKind::InvalidData, "Not a valid disk image."));
        }
        let mut dpb: [u8; 16] = [0; 16];
        for i in 0..16 {
            dpb[i] = header[32 + i];
        }
        let spt: u16 = (dpb[0] as u16) | ((dpb[1] as u16) << 8);
        let bsh: u16 = (dpb[2] as u16);
        let dsm: u16 = (dpb[5] as u16) | ((dpb[6] as u16) << 8);
        let off: u16 = (dpb[13] as u16) | ((dpb[14] as u16) << 8);
        let tracks: u16 = (dsm + 1) * (1 << bsh) / spt + off;
        Ok(Disk {
            view: image,
            tracks: tracks,
            spt: spt,
            dpb: dpb
        })
    }
}

impl ConcurrentDevice for DiskController {
    fn run(&mut self, die: Arc<AtomicBool>) {
        let mut disks = unsafe {
            let mut disks: [Option<Disk>; MAX_DISK as usize] = mem::uninitialized();
            for disk in disks.iter_mut() {
                ptr::write(disk, None);
            };
            disks
        };
        let mut parameters = self.parameters.lock().unwrap();
        loop {
            self.status.fetch_or(COMMAND_READY, Ordering::SeqCst);
            while !(*parameters).do_command {
                parameters = self.command_cond.wait(parameters).unwrap();
            }
            if die.load(Ordering::Acquire) { break; }
            let status = self.status.fetch_and(!DATA_READY, Ordering::SeqCst);
            if (status & ERROR) != 0 && parameters.command != RESET {
                self.status.fetch_or(DATA_READY, Ordering::SeqCst);
                continue;
            };
            {
                let mut buffer = self.buffer.lock().unwrap();
                buffer.i = 0;
                match parameters.command {
                    NOP => (),
                    SEL_DSK => {
                        if buffer.bytes[0] < MAX_DISK {
                            parameters.disk = buffer.bytes[0];
                        } else {
                            self.status.fetch_or(ERROR, Ordering::SeqCst);
                        }
                    },
                    SEL_TRK => {
                        let track = buffer.bytes[0] as u16 | ((buffer.bytes[1] as u16) << 8);
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                if track < disk.tracks {
                                    parameters.track = track;
                                } else {
                                    self.status.fetch_or(ERROR, Ordering::SeqCst);
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    SEL_SEC => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                let sector = buffer.bytes[0] as u16 | ((buffer.bytes[1] as u16) << 8);
                                if sector < disk.spt {
                                    parameters.sector = sector;
                                } else {
                                    self.status.fetch_or(ERROR, Ordering::SeqCst);
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }
                    },
                    READ => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                let off = ((parameters.track as usize * disk.spt as usize)
                                           + parameters.sector as usize) * SECTOR_SIZE as usize;
                                let bytes = unsafe { disk.view.as_slice() };
                                for (i, byte) in buffer.bytes.iter_mut().enumerate() {
                                    *byte = bytes[off + i];
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }
                    },
                    WRITE => {
                        match disks[parameters.disk as usize] {
                            Some(ref mut disk) => {
                                let off = ((parameters.track as usize * disk.spt as usize)
                                           + parameters.sector as usize) * SECTOR_SIZE as usize;
                                let bytes = unsafe { disk.view.as_mut_slice() };
                                for (i, byte) in buffer.bytes.iter().enumerate() {
                                    bytes[i] = *byte;
                                };
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }

                    }
                    RESET => {
                        parameters.disk = 0;
                        parameters.track = 0;
                        parameters.sector = 0;
                        parameters.command = NOP;
                        self.status.fetch_and(!ERROR, Ordering::SeqCst);
                    },
                    OPEN => {
                        match str::from_utf8(buffer.bytes.split(|a| *a == 0).next().unwrap()) {
                            Ok(file_name) => {
                                match Disk::open(&file_name, Protection::ReadWrite) {
                                    Ok(disk) => {
                                        disks[parameters.disk as usize] = Some(disk);
                                    },
                                    Err(err) => {
                                        let mut stderr = io::stderr();
                                        let _ = writeln!(stderr, "disk: Failed to open file: {}", file_name);
                                        let _ = writeln!(stderr, "Error:\n\t{}", err);
                                        self.status.fetch_or(ERROR, Ordering::SeqCst);
                                    },
                                }
                            },
                            Err(err) => {
                                let _ = write!(io::stderr(), "disk: Bad UTF-8 in file name.\nError:\n\t{}\n", err);
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    CLOSE => {
                        disks[parameters.disk as usize] = None;
                    },
                    DPB => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                for (a, b) in disk.dpb.iter().zip(buffer.bytes.iter_mut()) {
                                    *b = *a;
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    _ => {
                        self.status.fetch_or(ERROR, Ordering::SeqCst);
                        let _ = write!(io::stderr(), "disk: System sent bad command: {:02X}\n", parameters.command);
                    },
                }
            }
            self.status.fetch_or(DATA_READY, Ordering::SeqCst);
            parameters.do_command = false;
        }
    }
}
<commit_msg>HOW RACEY.<commit_after>use super::ConcurrentDevice;

extern crate memmap;
use z80e_core_rust::{ IoDevice };
use self::memmap::{ Mmap };
pub use self::memmap::{ MmapView, Protection };

use std::sync::{ Arc, Condvar, Mutex };
use std::sync::atomic::{ AtomicBool, AtomicUsize, Ordering };
use std::io::{ self, ErrorKind, Write };
use std::path::Path;
use std::{ str, mem, ptr };

// Sector size must be a power of two
const SECTOR_SIZE: u16 = 128;

// Max disk must be a power of two <= 16. If changed, you must insert/delete Nones in DiskController::run()
const MAX_DISK: u8 = 16;

// Status port bitflags.
//     8-bit values, but "must" be usize to avoid overly-verbose casts for AtomicUsize calls.
const COMMAND_READY: usize = 1 << 0;
const DATA_READY: usize = 1 << 1;
const ERROR: usize = 1 << 7;

// Commands.
const NOP: u8 = 0;
const SEL_DSK: u8 = 1;
const SEL_TRK: u8 = 2;
const SEL_SEC: u8 = 3;
const READ: u8 = 4;
const WRITE: u8 = 5;
const RESET: u8 = 6;
const OPEN: u8 = 7;
const CLOSE: u8 = 8;
const DPB: u8 = 9;

#[derive(Clone)]
pub struct DiskController {
    pub status: Arc<AtomicUsize>,
    command_cond: Arc<Condvar>,
    buffer: Arc<Mutex<Buffer>>,
    parameters: Arc<Mutex<Parameters>>,
}

impl DiskController {
    pub fn new() -> DiskController {
        DiskController {
            status: Arc::new(AtomicUsize::new(DATA_READY)),
            command_cond: Arc::new(Condvar::new()),
            buffer: Arc::new(Mutex::new(Buffer::new())),
            parameters: Arc::new(Mutex::new(Parameters::new())),
        }
    }
    pub fn status_port(&self) -> StatusPort {
        StatusPort::new(self.clone())
    }
    pub fn data_port(&self) -> DataPort {
        DataPort::new(self.clone())
    }
}

struct Buffer {
    bytes: [u8; SECTOR_SIZE as usize],
    i: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer {
            bytes: [0; SECTOR_SIZE as usize],
            i: 0,
        }
    }
}

struct Parameters {
    disk: u8,
    track: u16,
    sector: u16,
    command: u8,
    do_command: bool,
}

impl Parameters {
    fn new() -> Parameters {
        Parameters {
            disk: 0,
            track: 0,
            sector: 0,
            command: NOP,
            do_command: false,
        }
    }
}

struct StatusPort {
    controller: DiskController,
}

impl StatusPort {
    fn new(controller: DiskController) -> StatusPort {
        StatusPort {
            controller: controller,
        }
    }
}

impl IoDevice for StatusPort {
    fn read_in(&self) -> u8 {
        (self.controller.status.load(Ordering::SeqCst) & 0xff) as u8
    }
    fn write_out(&mut self, value: u8) {
        if (self.controller.status.fetch_and(!COMMAND_READY, Ordering::SeqCst) & COMMAND_READY) != 0 {
            let mut params = self.controller.parameters.lock().unwrap();
            params.command = value;
            params.do_command = true;
            self.controller.command_cond.notify_one();
        } else {
            self.controller.status.fetch_or(COMMAND_READY | ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to write command register when not ready.");
        }
    }
}

struct DataPort {
    controller: DiskController,
}

impl DataPort {
    fn new(controller: DiskController) -> DataPort {
        DataPort {
            controller: controller,
        }
    }
}

impl IoDevice for DataPort {
    fn read_in (&self) -> u8 {
        if (self.controller.status.fetch_and(!DATA_READY, Ordering::SeqCst) & DATA_READY) != 0 {
            let byte;
            {
                let mut buffer = self.controller.buffer.lock().unwrap();
                buffer.i = ((buffer.i as usize + 1) & (SECTOR_SIZE - 1) as usize) as u16;
                byte = buffer.bytes[buffer.i as usize];
            }
            self.controller.status.fetch_or(DATA_READY, Ordering::SeqCst);
            byte
        } else {
            self.controller.status.fetch_or(ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to read data register when not ready.");
            0
        }
    }
    fn write_out(&mut self, value: u8) {
        if (self.controller.status.fetch_and(!DATA_READY, Ordering::SeqCst) & DATA_READY) != 0 {
            {
                let mut buffer = self.controller.buffer.lock().unwrap();
                buffer.bytes[buffer.i as usize] = value;
                buffer.i = ((buffer.i as usize + 1) & (SECTOR_SIZE - 1) as usize) as u16;
            }
            self.controller.status.fetch_or(DATA_READY, Ordering::SeqCst);
        } else {
            self.controller.status.fetch_or(ERROR, Ordering::SeqCst);
            let _ = writeln!(io::stderr(), "disk: Attempted to write data register when not ready.");
        }
    }
}

pub struct Disk {
    view: MmapView,
    pub tracks: u16,
    pub spt: u16,
    dpb: [u8; 16],
}

impl Disk {
    pub fn open<T: AsRef<Path>>(path: &T, protection: Protection) -> io::Result<Disk> {
        let mut file = try!(Mmap::open_path(path, protection)).into_view();
        let (header, image) = try!(file.split_at(128));
        let header = unsafe { header.as_slice() };
        if match str::from_utf8(&header[0..10]) {
            Ok(x) => x,
            Err(err) => return Err(io::Error::new(ErrorKind::InvalidData, "Invalid image header encoding.")),
        }!= "<CPM_Disk>" {
            return Err(io::Error::new(ErrorKind::InvalidData, "Not a valid disk image."));
        }
        let mut dpb: [u8; 16] = [0; 16];
        for i in 0..16 {
            dpb[i] = header[32 + i];
        }
        let spt: u16 = (dpb[0] as u16) | ((dpb[1] as u16) << 8);
        let bsh: u16 = (dpb[2] as u16);
        let dsm: u16 = (dpb[5] as u16) | ((dpb[6] as u16) << 8);
        let off: u16 = (dpb[13] as u16) | ((dpb[14] as u16) << 8);
        let tracks: u16 = (dsm + 1) * (1 << bsh) / spt + off;
        Ok(Disk {
            view: image,
            tracks: tracks,
            spt: spt,
            dpb: dpb
        })
    }
}

impl ConcurrentDevice for DiskController {
    fn run(&mut self, die: Arc<AtomicBool>) {
        let mut disks = unsafe {
            let mut disks: [Option<Disk>; MAX_DISK as usize] = mem::uninitialized();
            for disk in disks.iter_mut() {
                ptr::write(disk, None);
            };
            disks
        };
        let mut parameters = self.parameters.lock().unwrap();
        loop {
            self.status.fetch_or(COMMAND_READY, Ordering::SeqCst);
            while !(*parameters).do_command {
                parameters = self.command_cond.wait(parameters).unwrap();
            }
            if die.load(Ordering::Acquire) { break; }
            let status = self.status.fetch_and(!DATA_READY, Ordering::SeqCst);
            if (status & ERROR) != 0 && parameters.command != RESET {
                self.status.fetch_or(DATA_READY, Ordering::SeqCst);
                continue;
            };
            {
                let mut buffer = self.buffer.lock().unwrap();
                buffer.i = 0;
                match parameters.command {
                    NOP => (),
                    SEL_DSK => {
                        if buffer.bytes[0] < MAX_DISK {
                            parameters.disk = buffer.bytes[0];
                        } else {
                            self.status.fetch_or(ERROR, Ordering::SeqCst);
                        }
                    },
                    SEL_TRK => {
                        let track = buffer.bytes[0] as u16 | ((buffer.bytes[1] as u16) << 8);
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                if track < disk.tracks {
                                    parameters.track = track;
                                } else {
                                    self.status.fetch_or(ERROR, Ordering::SeqCst);
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    SEL_SEC => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                let sector = buffer.bytes[0] as u16 | ((buffer.bytes[1] as u16) << 8);
                                if sector < disk.spt {
                                    parameters.sector = sector;
                                } else {
                                    self.status.fetch_or(ERROR, Ordering::SeqCst);
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }
                    },
                    READ => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                let off = ((parameters.track as usize * disk.spt as usize)
                                           + parameters.sector as usize) * SECTOR_SIZE as usize;
                                let bytes = unsafe { disk.view.as_slice() };
                                for (i, byte) in buffer.bytes.iter_mut().enumerate() {
                                    *byte = bytes[off + i];
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }
                    },
                    WRITE => {
                        match disks[parameters.disk as usize] {
                            Some(ref mut disk) => {
                                let off = ((parameters.track as usize * disk.spt as usize)
                                           + parameters.sector as usize) * SECTOR_SIZE as usize;
                                let bytes = unsafe { disk.view.as_mut_slice() };
                                for (i, byte) in buffer.bytes.iter().enumerate() {
                                    bytes[i] = *byte;
                                };
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            },
                        }

                    }
                    RESET => {
                        parameters.disk = 0;
                        parameters.track = 0;
                        parameters.sector = 0;
                        parameters.command = NOP;
                        self.status.fetch_and(!ERROR, Ordering::SeqCst);
                    },
                    OPEN => {
                        match str::from_utf8(buffer.bytes.split(|a| *a == 0).next().unwrap()) {
                            Ok(file_name) => {
                                match Disk::open(&file_name, Protection::ReadWrite) {
                                    Ok(disk) => {
                                        disks[parameters.disk as usize] = Some(disk);
                                    },
                                    Err(err) => {
                                        let mut stderr = io::stderr();
                                        let _ = writeln!(stderr, "disk: Failed to open file: {}", file_name);
                                        let _ = writeln!(stderr, "Error:\n\t{}", err);
                                        self.status.fetch_or(ERROR, Ordering::SeqCst);
                                    },
                                }
                            },
                            Err(err) => {
                                let _ = write!(io::stderr(), "disk: Bad UTF-8 in file name.\nError:\n\t{}\n", err);
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    CLOSE => {
                        disks[parameters.disk as usize] = None;
                    },
                    DPB => {
                        match disks[parameters.disk as usize] {
                            Some(ref disk) => {
                                for (a, b) in disk.dpb.iter().zip(buffer.bytes.iter_mut()) {
                                    *b = *a;
                                }
                            },
                            None => {
                                self.status.fetch_or(ERROR, Ordering::SeqCst);
                            }
                        }
                    },
                    _ => {
                        self.status.fetch_or(ERROR, Ordering::SeqCst);
                        let _ = write!(io::stderr(), "disk: System sent bad command: {:02X}\n", parameters.command);
                    },
                }
            }
            parameters.do_command = false;
            self.status.fetch_or(DATA_READY, Ordering::SeqCst);
        }
    }
}
<|endoftext|>


<commit_before>
/// Single entry of the `Dtab`
#[derive(PartialEq, Eq, Debug)]
pub struct Dentry {
    pub key: String,
    pub val: String,
}

/// Delegate table.
#[derive(PartialEq, Eq, Debug)]
pub struct Dtab {
    pub entries: Vec<Dentry>,
}

impl Dentry {
    /// Create a new `Dentry` from the key-value pair.
    pub fn new(key: String, val: String) -> Dentry {
        Dentry {
            key: key,
            val: val,
        }
    }
}

impl Dtab {
    /// Create a new, empty `Dtab`.
    #[inline]
    pub fn new() -> Dtab {
        Dtab::from_entries(Vec::new())
    }

    /// Create a new `Dtab` containing the `Dentry`s.
    #[inline]
    pub fn from_entries(entries: Vec<Dentry>) -> Dtab {
        Dtab {
            entries: entries,
        }
    }

    /// Add an entry to this `Dtab`.
    #[inline]
    pub fn add_entry(&mut self, key: String, value: String) -> &Self {
        self.entries.push(Dentry::new(key, value));
        self
    }
}
<commit_msg>Add `Default` instance for `Dtab`.<commit_after>
/// Single entry of the `Dtab`
#[derive(PartialEq, Eq, Debug)]
pub struct Dentry {
    pub key: String,
    pub val: String,
}

/// Delegate table.
#[derive(PartialEq, Eq, Debug)]
pub struct Dtab {
    pub entries: Vec<Dentry>,
}

impl Dentry {
    /// Create a new `Dentry` from the key-value pair.
    pub fn new(key: String, val: String) -> Dentry {
        Dentry {
            key: key,
            val: val,
        }
    }
}

impl Dtab {
    /// Create a new, empty `Dtab`.
    #[inline]
    pub fn new() -> Dtab {
        Dtab::from_entries(Vec::new())
    }

    /// Create a new `Dtab` containing the `Dentry`s.
    #[inline]
    pub fn from_entries(entries: Vec<Dentry>) -> Dtab {
        Dtab {
            entries: entries,
        }
    }

    /// Add an entry to this `Dtab`.
    #[inline]
    pub fn add_entry(&mut self, key: String, value: String) -> &Self {
        self.entries.push(Dentry::new(key, value));
        self
    }
}

impl Default for Dtab {
    fn default() -> Dtab {
        Dtab::new()
    }
}
<|endoftext|>


<commit_before>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<commit_msg>Add some media-type (Content-Type header) tests.<commit_after>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

pub fn MediaType(type_: ~str, subtype: ~str, parameters: ~[(~str, ~str)]) -> MediaType {
    MediaType {
        type_: type_,
        subtype: subtype,
        parameters: parameters,
    }
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}

#[test]
fn test_content_type() {
    use headers::test_utils::*;
    assert_conversion_correct("type/subtype", MediaType("type", "subtype", ~[]));
    assert_conversion_correct("type/subtype;key=value",
            MediaType("type", "subtype", ~[(~"key", ~"value")]));
    assert_conversion_correct("type/subtype;key=value;q=0.1",
            MediaType("type", "subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));
    assert_interpretation_correct("type/subtype ; key = value ; q = 0.1",
            MediaType("type", "subtype", ~[(~"key", ~"value"), (~"q", ~"0.1")]));

    assert_invalid::<MediaType>("");
    assert_invalid::<MediaType>("/");
    assert_invalid::<MediaType>("type /subtype");
    assert_invalid::<MediaType>("type/ subtype");
    assert_invalid::<MediaType>("type/subtype,foo=bar");
    assert_invalid::<MediaType>("type/subtype;foo=bar,foo=bar");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use parse::Env;
use var::Var;
use source::Src;

pub trait Eval {
    fn eval (&self, path: Option<&[&str]>, lookup: &str) -> Option<Var>;

    fn eval_bare (&self, lookup: &str) -> Option<Var> {
        let mut lookups: Vec<&str> = lookup.split_terminator('.').collect();
        let lookup = lookups.pop().unwrap();

        let path;
        if lookups.len() > 0 { path = Some(&lookups[..]); }
        else { path = None }

        self.eval(path, lookup)
    }
}

pub struct Evaluator<'e, 'd, D:Eval + 'd> {
    data: &'d D,
    env: &'e mut Env,
    next_node: String,
    await_node: String,
}

impl<'e, 'd, D:Eval + 'd> Iterator for Evaluator<'e, 'd, D>
    where D: Eval + 'd {

    type Item = (Vec<Var>,Option<String>); //here we only return node name as an option to advance
    fn next(&mut self) -> Option<Self::Item> {
        let nn = {
            if !self.await_node.is_empty() {
                let an = self.await_node.clone();
                self.await_node.clear();
                an
            }
            else if !self.next_node.is_empty() { self.next_node.clone() }
            else { return None }
        };

        let mut r = self.run(&nn);
        let nn = r.1.clone();
        if nn.is_none() { self.next_node.clear(); }
        else { self.next_node = nn.unwrap(); }

        if self.await_node.is_empty() { r.1 = None; } //no need to return node name

        Some(r)
    }
}

impl<'e, 'd, D:Eval> Evaluator<'e, 'd, D> {
    pub fn new (env: &'e mut Env, data: &'d D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: "root".to_owned(),
            await_node: "".to_owned()
        }
    }
    pub fn advance (&mut self) {
        if let Some(b) = self.env.src.get_mut(&self.await_node) {
            b.await_idx = 0; //reset on advance
        }

        self.await_node.clear();
    }

    pub fn run (&mut self, node_name: &str)
                -> (Vec<Var>,Option<String>)
        where D: Eval + 'd
    {
        let mut r = vec!();
        let mut node = None;
        let mut or_valid = false; //track for OR

        if let Some(b) = self.env.src.get_mut(node_name) { //println!("src:{:?}",b.src);
            let mut state: HashMap<String,bool> = HashMap::new();
            state.insert("this.visited".to_owned(), b.visited);
            b.visited = true;

            let await_idx = b.await_idx;
            b.await_idx = 0;

            for (i,src) in b.src[await_idx..].iter().enumerate() {
                match src {
                    &Src::Await(ref nn) => {
                        b.await_idx = i+1;
                        node = nn.clone();
                        break
                    },
                    &Src::Or(_,_) => {
                        if !or_valid {
                            continue
                        }
                        else { or_valid = false; }
                    }
                    &Src::If(_,_,_) => { or_valid = true; }
                    _ => { or_valid = false; },
                }

                let (mut vars, node_) = src.eval(&mut state, self.data);

                // reset if if was successful
                if (vars.len() > 0) || node_.is_some() { or_valid = false; }

                for n in vars.drain(..) { r.push(n); }
                if let Some((node_,await)) = node_ {
                    if await {
                        b.await_idx = i+1;
                        self.await_node = node_name.to_owned();
                    }

                    node = Some(node_);
                    break;
                }
            }
        }

        for var in r.iter_mut() {
            let mut val = None;
            match var {
                &mut Var::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;

                    // NOTE: we should move this out to a SYM varkind instead
                    // (parsed earlier)
                    if s.split_terminator(' ').count() == 1 {
                        if s.chars().next().unwrap() == '`' {
                            if let Some(ref val_) = self.data.eval_bare(&s[1..]) {
                                val = Some(val_.clone());
                            }
                        }
                    }
                    else {
                        for word in s.split_terminator(' ') {
                            if started { fs.push(' '); }

                            if word.chars().next().unwrap() == '`' {
                                if let Some(ref val_) = self.data.eval_bare(&word[1..]) {
                                    fs.push_str(&val_.to_string());
                                }
                            }
                            else {
                                fs.push_str(word);
                            }

                            started = true;
                        }
                        *s = fs;
                    }
                },
                _ => {}
            }

            if let Some(val) = val {
                *var = val;
            }
        }

        return (r,node)
    }
}
<commit_msg>remove debug<commit_after>use std::collections::HashMap;
use parse::Env;
use var::Var;
use source::Src;

pub trait Eval {
    fn eval (&self, path: Option<&[&str]>, lookup: &str) -> Option<Var>;

    fn eval_bare (&self, lookup: &str) -> Option<Var> {
        let mut lookups: Vec<&str> = lookup.split_terminator('.').collect();
        let lookup = lookups.pop().unwrap();

        let path;
        if lookups.len() > 0 { path = Some(&lookups[..]); }
        else { path = None }

        self.eval(path, lookup)
    }
}

pub struct Evaluator<'e, 'd, D:Eval + 'd> {
    data: &'d D,
    env: &'e mut Env,
    next_node: String,
    await_node: String,
}

impl<'e, 'd, D:Eval + 'd> Iterator for Evaluator<'e, 'd, D>
    where D: Eval + 'd {

    type Item = (Vec<Var>,Option<String>); //here we only return node name as an option to advance
    fn next(&mut self) -> Option<Self::Item> {
        let nn = {
            if !self.await_node.is_empty() {
                let an = self.await_node.clone();
                self.await_node.clear();
                an
            }
            else if !self.next_node.is_empty() { self.next_node.clone() }
            else { return None }
        };

        let mut r = self.run(&nn);
        let nn = r.1.clone();
        if nn.is_none() { self.next_node.clear(); }
        else { self.next_node = nn.unwrap(); }

        if self.await_node.is_empty() { r.1 = None; } //no need to return node name

        Some(r)
    }
}

impl<'e, 'd, D:Eval> Evaluator<'e, 'd, D> {
    pub fn new (env: &'e mut Env, data: &'d D) -> Evaluator<'e, 'd, D> {
        Evaluator {
            env: env, data: data,
            next_node: "root".to_owned(),
            await_node: "".to_owned()
        }
    }
    pub fn advance (&mut self) {
        if let Some(b) = self.env.src.get_mut(&self.await_node) {
            b.await_idx = 0; //reset on advance
        }

        self.await_node.clear();
    }

    pub fn run (&mut self, node_name: &str)
                -> (Vec<Var>,Option<String>)
        where D: Eval + 'd
    {
        let mut r = vec!();
        let mut node = None;
        let mut or_valid = false; //track for OR

        if let Some(b) = self.env.src.get_mut(node_name) {
            let mut state: HashMap<String,bool> = HashMap::new();
            state.insert("this.visited".to_owned(), b.visited);
            b.visited = true;

            let await_idx = b.await_idx;
            b.await_idx = 0;

            for (i,src) in b.src[await_idx..].iter().enumerate() {
                match src {
                    &Src::Await(ref nn) => {
                        b.await_idx = i+1;
                        node = nn.clone();
                        break
                    },
                    &Src::Or(_,_) => {
                        if !or_valid {
                            continue
                        }
                        else { or_valid = false; }
                    }
                    &Src::If(_,_,_) => { or_valid = true; }
                    _ => { or_valid = false; },
                }

                let (mut vars, node_) = src.eval(&mut state, self.data);

                // reset if if was successful
                if (vars.len() > 0) || node_.is_some() { or_valid = false; }

                for n in vars.drain(..) { r.push(n); }
                if let Some((node_,await)) = node_ {
                    if await {
                        b.await_idx = i+1;
                        self.await_node = node_name.to_owned();
                    }

                    node = Some(node_);
                    break;
                }
            }
        }

        for var in r.iter_mut() {
            let mut val = None;
            match var {
                &mut Var::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;

                    // NOTE: we should move this out to a SYM varkind instead
                    // (parsed earlier)
                    if s.split_terminator(' ').count() == 1 {
                        if s.chars().next().unwrap() == '`' {
                            if let Some(ref val_) = self.data.eval_bare(&s[1..]) {
                                val = Some(val_.clone());
                            }
                        }
                    }
                    else {
                        for word in s.split_terminator(' ') {
                            if started { fs.push(' '); }

                            if word.chars().next().unwrap() == '`' {
                                if let Some(ref val_) = self.data.eval_bare(&word[1..]) {
                                    fs.push_str(&val_.to_string());
                                }
                            }
                            else {
                                fs.push_str(word);
                            }

                            started = true;
                        }
                        *s = fs;
                    }
                },
                _ => {}
            }

            if let Some(val) = val {
                *var = val;
            }
        }

        return (r,node)
    }
}
<|endoftext|>


<commit_before>
use ast::ExprAst;
use ast::IntNode;
use env::Env;

use ast::SymbolNode;
// use ast::BoolNode;
// use ast::CharNode;
// use ast::StrNode;
// use ast::PairNode;
// use ast::SymbolNode;
// use ast::EmptyListNode;

//use ast::Ast;
use parser::Parser;

pub struct Evaler {
    parser: Parser
}

#[allow(dead_code)]
impl Evaler {
    pub fn new() -> Evaler {
        Evaler {
            parser: Parser::new()
        }
    }

    pub fn eval(&mut self, code: String) -> ExprAst {
        let ast = self.parser.load(code);
        self._eval(ast, &mut Env::new())
    }

    fn _eval(&mut self, ast: ExprAst, env: &mut Env) -> ExprAst {
        if ast.is_self() {
            return ast;
        } else if ast.is_symbol() {
            return env.lookup(ast).unwrap();
        } else if ast.is_quote() {
            return ast.cdr().car();
        } else if ast.is_assign() {
            return self._eval_assign(ast, env);
        }
        ExprAst::Int(IntNode::new(0))
    }

    fn _eval_assign(&mut self, exp: ExprAst, env: &mut Env) -> ExprAst {
        let var = exp.cdr().car();
        let val = self._eval(exp.cdr().cdr().car(), env);
        env.def_var(var, val);
        return ExprAst::Symbol(SymbolNode::new("OK"));
    }

}

#[test]
fn test_evaler() {
    let mut evaler = Evaler::new();
    let res = evaler.eval("11".to_string());
    assert!(res.as_int() == 11);

    let res = evaler.eval(r#""hello""#.to_string());
    assert!(res.as_str() == "hello");

    let res = evaler.eval("#t".to_string());
    assert!(res.as_bool() == true);

}
<commit_msg>more on ast<commit_after>
use ast::ExprAst;
use ast::IntNode;
use env::Env;

use ast::SymbolNode;
// use ast::BoolNode;
// use ast::CharNode;
// use ast::StrNode;
// use ast::PairNode;
// use ast::SymbolNode;
// use ast::EmptyListNode;

//use ast::Ast;
use parser::Parser;

pub struct Evaler {
    parser: Parser
}

#[allow(dead_code)]
impl Evaler {
    pub fn new() -> Evaler {
        Evaler {
            parser: Parser::new()
        }
    }

    pub fn eval(&mut self, code: String) -> ExprAst {
        let ast = self.parser.load(code);
        self._eval(ast, &mut Env::new())
    }

    fn _eval(&mut self, exp: ExprAst, env: &mut Env) -> ExprAst {
        if exp.is_self() {
            return exp;
        } else if exp.is_symbol() {
            return env.lookup(exp).unwrap();
        } else if exp.is_quote() {
            return exp.cdr().car();
        } else if exp.is_assign() {
            return self._eval_assign(exp, env);
        }
        ExprAst::Int(IntNode::new(0))
    }

    fn _eval_assign(&mut self, exp: ExprAst, env: &mut Env) -> ExprAst {
        let var = exp.cdr().car();
        let val = self._eval(exp.cdr().cdr().car(), env);
        env.def_var(var, val);
        return ExprAst::Symbol(SymbolNode::new("OK"));
    }

}

#[test]
fn test_evaler() {
    let mut evaler = Evaler::new();
    let res = evaler.eval("11".to_string());
    assert!(res.as_int() == 11);

    let res = evaler.eval(r#""hello""#.to_string());
    assert!(res.as_str() == "hello");

    let res = evaler.eval("#t".to_string());
    assert!(res.as_bool() == true);

}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::fmt;
use std::fmt::{Display, Formatter, Error as E};
use std::error;
use std::result;
use std::convert::From;

use ::env::Env;

pub type Kfloat = f32;
pub type Kint = isize;
pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Clone, Debug)]
pub enum Expr {
    Int(Kint),
    Float(Kfloat),
    Cons(Rc<Expr>, Rc<Expr>),
    Nil,
    Sym(String),
    Str(String),
    Proc(Proc),
    EOF
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {
    Int,
    Float,
    Cons,
    Nil,
    Sym,
    Str,
    Proc,
    Any
}

#[derive(Clone)]
pub enum Proc {
    Lambda(Rc<Expr>, Rc<Expr>),
    Prim(String, Rc<Fn(&mut Env, &Expr) -> Result<Expr>>)
}

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidArgument(Expr),
    Type(Type, Expr),
    ArityShort,
    ArityExceed,
    Form(Expr),
    NotFunction(Expr),
    Unbound(String),
    User(String)
}

impl From<Kint> for Expr {fn from(i: Kint) -> Self {Expr::Int(i)}}
impl From<Kfloat> for Expr {fn from(f: Kfloat) -> Self {Expr::Float(f)}}
impl <'a >From<&'a str> for Expr {fn from(s: &str) -> Self {Expr::Str(s.to_string())}}
impl From<String> for Expr {fn from(s: String) -> Self {Expr::Str(s)}}

impl PartialEq for Proc {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Proc::Lambda(ref param1, ref body1), &Proc::Lambda(ref param2, ref body2)) => param1 == param2 && body1 == body2,
            _ => false
        }
    }
}

impl fmt::Debug for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref param, ref body) => write!(f, "Lambda({}, {})", param, body),
            &Proc::Prim(ref name, _) => write!(f, "Prim(#<native function {}>)", name)
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Int(i) => write!(f, "{}", i),
            &Expr::Float(fl) => write!(f, "{}", fl),
            // :TODO: pretty print for lists
            &Expr::Cons(ref car,ref cdr) => write!(f, "({} . {})", car, cdr),
            &Expr::Nil => write!(f, "nil"),
            &Expr::Sym(ref s) => write!(f, "{}", s),
            &Expr::Str(ref s) => write!(f, "\"{}\"", s),
            &Expr::Proc(ref p) => write!(f, "{}", p),
            &Expr::EOF => write!(f, "<EOF>")
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Type::Int   => write!(f, "integer"),
            &Type::Float => write!(f, "float"),
            &Type::Cons  => write!(f, "cons"),
            &Type::Nil   => write!(f, "nil"),
            &Type::Sym   => write!(f, "symbol"),
            &Type::Str   => write!(f, "string"),
            &Type::Proc  => write!(f, "procedure"),
            &Type::Any   => write!(f, "any")
        }
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref args, ref body) => write!(f, "(lambda {} {})", args, body),
            &Proc::Prim(ref name, _) => write!(f, "{}", name)
        }
    }
}

impl Display for Error {
    fn fmt(&self,  f:&mut Formatter) -> result::Result<(), E> {
        let res = match self {
            &Error::InvalidArgument(ref args) => write!(f, "invalid argument: {}", args),
            &Error::Type(ref t, ref args) => write!(f, "type mismatch: expected: {}, got: {}", t, args),
            &Error::ArityShort => write!(f, "too few argument"),
            &Error::ArityExceed => write!(f, "too many argument"),
            &Error::Form(ref e) => write!(f, "invalid form: {}", e),
            &Error::NotFunction(ref e) => write!(f, "not a function: {}", e),
            &Error::Unbound(ref s) => write!(f, "unbound variable: {}", s),
            &Error::User(ref s) => write!(f, "user error: {}", s)

        };
        try!(res);
        Ok(())
    }
}

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

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

<commit_msg>pritty list printer<commit_after>use std::rc::Rc;
use std::fmt;
use std::fmt::{Display, Formatter, Error as E};
use std::error;
use std::result;
use std::convert::From;
use std::ops::Deref;

use ::env::Env;

pub type Kfloat = f32;
pub type Kint = isize;
pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Clone, Debug)]
pub enum Expr {
    Int(Kint),
    Float(Kfloat),
    Cons(Rc<Expr>, Rc<Expr>),
    Nil,
    Sym(String),
    Str(String),
    Proc(Proc),
    EOF
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {
    Int,
    Float,
    Cons,
    Nil,
    Sym,
    Str,
    Proc,
    Any
}

#[derive(Clone)]
pub enum Proc {
    Lambda(Rc<Expr>, Rc<Expr>),
    Prim(String, Rc<Fn(&mut Env, &Expr) -> Result<Expr>>)
}

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidArgument(Expr),
    Type(Type, Expr),
    ArityShort,
    ArityExceed,
    Form(Expr),
    NotFunction(Expr),
    Unbound(String),
    User(String)
}

impl From<Kint> for Expr {fn from(i: Kint) -> Self {Expr::Int(i)}}
impl From<Kfloat> for Expr {fn from(f: Kfloat) -> Self {Expr::Float(f)}}
impl <'a >From<&'a str> for Expr {fn from(s: &str) -> Self {Expr::Str(s.to_string())}}
impl From<String> for Expr {fn from(s: String) -> Self {Expr::Str(s)}}

impl PartialEq for Proc {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Proc::Lambda(ref param1, ref body1), &Proc::Lambda(ref param2, ref body2)) => param1 == param2 && body1 == body2,
            _ => false
        }
    }
}

impl fmt::Debug for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref param, ref body) => write!(f, "Lambda({}, {})", param, body),
            &Proc::Prim(ref name, _) => write!(f, "Prim(#<native function {}>)", name)
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Int(i) => write!(f, "{}", i),
            &Expr::Float(fl) => write!(f, "{}", fl),
            // :TODO: pretty print for lists
            &Expr::Cons(ref car,ref cdr) => {
                let mut tmp = cdr.deref();
                try!(write!(f, "("));
                try!(write!(f, "{}", car));

                loop {
                    match tmp {
                        &Expr::Cons(ref car, ref cdr) => {
                            try!(write!(f, " {}",  car));
                            tmp = cdr.deref()
                        },
                        &Expr::Nil => break,
                        cdr => {
                            try!(write!(f, " . {}", cdr));
                            break
                        }
                    }

                }
                write!(f, ")")
            }
            &Expr::Nil => write!(f, "nil"),
            &Expr::Sym(ref s) => write!(f, "{}", s),
            &Expr::Str(ref s) => write!(f, "\"{}\"", s),
            &Expr::Proc(ref p) => write!(f, "{}", p),
            &Expr::EOF => write!(f, "<EOF>")
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Type::Int   => write!(f, "integer"),
            &Type::Float => write!(f, "float"),
            &Type::Cons  => write!(f, "cons"),
            &Type::Nil   => write!(f, "nil"),
            &Type::Sym   => write!(f, "symbol"),
            &Type::Str   => write!(f, "string"),
            &Type::Proc  => write!(f, "procedure"),
            &Type::Any   => write!(f, "any")
        }
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref args, ref body) => write!(f, "(lambda {} {})", args, body),
            &Proc::Prim(ref name, _) => write!(f, "{}", name)
        }
    }
}

impl Display for Error {
    fn fmt(&self,  f:&mut Formatter) -> result::Result<(), E> {
        let res = match self {
            &Error::InvalidArgument(ref args) => write!(f, "invalid argument: {}", args),
            &Error::Type(ref t, ref args) => write!(f, "type mismatch: expected: {}, got: {}", t, args),
            &Error::ArityShort => write!(f, "too few argument"),
            &Error::ArityExceed => write!(f, "too many argument"),
            &Error::Form(ref e) => write!(f, "invalid form: {}", e),
            &Error::NotFunction(ref e) => write!(f, "not a function: {}", e),
            &Error::Unbound(ref s) => write!(f, "unbound variable: {}", s),
            &Error::User(ref s) => write!(f, "user error: {}", s)

        };
        try!(res);
        Ok(())
    }
}

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

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

<|endoftext|>


<commit_before>use imgui::{Ui,ImStr,ImString};

use std::fs;
use std::path::Path;

use app::AppState;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
        }
    }
}

impl FileState {
    fn update(&mut self) {
        let cd = self.cd.to_string();

        if self.idx > 1 { // chose a file?
            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = 1;
            }
        }
        else if self.idx < 1 { // up a directory?
            if let Some(path) = Path::new(&cd).parent() {
                self.cd.clear();
                self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
                self.idx = 1;
            }
            // NOTE: this fails if we're at the top of a relative directory listing,
            // or the root of the drive/share
        }

        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"./".to_owned());
                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else { self.selected = Some(cd); }
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                self.update();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                })
                    .collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);
            })
    }

}

<commit_msg>fix browsing<commit_after>use imgui::{Ui,ImStr,ImString};

use std::fs;
use std::path::Path;

use app::AppState;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
        }
    }
}

impl FileState {
    fn update(&mut self) {
        if self.idx > 1 { // chose a file?
            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = 1;
            }
        }
        else if self.idx < 1 { // up a directory?
            self.to_parent();
        }

        let cd = self.cd.to_string();
        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(&cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"./".to_owned());
                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else {
            if !cd.is_empty() {
                self.selected = Some(cd);
            }
        }
    }

    fn to_parent(&mut self) {
        self.selected = None;
        if let Some(path) = Path::new(&self.cd.to_string()).parent() {
            self.cd.clear();
            self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
            self.idx = 1;
        }
        // NOTE: this fails if we're at the top of a relative directory listing,
        // or the root of the drive/share
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                self.update();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                })
                    .collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);

                match self.selected {
                    Some(ref file) => {
                        ui.text(im_str!("Select File {:}?",file));

                        if ui.small_button(im_str!("open")) {
                        }
                    },
                    _ => {},
                }
            })
    }

}

<|endoftext|>


<commit_before>use futures::{Future, future};
use futures::sync::oneshot;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex, RwLock, Weak};
use uuid::Uuid;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    Dropped,
    NotReady,
    Eof,
    Other,
}

pub const MAX_SIZE: usize = 1048576;
pub const MAX_CAPACITY: u64 = 16777216;

#[derive(Debug)]
pub enum Chunk {
    Data(u64, Vec<u8>),
    Eof(u64),
}

impl Chunk {
    fn data(data: Vec<u8>) -> Self {
        Chunk::Data(0, data)
    }

    fn eof() -> Self {
        Chunk::Eof(0)
    }

    fn count(&self) -> u64 {
        match *self {
            Chunk::Data(count, ..) => count,
            Chunk::Eof(count, ..) => count,
        }
    }

    fn len(&self) -> u64 {
        match *self {
            Chunk::Data(_, ref data) => data.len() as u64,
            Chunk::Eof(..) => 0,
        }
    }
}

type SharedChunk = Arc<Mutex<Chunk>>;

#[derive(Clone, Debug)]
enum State {
    Streaming,
    Stop,
}

struct Config {
    pub length: Option<u64>,
    pub capacity: u64,
    pub lifecount: u64,
}

struct Statistic {
    pub pushed: u64,
    pub dropped: u64,
    pub buffered: u64,
}

pub struct Flow {
    reference: Weak<RwLock<Flow>>,
    pub id: String,
    config: Config,
    statistic: Statistic,
    state: State,
    next_index: u64,
    tail_index: u64,
    bucket: HashMap<u64, SharedChunk>,
    waiting_push: VecDeque<(u64, oneshot::Sender<()>)>,
    waiting_pull: Arc<Mutex<HashMap<u64, Vec<oneshot::Sender<SharedChunk>>>>>,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(length: Option<u64>) -> Arc<RwLock<Self>> {
        let flow = Flow {
            reference: Weak::new(),
            id: Uuid::new_v4().simple().to_string(),
            config: Config {
                length,
                capacity: MAX_CAPACITY,
                lifecount: 1,
            },
            statistic: Statistic {
                pushed: 0,
                dropped: 0,
                buffered: 0,
            },
            state: State::Streaming,
            next_index: 0,
            tail_index: 0,
            bucket: HashMap::new(),
            waiting_push: VecDeque::new(),
            waiting_pull: Arc::new(Mutex::new(HashMap::new())),
        };
        let flow_ptr = Arc::new(RwLock::new(flow));
        flow_ptr.write().unwrap().reference = Arc::downgrade(&flow_ptr);
        flow_ptr
    }

    pub fn get_range(&self) -> (u64, u64) {
        (self.tail_index, self.next_index)
    }

    fn is_streaming(&self) -> bool {
        match self.state {
            State::Streaming => true,
            _ => false,
        }
    }

    fn acquire_chunk(&mut self, chunk: Chunk) -> FlowFuture<u64> {
        let chunk_len = chunk.len() as u64;

        // Check if the flow is EOF.
        if !self.is_streaming() {
            return future::err(Error::Invalid).boxed();
        }
        // Check if the flow is already overflow.
        if self.statistic.buffered > self.config.capacity {
            return future::err(Error::Invalid).boxed();
        }

        // Update statistic.
        let new_pushed = match self.statistic.pushed.checked_add(chunk_len) {
            Some(new_pushed) => {
                if let Some(length) = self.config.length {
                    // Check if the length is over.
                    if new_pushed > length {
                        return future::err(Error::Invalid).boxed();
                    }
                }
                new_pushed
            }
            None => return future::err(Error::Invalid).boxed(),
        };
        let new_buffered = match self.statistic.buffered.checked_add(chunk_len) {
            Some(new_buffered) => new_buffered,
            None => return future::err(Error::Invalid).boxed(),
        };
        self.statistic.pushed = new_pushed;
        self.statistic.buffered = new_buffered;

        // Update EOF state.
        if let Chunk::Eof(..) = chunk {
            self.state = State::Stop;
        }

        // Acquire the chunk index.
        let chunk_index = self.next_index;
        self.next_index += 1;

        let shared_chunk = Arc::new(Mutex::new(chunk));
        // Insert the chunk.
        self.bucket.insert(chunk_index, shared_chunk.clone());

        // Check if we need to block for overflow.
        let fut = if self.statistic.buffered > self.config.capacity {
            let (tx, rx) = oneshot::channel();
            self.waiting_push.push_back((chunk_len, tx));
            rx.map_err(|_| Error::Other).boxed()
        } else {
            future::ok(()).boxed()
        };

        // Wake up the waiting pulls.
        let mut waiting_pull = self.waiting_pull.lock().unwrap();
        if let Some(waits) = waiting_pull.remove(&chunk_index) {
            for wait in waits {
                // Don't unwrap, since the receiver can early quit.
                wait.send(shared_chunk.clone()).is_ok();
            }
        }

        fut.map(move |_| chunk_index).boxed()
    }

    fn sanitize_buffer(&mut self) {
        let mut tail_index = self.tail_index;
        let next_index = self.next_index;
        let lifecount = self.config.lifecount;

        while tail_index < next_index {
            {
                // Get should always success.
                let chunk = self.bucket.get(&tail_index).unwrap().lock().unwrap();
                if chunk.count() < lifecount {
                    break;
                }

                self.statistic.buffered -= chunk.len();
                self.statistic.dropped += chunk.len();

                let mut remain = chunk.len();
                while remain > 0 {
                    let new_len = if let Some(wait) = self.waiting_push.front_mut() {
                        let (new_remain, new_len) = if remain >= wait.0 {
                            (remain - wait.0, 0)
                        } else {
                            (0, wait.0 - remain)
                        };
                        remain = new_remain;
                        wait.0 = new_len;
                        wait.0
                    } else {
                        break;
                    };
                    if new_len == 0 {
                        // Remove should always success.
                        let wait = self.waiting_push.pop_front().unwrap();
                        // Don't unwrap, since the receiver can early quit.
                        wait.1.send(()).is_ok();
                    }
                }
            }

            // Remove should always success.
            self.bucket.remove(&tail_index).unwrap();

            tail_index += 1;
        }

        self.tail_index = tail_index;
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        self.acquire_chunk(Chunk::data(data.to_vec()))
    }

    pub fn close(&mut self) -> FlowFuture<()> {
        if self.is_streaming() {
            self.acquire_chunk(Chunk::eof()).map(|_| ()).boxed()
        } else {
            future::err(Error::Invalid).boxed()
        }
    }

    pub fn pull(&self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        // Clone the chunk if exists.
        let chunk = match self.bucket.get(&chunk_index) {
            Some(chunk) => Some(chunk.clone()),
            None => None,
        };
        // Try to get the chunk.
        let fut = if let Some(chunk) = chunk {
            future::ok(chunk).boxed()
        } else {
            if chunk_index < self.next_index {
                future::err(Error::Dropped).boxed()
            } else if let Some(0) = timeout {
                future::err(Error::NotReady).boxed()
            } else {
                let (tx, rx) = oneshot::channel();
                let mut waiting_pull = self.waiting_pull.lock().unwrap();
                let waits = waiting_pull.entry(chunk_index).or_insert(Vec::new());
                waits.push(tx);
                rx.map_err(|_| Error::Other).boxed()
            }
        };

        let flow_ref = self.reference.clone();
        let lifecount = self.config.lifecount;
        fut.and_then(move |chunk| {
                let flow_ptr = match flow_ref.upgrade() {
                    Some(ptr) => ptr.clone(),
                    None => return future::err(Error::Other),
                };

                let (count, result) = {
                    let mut chunk = chunk.lock().unwrap();
                    let (count, result) = match *chunk {
                        Chunk::Data(ref mut count, ref data) => (count, Ok(data.to_vec())),
                        Chunk::Eof(ref mut count) => (count, Err(Error::Eof)),
                    };
                    *count += 1;
                    (*count, result)
                };

                // Fast check if we need to sanitize.
                if count >= lifecount {
                    let mut flow = flow_ptr.write().unwrap();
                    flow.sanitize_buffer();
                }

                future::result(result)
            })
            .boxed()
    }
}

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

    macro_rules! sync_assert_eq {
        ($a:expr, $b:expr) => {
            let fut = $a;
            assert_eq!(fut.wait(), $b);
        }
    }

    #[test]
    fn basic_flow_operations() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(&[1u8; 1234]), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE]), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(2));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE + 1]), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(&[1u8; 1234] as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(2, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(100, Some(0)), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let ptr = Flow::new(Some(10));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"world"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"!"), Err(Error::Invalid));
    }

    #[test]
    fn close_flow() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.write().unwrap().close(), Ok(()));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Eof));
        sync_assert_eq!(ptr.write().unwrap().close(), Err(Error::Invalid));
    }

    #[test]
    fn dropped_chunk() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"A"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"B"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"C"), Ok(2));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"A" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::Dropped));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Ok(Vec::from(b"B" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Dropped));
        assert_eq!(ptr.read().unwrap().get_range(), (2, 3));
    }

    #[test]
    fn waiting_pull() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::NotReady));
        let fut = ptr.read().unwrap().pull(1, None);
        let fut1 = ptr.write().unwrap().push(b"ello");
        let fut2 = ptr.write().unwrap().push(b"hello");
        sync_assert_eq!(fut.join3(fut1, fut2), Ok((Vec::from(b"hello" as &[u8]), 0, 1)));
    }

    #[test]
    fn waiting_push() {
        let ptr = Flow::new(None);

        for idx in 0..(MAX_CAPACITY / MAX_SIZE as u64) {
            sync_assert_eq!(ptr.write().unwrap().push(&[0u8; MAX_SIZE]), Ok(idx));
        }
        let base_idx = MAX_CAPACITY / MAX_SIZE as u64;

        let fut = ptr.write().unwrap().push(b"B");
        sync_assert_eq!(ptr.write().unwrap().push(&[0u8; MAX_SIZE]), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(vec![0u8; MAX_SIZE]));
        sync_assert_eq!(fut, Ok(base_idx));
        sync_assert_eq!(ptr.write().unwrap().push(b"C"), Ok(base_idx + 1));
    }
}
<commit_msg>Improve tests<commit_after>use futures::{Future, future};
use futures::sync::oneshot;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex, RwLock, Weak};
use uuid::Uuid;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    Dropped,
    NotReady,
    Eof,
    Other,
}

pub const MAX_SIZE: usize = 1048576;
pub const MAX_CAPACITY: u64 = 16777216;

#[derive(Debug)]
pub enum Chunk {
    Data(u64, Vec<u8>),
    Eof(u64),
}

impl Chunk {
    fn data(data: Vec<u8>) -> Self {
        Chunk::Data(0, data)
    }

    fn eof() -> Self {
        Chunk::Eof(0)
    }

    fn count(&self) -> u64 {
        match *self {
            Chunk::Data(count, ..) => count,
            Chunk::Eof(count, ..) => count,
        }
    }

    fn len(&self) -> u64 {
        match *self {
            Chunk::Data(_, ref data) => data.len() as u64,
            Chunk::Eof(..) => 0,
        }
    }
}

type SharedChunk = Arc<Mutex<Chunk>>;

#[derive(Clone, Debug)]
enum State {
    Streaming,
    Stop,
}

struct Config {
    pub length: Option<u64>,
    pub capacity: u64,
    pub lifecount: u64,
}

struct Statistic {
    pub pushed: u64,
    pub dropped: u64,
    pub buffered: u64,
}

pub struct Flow {
    reference: Weak<RwLock<Flow>>,
    pub id: String,
    config: Config,
    statistic: Statistic,
    state: State,
    next_index: u64,
    tail_index: u64,
    bucket: HashMap<u64, SharedChunk>,
    waiting_push: VecDeque<(u64, oneshot::Sender<()>)>,
    waiting_pull: Arc<Mutex<HashMap<u64, Vec<oneshot::Sender<SharedChunk>>>>>,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(length: Option<u64>) -> Arc<RwLock<Self>> {
        let flow = Flow {
            reference: Weak::new(),
            id: Uuid::new_v4().simple().to_string(),
            config: Config {
                length,
                capacity: MAX_CAPACITY,
                lifecount: 1,
            },
            statistic: Statistic {
                pushed: 0,
                dropped: 0,
                buffered: 0,
            },
            state: State::Streaming,
            next_index: 0,
            tail_index: 0,
            bucket: HashMap::new(),
            waiting_push: VecDeque::new(),
            waiting_pull: Arc::new(Mutex::new(HashMap::new())),
        };
        let flow_ptr = Arc::new(RwLock::new(flow));
        flow_ptr.write().unwrap().reference = Arc::downgrade(&flow_ptr);
        flow_ptr
    }

    pub fn get_range(&self) -> (u64, u64) {
        (self.tail_index, self.next_index)
    }

    fn is_streaming(&self) -> bool {
        match self.state {
            State::Streaming => true,
            _ => false,
        }
    }

    fn acquire_chunk(&mut self, chunk: Chunk) -> FlowFuture<u64> {
        let chunk_len = chunk.len() as u64;

        // Check if the flow is EOF.
        if !self.is_streaming() {
            return future::err(Error::Invalid).boxed();
        }
        // Check if the flow is already overflow.
        if self.statistic.buffered > self.config.capacity {
            return future::err(Error::Invalid).boxed();
        }

        // Update statistic.
        let new_pushed = match self.statistic.pushed.checked_add(chunk_len) {
            Some(new_pushed) => {
                if let Some(length) = self.config.length {
                    // Check if the length is over.
                    if new_pushed > length {
                        return future::err(Error::Invalid).boxed();
                    }
                }
                new_pushed
            }
            None => return future::err(Error::Invalid).boxed(),
        };
        let new_buffered = match self.statistic.buffered.checked_add(chunk_len) {
            Some(new_buffered) => new_buffered,
            None => return future::err(Error::Invalid).boxed(),
        };
        self.statistic.pushed = new_pushed;
        self.statistic.buffered = new_buffered;

        // Update EOF state.
        if let Chunk::Eof(..) = chunk {
            self.state = State::Stop;
        }

        // Acquire the chunk index.
        let chunk_index = self.next_index;
        self.next_index += 1;

        let shared_chunk = Arc::new(Mutex::new(chunk));
        // Insert the chunk.
        self.bucket.insert(chunk_index, shared_chunk.clone());

        // Check if we need to block for overflow.
        let fut = if self.statistic.buffered > self.config.capacity {
            let (tx, rx) = oneshot::channel();
            self.waiting_push.push_back((chunk_len, tx));
            rx.map_err(|_| Error::Other).boxed()
        } else {
            future::ok(()).boxed()
        };

        // Wake up the waiting pulls.
        let mut waiting_pull = self.waiting_pull.lock().unwrap();
        if let Some(waits) = waiting_pull.remove(&chunk_index) {
            for wait in waits {
                // Don't unwrap, since the receiver can early quit.
                wait.send(shared_chunk.clone()).is_ok();
            }
        }

        fut.map(move |_| chunk_index).boxed()
    }

    fn sanitize_buffer(&mut self) {
        let mut tail_index = self.tail_index;
        let next_index = self.next_index;
        let lifecount = self.config.lifecount;

        while tail_index < next_index {
            {
                // Get should always success.
                let chunk = self.bucket.get(&tail_index).unwrap().lock().unwrap();
                if chunk.count() < lifecount {
                    break;
                }

                self.statistic.buffered -= chunk.len();
                self.statistic.dropped += chunk.len();

                let mut remain = chunk.len();
                while remain > 0 {
                    let new_len = if let Some(wait) = self.waiting_push.front_mut() {
                        let (new_remain, new_len) = if remain >= wait.0 {
                            (remain - wait.0, 0)
                        } else {
                            (0, wait.0 - remain)
                        };
                        remain = new_remain;
                        wait.0 = new_len;
                        wait.0
                    } else {
                        break;
                    };
                    if new_len == 0 {
                        // Remove should always success.
                        let wait = self.waiting_push.pop_front().unwrap();
                        // Don't unwrap, since the receiver can early quit.
                        wait.1.send(()).is_ok();
                    }
                }
            }

            // Remove should always success.
            self.bucket.remove(&tail_index).unwrap();

            tail_index += 1;
        }

        self.tail_index = tail_index;
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        self.acquire_chunk(Chunk::data(data.to_vec()))
    }

    pub fn close(&mut self) -> FlowFuture<()> {
        if self.is_streaming() {
            self.acquire_chunk(Chunk::eof()).map(|_| ()).boxed()
        } else {
            future::err(Error::Invalid).boxed()
        }
    }

    pub fn pull(&self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        // Clone the chunk if exists.
        let chunk = match self.bucket.get(&chunk_index) {
            Some(chunk) => Some(chunk.clone()),
            None => None,
        };
        // Try to get the chunk.
        let fut = if let Some(chunk) = chunk {
            future::ok(chunk).boxed()
        } else {
            if chunk_index < self.next_index {
                future::err(Error::Dropped).boxed()
            } else if let Some(0) = timeout {
                future::err(Error::NotReady).boxed()
            } else {
                let (tx, rx) = oneshot::channel();
                let mut waiting_pull = self.waiting_pull.lock().unwrap();
                let waits = waiting_pull.entry(chunk_index).or_insert(Vec::new());
                waits.push(tx);
                rx.map_err(|_| Error::Other).boxed()
            }
        };

        let flow_ref = self.reference.clone();
        let lifecount = self.config.lifecount;
        fut.and_then(move |chunk| {
                let flow_ptr = match flow_ref.upgrade() {
                    Some(ptr) => ptr.clone(),
                    None => return future::err(Error::Other),
                };

                let (count, result) = {
                    let mut chunk = chunk.lock().unwrap();
                    let (count, result) = match *chunk {
                        Chunk::Data(ref mut count, ref data) => (count, Ok(data.to_vec())),
                        Chunk::Eof(ref mut count) => (count, Err(Error::Eof)),
                    };
                    *count += 1;
                    (*count, result)
                };

                // Fast check if we need to sanitize.
                if count >= lifecount {
                    let mut flow = flow_ptr.write().unwrap();
                    flow.sanitize_buffer();
                }

                future::result(result)
            })
            .boxed()
    }
}

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

    macro_rules! sync_assert_eq {
        ($a:expr, $b:expr) => {
            let fut = $a;
            assert_eq!(fut.wait(), $b);
        }
    }

    #[test]
    fn basic_flow_operations() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(&[1u8; 1234]), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE]), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(2));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE + 1]), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(&[1u8; 1234] as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(2, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(100, Some(0)), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let ptr = Flow::new(Some(10));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"world"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"!"), Err(Error::Invalid));
    }

    #[test]
    fn close_flow() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.write().unwrap().close(), Ok(()));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Eof));
        sync_assert_eq!(ptr.write().unwrap().close(), Err(Error::Invalid));
    }

    #[test]
    fn dropped_chunk() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"A"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"B"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"C"), Ok(2));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"A" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::Dropped));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Ok(Vec::from(b"B" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Dropped));
        assert_eq!(ptr.read().unwrap().get_range(), (2, 3));
    }

    #[test]
    fn waiting_pull() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::NotReady));
        let fut = ptr.read().unwrap().pull(1, None);
        let fut1 = ptr.write().unwrap().push(b"ello");
        let fut2 = ptr.write().unwrap().push(b"hello");
        sync_assert_eq!(fut.join3(fut1, fut2), Ok((Vec::from(b"hello" as &[u8]), 0, 1)));
    }

    #[test]
    fn waiting_push() {
        let ptr = Flow::new(None);

        sync_assert_eq!(ptr.write().unwrap().push(b"A"), Ok(0));
        for idx in 1..(MAX_CAPACITY / MAX_SIZE as u64) {
            sync_assert_eq!(ptr.write().unwrap().push(&[0u8; MAX_SIZE]), Ok(idx));
        }
        let base_idx = MAX_CAPACITY / MAX_SIZE as u64;
        sync_assert_eq!(ptr.write().unwrap().push(b"D"), Ok(base_idx));

        let fut = ptr.write().unwrap().push(&[0u8; MAX_SIZE]);
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"A" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Ok(vec![0u8; MAX_SIZE]));
        sync_assert_eq!(fut, Ok(base_idx + 1));

        ptr.write().unwrap().push(&[0u8; MAX_SIZE]);
        sync_assert_eq!(ptr.write().unwrap().push(b"C"), Err(Error::Invalid));
    }

    #[test]
    fn outlive() {
        let fut = {
            let ptr = Flow::new(None);
            sync_assert_eq!(ptr.write().unwrap().push(b"A"), Ok(0));
            let flow = ptr.read().unwrap();
            flow.pull(0, Some(0))
        };
        sync_assert_eq!(fut, Err(Error::Other));
    }
}
<|endoftext|>