<commit_before>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{
    FloatRegisters,
    IntRegisters,
    EnvRegisters,
    data,
    error,
    flag,
    io,
    number,
    ptrace_event,
    scheme,
};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::scheme::Scheme as _;

use self::data::{Map, SigAction, Stat, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace, memory::MemoryScheme};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => match a {
                        SYS_FMAP if b == !0 => {
                            MemoryScheme.fmap(!0, unsafe { validate_ref(c as *const Map, d)? })
                        },
                        _ => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    }
                    SYS_ARG_MSLICE => match a {
                        SYS_FSTAT => fstat(fd, unsafe { validate_ref_mut(c as *mut Stat, d)? }),
                        _ => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    },
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FRENAME => frename(fd, validate_str(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_str(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_RMDIR => rmdir(validate_str(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_str(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(b, c, d, e, f),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),

                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_IOPL => iopl(b, stack),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name = context.name.read();
            if name.contains("bootstrap") {
                if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", *context.name.read(), context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", *context.name.read(), context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<commit_msg>Disable syscall debugging<commit_after>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{
    FloatRegisters,
    IntRegisters,
    EnvRegisters,
    data,
    error,
    flag,
    io,
    number,
    ptrace_event,
    scheme,
};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::scheme::Scheme as _;

use self::data::{Map, SigAction, Stat, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace, memory::MemoryScheme};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => match a {
                        SYS_FMAP if b == !0 => {
                            MemoryScheme.fmap(!0, unsafe { validate_ref(c as *const Map, d)? })
                        },
                        _ => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    }
                    SYS_ARG_MSLICE => match a {
                        SYS_FSTAT => fstat(fd, unsafe { validate_ref_mut(c as *mut Stat, d)? }),
                        _ => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    },
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FRENAME => frename(fd, validate_str(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_str(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_RMDIR => rmdir(validate_str(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_str(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(b, c, d, e, f),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),

                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_IOPL => iopl(b, stack),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name = context.name.read();
            if name.contains("bootstrap") {
                if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", *context.name.read(), context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", *context.name.read(), context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();
            if term.cursor.pos.x == 0 {
                term.editor.contents.remove(line);
                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                let line = term.current_line() + term.cursor.pos.y;
                let len = term.editor.contents[line].len() - 1;
                term.cursor.pos.x = len;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;
                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            term.editor.contents.insert(line, vec![b'\n']);
            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;
            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }
            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            /*let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;
            term.editor.contents[line, pos*/
            term.term[term.cursor.current_pos()].set_ch(c);
            term.cursor.save_pos();
            term.cursor.pos.x += 1;
        }
    }
}
<commit_msg>Implement backspace<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();
            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;
                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);
                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                //let line = term.current_line() + term.cursor.pos.y;
                //let len = term.editor.contents[line].len() - 1;
                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;
                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            term.editor.contents.insert(line, vec![b'\n']);
            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;
            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }
            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            /*let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;
            term.editor.contents[line, pos*/
            term.term[term.cursor.current_pos()].set_ch(c);
            term.cursor.save_pos();
            term.cursor.pos.x += 1;
        }
    }
}
<|endoftext|>


<commit_before>
/// Implemented by contexts that can transform.
pub trait Transform2d<'a> {
    /// Translate x and y.
    fn trans(&'a self, x: f64, y: f64) -> Self;

    /// Translate x an y in local coordinates.
    fn trans_local(&'a self, x: f64, y: f64) -> Self;

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg_local(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad_local(angle * pi / 180.0)
    }

    /// Rotate radians.
    fn rot_rad(&'a self, angle: f64) -> Self;

    /// Rotate radians in local coordinates.
    fn rot_rad_local(&'a self, angle: f64) -> Self;

    /// Scale.
    fn scale(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in local coordinates.
    fn scale_local(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in both directions.
    #[inline(always)]
    fn zoom(&'a self, s: f64) -> Self {
        self.scale(s, s)
    }

    /// Scales in both directions.
    #[inline(always)]
    fn zoom_local(&'a self, s: f64) -> Self {
        self.scale_local(s, s)
    }

    /// Flips vertically.
    #[inline(always)]
    fn flip_v(&'a self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v_local(&'a self) -> Self {
        self.scale_local(1.0, -1.0)
    }

    /// Flips horizontally.
    #[inline(always)]
    fn flip_h(&'a self) -> Self {
        self.scale(-1.0, 0.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h_local(&'a self) -> Self {
        self.scale_local(-1.0, 0.0)
    }

    /// Shear.
    fn shear(&'a self, sx: f64, sy: f64) -> Self;

    /// Shears in local coordinates.
    fn shear_local(&'a self, sx: f64, sy: f64) -> Self;
}
<commit_msg>Fixed documentation<commit_after>
/// Implemented by contexts that can transform.
pub trait Transform2d<'a> {
    /// Translate x and y.
    fn trans(&'a self, x: f64, y: f64) -> Self;

    /// Translate x an y in local coordinates.
    fn trans_local(&'a self, x: f64, y: f64) -> Self;

    /// Rotates degrees.
    #[inline(always)]
    fn rot_deg(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotates degrees in local coordinates.
    #[inline(always)]
    fn rot_deg_local(&'a self, angle: f64) -> Self {
        let pi: f64 = Float::pi();
        self.rot_rad_local(angle * pi / 180.0)
    }

    /// Rotate radians.
    fn rot_rad(&'a self, angle: f64) -> Self;

    /// Rotate radians in local coordinates.
    fn rot_rad_local(&'a self, angle: f64) -> Self;

    /// Scale.
    fn scale(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in local coordinates.
    fn scale_local(&'a self, sx: f64, sy: f64) -> Self;

    /// Scales in both directions.
    #[inline(always)]
    fn zoom(&'a self, s: f64) -> Self {
        self.scale(s, s)
    }

    /// Scales in both directions in local coordinates.
    #[inline(always)]
    fn zoom_local(&'a self, s: f64) -> Self {
        self.scale_local(s, s)
    }

    /// Flips vertically.
    #[inline(always)]
    fn flip_v(&'a self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v_local(&'a self) -> Self {
        self.scale_local(1.0, -1.0)
    }

    /// Flips horizontally.
    #[inline(always)]
    fn flip_h(&'a self) -> Self {
        self.scale(-1.0, 0.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h_local(&'a self) -> Self {
        self.scale_local(-1.0, 0.0)
    }

    /// Shear.
    fn shear(&'a self, sx: f64, sy: f64) -> Self;

    /// Shears in local coordinates.
    fn shear_local(&'a self, sx: f64, sy: f64) -> Self;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::cell::{RefCell, Cell};
use std::cmp;
use std::fmt::{Display, Result as FmtResult, Formatter};
use std::io::{Result as IoResult, Write};
use std::mem;
use std::rc::{Rc, Weak};

use arena::TypedArena;
use errors::Result;

// ----------------------------------------------------------------------
// Memory Tracker classes

type MemTrackerPtr = Rc<MemTracker>;
type WeakMemTrackerPtr = Weak<MemTracker>;

pub struct MemTracker {
  cur_bytes: Cell<i64>,
  max_bytes: Cell<i64>,
  children: RefCell<Vec<MemTrackerPtr>>,
  parent: Option<WeakMemTrackerPtr>
}

impl MemTracker {
  pub fn new_ptr(mut parent: Option<&mut MemTrackerPtr>) -> Result<MemTrackerPtr> {
    let mem_tracker = Rc::new(MemTracker {
      cur_bytes: Cell::new(0), max_bytes: Cell::new(0),
      children: RefCell::new(vec!()),
      parent: parent.as_mut().map(|p| Rc::downgrade(p))
    });
    if let Some(p) = parent {
      let mut parent_children = p.children.try_borrow_mut()?;
      parent_children.push(mem_tracker.clone());
    }
    Ok(mem_tracker)
  }

  pub fn cur_bytes(&self) -> i64 {
    self.cur_bytes.get()
  }

  pub fn max_bytes(&self) -> i64 {
    self.max_bytes.get()
  }

  pub fn alloc(&self, num_bytes: usize) {
    let new_cur_bytes = self.cur_bytes.get() + num_bytes as i64;
    if new_cur_bytes > self.max_bytes.get() {
      self.max_bytes.set(new_cur_bytes)
    }
    self.cur_bytes.set(new_cur_bytes);
  }

  pub fn dealloc(&self, num_bytes: usize) {
    assert!(self.cur_bytes.get() >= num_bytes as i64);
    self.cur_bytes.set(self.cur_bytes.get() - num_bytes as i64);
  }
}

// ----------------------------------------------------------------------
// Buffer classes

/// A resize-able byte buffer class.
///
/// Note that a byte buffer has two attributes:
/// `capacity` and `size`: the former is the total bytes allocated for
/// the buffer, while the latter is the actual bytes that have valid data.
/// Invariant: `capacity` >= `size`.
pub struct ByteBuffer {
  data: Vec<u8>,
  mem_tracker: Option<MemTrackerPtr>
}

impl ByteBuffer {
  pub fn new() -> Self {
    ByteBuffer { data: vec!(), mem_tracker: None }
  }

  pub fn with_capacity(mut self, cap: usize) -> Self {
    self.data.reserve(cap);
    self
  }

  pub fn with_mem_tracker(mut self, mc: MemTrackerPtr) -> Self {
    mc.alloc(self.data.capacity());
    self.mem_tracker = Some(mc);
    self
  }

  pub fn data(&self) -> &[u8] {
    self.data.as_slice()
  }

  #[inline]
  pub fn set_data(&mut self, new_data: Vec<u8>) {
    if self.is_mem_tracked() {
      let mc = self.mem_tracker.as_ref().unwrap();
      mc.dealloc(self.data.capacity());
      mc.alloc(new_data.capacity());
    }
    self.data = new_data;
  }

  #[inline]
  pub fn resize(&mut self, new_capacity: usize) {
    let old_capacity = self.data.capacity();
    let extra_capacity = new_capacity - old_capacity;
    if extra_capacity > 0 {
      self.data.reserve(extra_capacity);
      if let Some(ref mc) = self.mem_tracker {
        mc.alloc(self.data.capacity() - old_capacity);
      }
    }
  }

  #[inline]
  pub fn consume(&mut self) -> BytePtr {
    let new_data = vec!();
    if let Some(ref mc) = self.mem_tracker {
      mc.dealloc(self.data.capacity());
      mc.alloc(new_data.capacity());
    }
    let old_data = mem::replace(&mut self.data, new_data);
    BytePtr::new(old_data)
  }

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

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

  #[inline]
  pub fn is_mem_tracked(&self) -> bool {
    self.mem_tracker.is_some()
  }

  pub fn mem_tracker(&self) -> &MemTrackerPtr {
    self.mem_tracker.as_ref().unwrap()
  }
}

impl Write for ByteBuffer {
  fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
    // Check if we have enough capacity for the new data
    if self.data.len() + buf.len() > self.data.capacity() {
      let new_capacity = ::std::cmp::max(
        self.data.capacity() * 2, self.data.len() + buf.len());
      self.resize(new_capacity);
    }
    self.data.write(buf)
  }

  fn flush(&mut self) -> IoResult<()> {
    self.data.flush()
  }
}

impl Drop for ByteBuffer {
  fn drop(&mut self) {
    if self.is_mem_tracked() {
      let mc = self.mem_tracker.as_ref().unwrap();
      mc.dealloc(self.data.capacity());
    }
  }
}

// ----------------------------------------------------------------------
// Immutable Buffer (BytePtr) classes

/// An representation of a slice on a reference-counting and read-only byte array.
/// Sub-slices can be further created from this. The byte array will be released
/// when all slices are dropped.
#[derive(Clone, Debug, PartialEq)]
pub struct BytePtr {
  data: Rc<Vec<u8>>,
  start: usize,
  len: usize
}

impl BytePtr {
  pub fn new(v: Vec<u8>) -> Self {
    let len = v.len();
    Self { data: Rc::new(v), start: 0, len: len }
  }

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

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

  pub fn all(&self) -> BytePtr {
    BytePtr { data: self.data.clone(), start: self.start, len: self.len }
  }

  pub fn start_from(&self, start: usize) -> BytePtr {
    assert!(start <= self.len);
    BytePtr { data: self.data.clone(), start: self.start + start, len: self.len - start }
  }

  pub fn range(&self, start: usize, len: usize) -> BytePtr {
    assert!(start + len <= self.len);
    BytePtr { data: self.data.clone(), start: self.start + start, len: len }
  }

  pub fn slice(&self) -> &[u8] {
    &self.data[self.start..self.start + self.len]
  }
}

impl Display for BytePtr {
  fn fmt(&self, f: &mut Formatter) -> FmtResult {
    write!(f, "{:?}", self.data)
  }
}

// ----------------------------------------------------------------------
// MemoryPool classes

/// A central place for managing memory.
/// NOTE: client can only acquire bytes through this API, but not releasing.
/// All the memory will be released once the instance of this trait goes out of scope.
pub struct MemoryPool {
  arena: TypedArena<Vec<u8>>,

  // NOTE: these need to be in `Cell` since all public APIs of
  // this struct take `&self`, instead of `&mut self`. Otherwise, we cannot make the
  // lifetime of outputs to be the same as this memory pool.
  cur_bytes_allocated: Cell<i64>,
  max_bytes_allocated: Cell<i64>
}

impl MemoryPool {
  pub fn new() -> Self {
    let arena = TypedArena::new();
    Self { arena: arena, cur_bytes_allocated: Cell::new(0), max_bytes_allocated: Cell::new(0) }
  }

  /// Acquire a new byte buffer of at least `size` bytes
  /// Return a unique reference to the buffer
  pub fn acquire(&self, size: usize) -> &mut [u8] {
    let buf = vec![0; size];
    self.consume(buf)
  }

  /// Consume `buf` and add it to this memory pool
  /// After the call, `buf` has the same lifetime as the pool.
  /// Return a unique reference to the consumed buffer.
  pub fn consume(&self, data: Vec<u8>) -> &mut [u8] {
    let bytes_allocated = data.capacity();
    let result = self.arena.alloc(data);
    self.cur_bytes_allocated.set(self.cur_bytes_allocated.get() + bytes_allocated as i64);
    self.max_bytes_allocated.set(
      cmp::max(self.max_bytes_allocated.get(), self.cur_bytes_allocated.get()));
    result
  }

  /// Return the total number of bytes allocated so far
  fn cur_allocated(&self) -> i64 {
    self.cur_bytes_allocated.get()
  }

  /// Return the maximum number of bytes allocated so far
  fn max_allocated(&self) -> i64 {
    self.max_bytes_allocated.get()
  }
}

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

  #[test]
  fn test_mem_tracker() {
    let result = MemTracker::new_ptr(None);
    assert!(result.is_ok());
    let mem_tracker = result.unwrap();

    let mut buffer = ByteBuffer::new()
      .with_mem_tracker(mem_tracker.clone());
    buffer.set_data(vec![0; 10]);
    assert!(mem_tracker.cur_bytes() >= 10);
    buffer.set_data(vec![0; 20]);
    assert!(mem_tracker.cur_bytes() >= 20);

    {
      let mut buffer2 = ByteBuffer::new()
        .with_capacity(30)
        .with_mem_tracker(mem_tracker.clone());
      assert!(mem_tracker.cur_bytes() >= 50);
      buffer2.set_data(vec![0; 100]);
      assert!(mem_tracker.cur_bytes() >= 120);
    }

    assert!(mem_tracker.cur_bytes() >= 20);
    assert!(mem_tracker.max_bytes() >= 50);

    buffer.resize(40);
    assert!(mem_tracker.cur_bytes() >= 40);

    buffer.consume();
    assert!(mem_tracker.cur_bytes() <= 10);
  }

  #[test]
  fn test_byte_buffer() {
    let mut buffer = ByteBuffer::new();
    assert_eq!(buffer.size(), 0);
    assert_eq!(buffer.capacity(), 0);

    let buffer2 = ByteBuffer::new().with_capacity(40);
    assert_eq!(buffer2.size(), 0);
    assert_eq!(buffer2.capacity(), 40);

    buffer.set_data((0..5).collect());
    assert_eq!(buffer.size(), 5);

    buffer.set_data((0..20).collect());
    assert_eq!(buffer.size(), 20);

    let expected: Vec<u8> = (0..20).collect();
    {
      let data = buffer.data();
      assert_eq!(data, expected.as_slice());
    }

    buffer.resize(40);
    assert!(buffer.capacity() >= 40);

    let byte_ptr = buffer.consume();
    assert_eq!(buffer.size(), 0);
    assert_eq!(byte_ptr.slice(), expected.as_slice());

    let values: Vec<u8> = (0..30).collect();
    let _ = buffer.write(values.as_slice());
    let _ = buffer.flush();

    assert_eq!(buffer.data(), values.as_slice());
  }

  #[test]
  fn test_byte_ptr() {
    let values = (0..50).collect();
    let ptr = BytePtr::new(values);
    assert_eq!(ptr.len(), 50);
    assert_eq!(ptr.start(), 0);

    let ptr2 = ptr.all();
    assert_eq!(ptr2.len(), 50);
    assert_eq!(ptr2.start(), 0);

    let ptr3 = ptr.start_from(20);
    assert_eq!(ptr3.len(), 30);
    assert_eq!(ptr3.start(), 20);

    let ptr4 = ptr3.range(10, 10);
    assert_eq!(ptr4.len(), 10);
    assert_eq!(ptr4.start(), 30);

    let expected: Vec<u8> = (30..40).collect();
    assert_eq!(ptr4.slice(), expected.as_slice());
  }
}
<commit_msg>Adding mem tracker to BytePtr struct<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::cell::{RefCell, Cell};
use std::cmp;
use std::fmt::{Display, Result as FmtResult, Formatter};
use std::io::{Result as IoResult, Write};
use std::mem;
use std::rc::{Rc, Weak};

use arena::TypedArena;
use errors::Result;

// ----------------------------------------------------------------------
// Memory Tracker classes

type MemTrackerPtr = Rc<MemTracker>;
type WeakMemTrackerPtr = Weak<MemTracker>;

#[derive(Debug)]
pub struct MemTracker {
  cur_bytes: Cell<i64>,
  max_bytes: Cell<i64>,
  children: RefCell<Vec<MemTrackerPtr>>,
  parent: Option<WeakMemTrackerPtr>
}

impl MemTracker {
  #[inline]
  pub fn new_ptr(mut parent: Option<&mut MemTrackerPtr>) -> Result<MemTrackerPtr> {
    let mem_tracker = Rc::new(MemTracker {
      cur_bytes: Cell::new(0), max_bytes: Cell::new(0),
      children: RefCell::new(vec!()),
      parent: parent.as_mut().map(|p| Rc::downgrade(p))
    });
    if let Some(p) = parent {
      let mut parent_children = p.children.try_borrow_mut()?;
      parent_children.push(mem_tracker.clone());
    }
    Ok(mem_tracker)
  }

  pub fn cur_bytes(&self) -> i64 {
    self.cur_bytes.get()
  }

  pub fn max_bytes(&self) -> i64 {
    self.max_bytes.get()
  }

  #[inline]
  pub fn alloc(&self, num_bytes: usize) {
    let new_cur_bytes = self.cur_bytes.get() + num_bytes as i64;
    if new_cur_bytes > self.max_bytes.get() {
      self.max_bytes.set(new_cur_bytes)
    }
    self.cur_bytes.set(new_cur_bytes);
  }

  #[inline]
  pub fn dealloc(&self, num_bytes: usize) {
    assert!(self.cur_bytes.get() >= num_bytes as i64);
    self.cur_bytes.set(self.cur_bytes.get() - num_bytes as i64);
  }
}

// ----------------------------------------------------------------------
// Buffer classes

/// A resize-able byte buffer class.
///
/// Note that a byte buffer has two attributes:
/// `capacity` and `size`: the former is the total bytes allocated for
/// the buffer, while the latter is the actual bytes that have valid data.
/// Invariant: `capacity` >= `size`.
pub struct ByteBuffer {
  data: Vec<u8>,
  mem_tracker: Option<MemTrackerPtr>
}

impl ByteBuffer {
  pub fn new() -> Self {
    ByteBuffer { data: vec!(), mem_tracker: None }
  }

  pub fn with_capacity(mut self, cap: usize) -> Self {
    self.data.reserve(cap);
    self
  }

  pub fn with_mem_tracker(mut self, mc: MemTrackerPtr) -> Self {
    mc.alloc(self.data.capacity());
    self.mem_tracker = Some(mc);
    self
  }

  pub fn data(&self) -> &[u8] {
    self.data.as_slice()
  }

  #[inline]
  pub fn set_data(&mut self, new_data: Vec<u8>) {
    if self.is_mem_tracked() {
      let mc = self.mem_tracker.as_ref().unwrap();
      mc.dealloc(self.data.capacity());
      mc.alloc(new_data.capacity());
    }
    self.data = new_data;
  }

  #[inline]
  pub fn resize(&mut self, new_capacity: usize) {
    let old_capacity = self.data.capacity();
    let extra_capacity = new_capacity - old_capacity;
    if extra_capacity > 0 {
      self.data.reserve(extra_capacity);
      if let Some(ref mc) = self.mem_tracker {
        mc.alloc(self.data.capacity() - old_capacity);
      }
    }
  }

  #[inline]
  pub fn consume(&mut self) -> BytePtr {
    let old_data = mem::replace(&mut self.data, vec!());
    let mut result = BytePtr::new(old_data);
    if let Some(ref mc) = self.mem_tracker {
      result = result.with_mem_tracker(mc.clone());
    }
    result
  }

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

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

  pub fn is_mem_tracked(&self) -> bool {
    self.mem_tracker.is_some()
  }

  pub fn mem_tracker(&self) -> &MemTrackerPtr {
    self.mem_tracker.as_ref().unwrap()
  }
}

impl Write for ByteBuffer {
  fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
    // Check if we have enough capacity for the new data
    if self.data.len() + buf.len() > self.data.capacity() {
      let new_capacity = ::std::cmp::max(
        self.data.capacity() * 2, self.data.len() + buf.len());
      self.resize(new_capacity);
    }
    self.data.write(buf)
  }

  fn flush(&mut self) -> IoResult<()> {
    self.data.flush()
  }
}

impl Drop for ByteBuffer {
  fn drop(&mut self) {
    if self.is_mem_tracked() {
      let mc = self.mem_tracker.as_ref().unwrap();
      mc.dealloc(self.data.capacity());
    }
  }
}

// ----------------------------------------------------------------------
// Immutable Buffer (BytePtr) classes

/// An representation of a slice on a reference-counting and read-only byte array.
/// Sub-slices can be further created from this. The byte array will be released
/// when all slices are dropped.
#[derive(Clone, Debug)]
pub struct BytePtr {
  data: Rc<Vec<u8>>,
  start: usize,
  len: usize,
  // TODO: will this create too many references? rethink about this.
  mem_tracker: Option<MemTrackerPtr>
}

impl BytePtr {
  pub fn new(v: Vec<u8>) -> Self {
    let len = v.len();
    Self { data: Rc::new(v), start: 0, len: len, mem_tracker: None }
  }

  pub fn with_range(mut self, start: usize, len: usize) -> Self {
    assert!(start <= self.len);
    assert!(start + len <= self.len);
    self.start = start;
    self.len = len;
    self
  }

  pub fn with_mem_tracker(mut self, mc: MemTrackerPtr) -> Self {
    self.mem_tracker = Some(mc);
    self
  }

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

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

  pub fn is_mem_tracked(&self) -> bool {
    self.mem_tracker.is_some()
  }

  pub fn all(&self) -> BytePtr {
    BytePtr {
      data: self.data.clone(), start: self.start,
      len: self.len, mem_tracker: self.mem_tracker.as_ref().map(|p| p.clone())
    }
  }

  pub fn start_from(&self, start: usize) -> BytePtr {
    assert!(start <= self.len);
    BytePtr {
      data: self.data.clone(), start: self.start + start,
      len: self.len - start, mem_tracker: self.mem_tracker.as_ref().map(|p| p.clone())
    }
  }

  pub fn range(&self, start: usize, len: usize) -> BytePtr {
    assert!(start + len <= self.len);
    BytePtr {
      data: self.data.clone(), start: self.start + start,
      len: len, mem_tracker: self.mem_tracker.as_ref().map(|p| p.clone())
    }
  }

  pub fn slice(&self) -> &[u8] {
    &self.data[self.start..self.start + self.len]
  }
}

impl Display for BytePtr {
  fn fmt(&self, f: &mut Formatter) -> FmtResult {
    write!(f, "{:?}", self.data)
  }
}

impl Drop for BytePtr {
  fn drop(&mut self) {
    if self.is_mem_tracked() &&
      Rc::strong_count(&self.data) == 1 && Rc::weak_count(&self.data) == 0 {
      let mc = self.mem_tracker.as_ref().unwrap();
      mc.dealloc(self.data.capacity());
    }
  }
}

// ----------------------------------------------------------------------
// MemoryPool classes

/// A central place for managing memory.
/// NOTE: client can only acquire bytes through this API, but not releasing.
/// All the memory will be released once the instance of this trait goes out of scope.
pub struct MemoryPool {
  arena: TypedArena<Vec<u8>>,

  // NOTE: these need to be in `Cell` since all public APIs of
  // this struct take `&self`, instead of `&mut self`. Otherwise, we cannot make the
  // lifetime of outputs to be the same as this memory pool.
  cur_bytes_allocated: Cell<i64>,
  max_bytes_allocated: Cell<i64>
}

impl MemoryPool {
  pub fn new() -> Self {
    let arena = TypedArena::new();
    Self { arena: arena, cur_bytes_allocated: Cell::new(0), max_bytes_allocated: Cell::new(0) }
  }

  /// Acquire a new byte buffer of at least `size` bytes
  /// Return a unique reference to the buffer
  pub fn acquire(&self, size: usize) -> &mut [u8] {
    let buf = vec![0; size];
    self.consume(buf)
  }

  /// Consume `buf` and add it to this memory pool
  /// After the call, `buf` has the same lifetime as the pool.
  /// Return a unique reference to the consumed buffer.
  pub fn consume(&self, data: Vec<u8>) -> &mut [u8] {
    let bytes_allocated = data.capacity();
    let result = self.arena.alloc(data);
    self.cur_bytes_allocated.set(self.cur_bytes_allocated.get() + bytes_allocated as i64);
    self.max_bytes_allocated.set(
      cmp::max(self.max_bytes_allocated.get(), self.cur_bytes_allocated.get()));
    result
  }

  /// Return the total number of bytes allocated so far
  fn cur_allocated(&self) -> i64 {
    self.cur_bytes_allocated.get()
  }

  /// Return the maximum number of bytes allocated so far
  fn max_allocated(&self) -> i64 {
    self.max_bytes_allocated.get()
  }
}

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

  #[test]
  fn test_byte_buffer_mem_tracker() {
    let result = MemTracker::new_ptr(None);
    assert!(result.is_ok());
    let mem_tracker = result.unwrap();

    let mut buffer = ByteBuffer::new()
      .with_mem_tracker(mem_tracker.clone());
    buffer.set_data(vec![0; 10]);
    assert_eq!(mem_tracker.cur_bytes(), buffer.capacity() as i64);
    buffer.set_data(vec![0; 20]);
    let capacity = buffer.capacity() as i64;
    assert_eq!(mem_tracker.cur_bytes(), capacity);

    let max_capacity =
    {
      let mut buffer2 = ByteBuffer::new()
        .with_capacity(30)
        .with_mem_tracker(mem_tracker.clone());
      assert_eq!(mem_tracker.cur_bytes(), buffer2.capacity() as i64 + capacity);
      buffer2.set_data(vec![0; 100]);
      assert_eq!(mem_tracker.cur_bytes(), buffer2.capacity() as i64 + capacity);
      buffer2.capacity() as i64 + capacity
    };

    assert_eq!(mem_tracker.cur_bytes(), capacity);
    assert_eq!(mem_tracker.max_bytes(), max_capacity);

    buffer.resize(40);
    assert_eq!(mem_tracker.cur_bytes(), buffer.capacity() as i64);

    buffer.consume();
    assert_eq!(mem_tracker.cur_bytes(), buffer.capacity() as i64);
  }

  #[test]
  fn test_byte_ptr_mem_tracker() {
    let result = MemTracker::new_ptr(None);
    assert!(result.is_ok());
    let mem_tracker = result.unwrap();

    let mut buffer = ByteBuffer::new()
      .with_mem_tracker(mem_tracker.clone());
    buffer.set_data(vec![0; 60]);

    {
      let buffer_capacity = buffer.capacity() as i64;
      let buf_ptr = buffer.consume();
      assert_eq!(mem_tracker.cur_bytes(), buffer_capacity);
      {
        let buf_ptr1 = buf_ptr.all();
        {
          let _ = buf_ptr.start_from(20);
          assert_eq!(mem_tracker.cur_bytes(), buffer_capacity);
        }
        assert_eq!(mem_tracker.cur_bytes(), buffer_capacity);
        let _ = buf_ptr1.range(30, 20);
        assert_eq!(mem_tracker.cur_bytes(), buffer_capacity);
      }
      assert_eq!(mem_tracker.cur_bytes(), buffer_capacity);
    }
    assert_eq!(mem_tracker.cur_bytes(), buffer.capacity() as i64);
  }

  #[test]
  fn test_byte_buffer() {
    let mut buffer = ByteBuffer::new();
    assert_eq!(buffer.size(), 0);
    assert_eq!(buffer.capacity(), 0);

    let buffer2 = ByteBuffer::new().with_capacity(40);
    assert_eq!(buffer2.size(), 0);
    assert_eq!(buffer2.capacity(), 40);

    buffer.set_data((0..5).collect());
    assert_eq!(buffer.size(), 5);

    buffer.set_data((0..20).collect());
    assert_eq!(buffer.size(), 20);

    let expected: Vec<u8> = (0..20).collect();
    {
      let data = buffer.data();
      assert_eq!(data, expected.as_slice());
    }

    buffer.resize(40);
    assert!(buffer.capacity() >= 40);

    let byte_ptr = buffer.consume();
    assert_eq!(buffer.size(), 0);
    assert_eq!(byte_ptr.slice(), expected.as_slice());

    let values: Vec<u8> = (0..30).collect();
    let _ = buffer.write(values.as_slice());
    let _ = buffer.flush();

    assert_eq!(buffer.data(), values.as_slice());
  }

  #[test]
  fn test_byte_ptr() {
    let values = (0..50).collect();
    let ptr = BytePtr::new(values);
    assert_eq!(ptr.len(), 50);
    assert_eq!(ptr.start(), 0);

    let ptr2 = ptr.all();
    assert_eq!(ptr2.len(), 50);
    assert_eq!(ptr2.start(), 0);

    let ptr3 = ptr.start_from(20);
    assert_eq!(ptr3.len(), 30);
    assert_eq!(ptr3.start(), 20);

    let ptr4 = ptr3.range(10, 10);
    assert_eq!(ptr4.len(), 10);
    assert_eq!(ptr4.start(), 30);

    let expected: Vec<u8> = (30..40).collect();
    assert_eq!(ptr4.slice(), expected.as_slice());
  }
}
<|endoftext|>


<commit_before>//! A whitespace and comment preserving lexer designed for use in both the compiler frontend
//! and IDEs.
//!
//! The output of the tokenizer is lightweight, and only contains information about the
//! type of a [Token] and where it occurred in the source.
//!
//! ```rust,ignore
//! use crate::token::{Token, TokenType};
//! use crate::lexer;
//!
//! let tokens = lexer::tokenize("test");
//! assert_eq!(Token(TokenType::Name, 0..4), tokens[0]);
//! assert_eq!(Token(TokenType::Eof, 4..5), tokens[1]);
//! ```

use crate::token::{Token, TokenType};
use itertools::Itertools;
use logos::Lexer;
use logos::Logos;
use logos::Source;
use std::marker::PhantomData;
use std::ops::Range;

struct Tokenizer<'a> {
    lexer: Lexer<TokenType, &'a str>,
    seen_eof: bool,
}

impl<'a> Tokenizer<'a> {
    fn new(text: &'a str) -> Self {
        Tokenizer {
            lexer: TokenType::lexer(text),
            seen_eof: false,
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = (TokenType, Range<usize>);

    fn next(&mut self) -> Option<Self::Item> {
        if self.seen_eof {
            return None;
        }

        let ty = self.lexer.token;
        let range = self.lexer.range();

        self.lexer.advance();

        if ty == TokenType::Eof {
            self.seen_eof = true;
        }

        Some((ty, range))
    }
}

/// Runs the tokenizer on an input string and collects all of the output tokens
/// into a list, continuing past lex errors.
pub fn tokenize<S: AsRef<str>>(str: S) -> Vec<Token> {
    let mut tokenizer = Tokenizer::new(str.as_ref());
    let mut tokens: Vec<Token> = vec![];
    let mut iter = tokenizer.into_iter().peekable();

    while let Some((token, range)) = iter.next() {
        match token {
            TokenType::Illegal | TokenType::Whitespace | TokenType::LineComment => {
                let range = iter
                    .peeking_take_while(|(ty, _)| *ty == token)
                    .map(|(_, range)| range)
                    .last()
                    .map_or(range.clone(), |to| range.start..to.end);

                tokens.push(Token::new(token, range))
            }
            _ => tokens.push(Token::new(token, range)),
        }
    }

    tokens
}

#[test]
fn preserves_whitespace() {
    let types: Vec<TokenType> = tokenize("test abc 123")
        .into_iter()
        .map(|t| t.into())
        .collect();

    assert_eq!(
        vec![
            TokenType::Name,
            TokenType::Whitespace,
            TokenType::Name,
            TokenType::Whitespace,
            TokenType::Integer,
            TokenType::Eof,
        ],
        types
    );
}
<commit_msg>Remove ignored doctest from lexer<commit_after>//! A whitespace and comment preserving lexer designed for use in both the compiler frontend
//! and IDEs.
//!
//! The output of the tokenizer is lightweight, and only contains information about the
//! type of a [Token] and where it occurred in the source.

use crate::token::{Token, TokenType};
use itertools::Itertools;
use logos::Lexer;
use logos::Logos;
use logos::Source;
use std::marker::PhantomData;
use std::ops::Range;

struct Tokenizer<'a> {
    lexer: Lexer<TokenType, &'a str>,
    seen_eof: bool,
}

impl<'a> Tokenizer<'a> {
    fn new(text: &'a str) -> Self {
        Tokenizer {
            lexer: TokenType::lexer(text),
            seen_eof: false,
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = (TokenType, Range<usize>);

    fn next(&mut self) -> Option<Self::Item> {
        if self.seen_eof {
            return None;
        }

        let ty = self.lexer.token;
        let range = self.lexer.range();

        self.lexer.advance();

        if ty == TokenType::Eof {
            self.seen_eof = true;
        }

        Some((ty, range))
    }
}

/// Runs the tokenizer on an input string and collects all of the output tokens
/// into a list, continuing past lex errors.
pub fn tokenize<S: AsRef<str>>(str: S) -> Vec<Token> {
    let mut tokenizer = Tokenizer::new(str.as_ref());
    let mut tokens: Vec<Token> = vec![];
    let mut iter = tokenizer.into_iter().peekable();

    while let Some((token, range)) = iter.next() {
        match token {
            TokenType::Illegal | TokenType::Whitespace | TokenType::LineComment => {
                let range = iter
                    .peeking_take_while(|(ty, _)| *ty == token)
                    .map(|(_, range)| range)
                    .last()
                    .map_or(range.clone(), |to| range.start..to.end);

                tokens.push(Token::new(token, range))
            }
            _ => tokens.push(Token::new(token, range)),
        }
    }

    tokens
}

#[test]
fn preserves_whitespace() {
    let types: Vec<TokenType> = tokenize("test abc 123")
        .into_iter()
        .map(|t| t.into())
        .collect();

    assert_eq!(
        vec![
            TokenType::Name,
            TokenType::Whitespace,
            TokenType::Name,
            TokenType::Whitespace,
            TokenType::Integer,
            TokenType::Eof,
        ],
        types
    );
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

/// Figure 11.16: Using a barrier
///
/// Finding about runtime speed:
///
/// - 8 threads are really faster than 1 thread
/// - building without --release is ten times slower than when using --release
///   see my question on stackoverflow: http://stackoverflow.com/questions/42688721
/// - XorShiftRng is about 2x as fast as random() from libc
///
/// On my 4 core computer (hyperthreaded so it's 8 logical cores):
///
///            1 Thread   4 Threads   8 Threads
/// Debug      3.19s      2.63s       2.86s
/// Release    1.25s      0.41s       0.35s
///
/// Other findings:
/// - this time the book did not say at all that OSX does not implement
///   pthread_barrier_*, needed to take a C implementation I found on the
///   web
/// - the mutable statics are ugly, a bit nicer would have been to pass
///   a struct to thr_fn..
/// - merge() is really hard to understand, I guess that's typical C
///   code. Performant but hard to grasp..
///
/// $ f16-barrier | sed 's/[\.0-9]*//g'
/// sort took  seconds

extern crate libc;
extern crate rand;
extern crate apue;

use apue::my_libc::{qsort, pthread_create, random, srandom};
use libc::{c_long, c_void, c_int, c_uint, pthread_mutex_t, pthread_cond_t, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
use libc::{gettimeofday};
use std::ptr::{null, null_mut};
use std::mem::{uninitialized, size_of};
use rand::Rng;

const NTHR:usize = 4;
const NUMNUM:usize = 8_000_000;
const TNUM:usize = NUMNUM / NTHR;

pub type pthread_barrierattr_t = c_int;
#[repr(C)]
pub struct pthread_barrier_t {
    pub mutex: pthread_mutex_t,
    pub cond: pthread_cond_t,
    pub count: c_int,
    pub tripCount: c_int,
}

static mut B:pthread_barrier_t = pthread_barrier_t {
    mutex: PTHREAD_MUTEX_INITIALIZER,
    cond: PTHREAD_COND_INITIALIZER,
    count: 0,
    tripCount: 0,
};
static mut NUMS: [c_long; NUMNUM] = [0;NUMNUM];

extern "C" {
    pub fn pthread_barrier_init(barrier: *mut pthread_barrier_t,
                                attr: *const pthread_barrierattr_t,
                                count: c_uint) -> c_int;
    pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int;
    pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int;
}

unsafe extern fn thr_fn(arg:*mut c_void) -> *mut c_void {
    let idx:c_long = arg as c_long;
    qsort(NUMS.as_mut_ptr().offset(idx as isize) as _, TNUM, size_of::<c_long>(), cmp);
    pthread_barrier_wait(&mut B);
    0 as *mut c_void
}

extern fn cmp(val1: *const c_void, val2: *const c_void) -> c_int {
    unsafe {
        let val1 = val1 as *const c_long;
        let val2 = val2 as *const c_long;
        if *val1 == *val2 { 0 } else if *val1 < *val2 { -1 } else { 1 }
    }
}

unsafe fn merge() -> Vec<c_long> {
    let mut idx = [0usize;NTHR];
    let mut snums = Vec::with_capacity(NUMNUM);
    for i in 0..NTHR {
        idx[i] = i * TNUM;
    }
    for _ in 0..NUMNUM {
        let mut num = c_long::max_value();
        let mut minidx = 0;
        for i in 0..NTHR {
            if idx[i] < (i+1)*TNUM && NUMS[idx[i]] < num {
                num = NUMS[idx[i]];
                minidx = i;
            }
        }
        snums.push(NUMS[idx[minidx]]);
        idx[minidx]+=1;
    }
    snums
}

fn main() {
    unsafe {
        let (mut tid, mut start, mut end) = uninitialized();

        let mut rng = rand::XorShiftRng::new_unseeded();
        for i in 0..NUMNUM - 1 {
            NUMS[i] = rng.gen();
        }
        // create 8 threads to sort the numbers
        gettimeofday(&mut start, null_mut());
        // barrier count = num worker threads + 1 because main thread counts as 1 waiter
        pthread_barrier_init(&mut B, null(), (NTHR + 1) as _);
        for i in 0..NTHR {
            let err = pthread_create(&mut tid, null_mut(), thr_fn, (i*TNUM) as *mut c_void);
            if err != 0 {
                panic!("can't create thread, error: {}", err)
            }
        }
        pthread_barrier_wait(&mut B);
        let res = merge();
        gettimeofday(&mut end, null_mut());
        let startusec = start.tv_sec * 1_000_000 + start.tv_usec as i64;
        let endusec = end.tv_sec * 1_000_000 + end.tv_usec as i64;
        let elapsed = (endusec - startusec) as f64 / 1_000_000f64;
        println!("sort took {} seconds", elapsed);
        let mut pre = c_long::min_value();
        for n in res {
            assert!(pre <= n);
            pre = n;
        }
    }
}<commit_msg>one more comment, increased to 8 threads<commit_after>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

/// Figure 11.16: Using a barrier
///
/// Finding about runtime speed:
///
/// - 8 threads are really faster than 1 thread
/// - building without --release is ten times slower than when using --release
///   see my question on stackoverflow: http://stackoverflow.com/questions/42688721
/// - XorShiftRng is about 2x as fast as random() from libc
///
/// On my 4 core computer (hyperthreaded so it's 8 logical cores):
///
///            1 Thread   4 Threads   8 Threads
/// Debug      3.19s      2.45s       3.48s
/// Release    1.25s      0.41s       0.35s
///
/// Strange is that the debug version takes considerably longer
/// with 8 threads than with 4 threads.
///
/// Other findings:
/// - this time the book did not say at all that OSX does not implement
///   pthread_barrier_*, needed to take a C implementation I found on the
///   web
/// - the mutable statics are ugly, a bit nicer would have been to pass
///   a struct to thr_fn..
/// - merge() is really hard to understand, I guess that's typical C
///   code. Performant but hard to grasp..
///
/// $ f16-barrier | sed 's/[\.0-9]*//g'
/// sort took  seconds

extern crate libc;
extern crate rand;
extern crate apue;

use apue::my_libc::{qsort, pthread_create};
use libc::{c_long, c_void, c_int, c_uint, pthread_mutex_t, pthread_cond_t, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
use libc::{gettimeofday};
use std::ptr::{null, null_mut};
use std::mem::{uninitialized, size_of};
use rand::Rng;

const NTHR:usize = 8;
const NUMNUM:usize = 8_000_000;
const TNUM:usize = NUMNUM / NTHR;

pub type pthread_barrierattr_t = c_int;
#[repr(C)]
pub struct pthread_barrier_t {
    pub mutex: pthread_mutex_t,
    pub cond: pthread_cond_t,
    pub count: c_int,
    pub tripCount: c_int,
}

static mut B:pthread_barrier_t = pthread_barrier_t {
    mutex: PTHREAD_MUTEX_INITIALIZER,
    cond: PTHREAD_COND_INITIALIZER,
    count: 0,
    tripCount: 0,
};
static mut NUMS: [c_long; NUMNUM] = [0;NUMNUM];

extern "C" {
    pub fn pthread_barrier_init(barrier: *mut pthread_barrier_t,
                                attr: *const pthread_barrierattr_t,
                                count: c_uint) -> c_int;
    pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int;
    pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int;
}

unsafe extern fn thr_fn(arg:*mut c_void) -> *mut c_void {
    let idx:c_long = arg as c_long;
    qsort(NUMS.as_mut_ptr().offset(idx as isize) as _, TNUM, size_of::<c_long>(), cmp);
    pthread_barrier_wait(&mut B);
    0 as *mut c_void
}

extern fn cmp(val1: *const c_void, val2: *const c_void) -> c_int {
    unsafe {
        let val1 = val1 as *const c_long;
        let val2 = val2 as *const c_long;
        if *val1 == *val2 { 0 } else if *val1 < *val2 { -1 } else { 1 }
    }
}

unsafe fn merge() -> Vec<c_long> {
    let mut idx = [0usize;NTHR];
    let mut snums = Vec::with_capacity(NUMNUM);
    for i in 0..NTHR {
        idx[i] = i * TNUM;
    }
    for _ in 0..NUMNUM {
        let mut num = c_long::max_value();
        let mut minidx = 0;
        for i in 0..NTHR {
            if idx[i] < (i+1)*TNUM && NUMS[idx[i]] < num {
                num = NUMS[idx[i]];
                minidx = i;
            }
        }
        snums.push(NUMS[idx[minidx]]);
        idx[minidx]+=1;
    }
    snums
}

fn main() {
    unsafe {
        let (mut tid, mut start, mut end) = uninitialized();

        let mut rng = rand::XorShiftRng::new_unseeded();
        for i in 0..NUMNUM - 1 {
            NUMS[i] = rng.gen();
        }
        // create 8 threads to sort the numbers
        gettimeofday(&mut start, null_mut());
        // barrier count = num worker threads + 1 because main thread counts as 1 waiter
        pthread_barrier_init(&mut B, null(), (NTHR + 1) as _);
        for i in 0..NTHR {
            let err = pthread_create(&mut tid, null_mut(), thr_fn, (i*TNUM) as *mut c_void);
            if err != 0 {
                panic!("can't create thread, error: {}", err)
            }
        }
        pthread_barrier_wait(&mut B);
        let res = merge();
        gettimeofday(&mut end, null_mut());
        let startusec = start.tv_sec * 1_000_000 + start.tv_usec as i64;
        let endusec = end.tv_sec * 1_000_000 + end.tv_usec as i64;
        let elapsed = (endusec - startusec) as f64 / 1_000_000f64;
        println!("sort took {} seconds", elapsed);
        let mut pre = c_long::min_value();
        for n in res {
            assert!(pre <= n);
            pre = n;
        }
    }
}<|endoftext|>


<commit_before>// min-lldb-version: 310

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run
// gdb-command:print a
// gdb-check:$1 = 5
// gdb-command:print d
// gdb-check:$2 = 6

// === LLDB TESTS ==================================================================================

// lldb-command:run
// lldb-command:print a
// lldbg-check:(int) $0 = 5
// lldbr-check:(int) a = 5
// lldb-command:print d
// lldbg-check:(int) $1 = 6
// lldbr-check:(int) d = 6

#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]

use std::ops::Generator;
use std::pin::Pin;

fn main() {
    let mut a = 5;
    let mut b = || {
        let d = 6;
        yield;
        _zzz(); // #break
        a = d;
    };
    Pin::new(&mut b).resume();
    Pin::new(&mut b).resume();
    _zzz(); // #break
}

fn _zzz() {()}
<commit_msg>Test debuginfo of different var liveness in generators<commit_after>// min-lldb-version: 310

// compile-flags:-g

// === GDB TESTS ===================================================================================

// gdb-command:run
// gdb-command:print a
// gdb-check:$1 = 5
// gdb-command:print c
// gdb-check:$2 = 6
// gdb-command:print d
// gdb-check:$3 = 7
// gdb-command:continue
// gdb-command:print a
// gdb-check:$4 = 7
// gdb-command:print c
// gdb-check:$5 = 6
// gdb-command:print e
// gdb-check:$6 = 8
// gdb-command:continue
// gdb-command:print a
// gdb-check:$7 = 8
// gdb-command:print c
// gdb-check:$8 = 6

// === LLDB TESTS ==================================================================================

// lldb-command:run
// lldb-command:print a
// lldbg-check:(int) $0 = 5
// lldbr-check:(int) a = 5
// lldb-command:print c
// lldbg-check:(int) $1 = 6
// lldbr-check:(int) c = 6
// lldb-command:print d
// lldbg-check:(int) $2 = 7
// lldbr-check:(int) d = 7
// lldb-command:continue
// lldb-command:print a
// lldbg-check:(int) $3 = 7
// lldbr-check:(int) a = 7
// lldb-command:print c
// lldbg-check:(int) $4 = 6
// lldbr-check:(int) c = 6
// lldb-command:print e
// lldbg-check:(int) $5 = 8
// lldbr-check:(int) e = 8
// lldb-command:continue
// lldb-command:print a
// lldbg-check:(int) $6 = 8
// lldbr-check:(int) a = 8
// lldb-command:print c
// lldbg-check:(int) $7 = 6
// lldbr-check:(int) c = 6

#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]

use std::ops::Generator;
use std::pin::Pin;

fn main() {
    let mut a = 5;
    let mut b = || {
        let c = 6; // Live across multiple yield points

        let d = 7; // Live across only one yield point
        yield;
        _zzz(); // #break
        a = d;

        let e = 8; // Live across zero yield points
        _zzz(); // #break
        a = e;

        yield;
        _zzz(); // #break
        a = c;
    };
    Pin::new(&mut b).resume();
    Pin::new(&mut b).resume();
    Pin::new(&mut b).resume();
    _zzz(); // #break
}

fn _zzz() {()}
<|endoftext|>


<commit_before>use std;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::rc::{Rc, Weak};

/**
 * A trait for all values that can be handled by Operation
 */
pub trait Value: Clone + Debug {}

// TODO: use this.
pub trait ExpressionContext<V: Value + 'static> {
}

/**
 * Responds to expressions becoming total
 */
pub trait EvaluationListener<V: Value + 'static> : Debug {
    fn on_evaluated(&mut self, partial: &PartialExpression<V>, value: V);
}

/**
 * A list of operands
 */
#[derive(Debug)]
pub enum OperandList<V: Value + 'static> {
    Total(Vec<V>),
    Partial(Vec<Expression<V>>, usize)
}

impl<V: Value + 'static> OperandList<V> {
    pub fn new(operands: Vec<Expression<V>>) -> OperandList<V> {
        let num_partial = operands.iter().filter(|operand| {
            match *operand {
                &Expression::Total(_) => false,
                &Expression::Partial(_) => true,
            }
        }).count();

        if num_partial == 0 {
            OperandList::Total(operands.into_iter().map(|operand| {
                match operand {
                    Expression::Total(ref value) => value.clone(),
                    Expression::Partial(_) => unreachable!()
                }
            }).collect::<Vec<_>>())
        } else {
            OperandList::Partial(operands, num_partial)
        }

        // TODO: set child indices?
    }

    pub fn total_operands(&self) -> Option<Vec<V>> {
        match self {
            &OperandList::Total(ref v) => Some(v.clone()),
            &OperandList::Partial(ref operands, num_partial) => {
                if num_partial == 0 {
                    Some(operands.iter().map(|o| {
                        match o {
                            &Expression::Total(ref value) => value.clone(),
                            _ => unreachable!()
                        }
                    }).collect::<Vec<_>>())
                } else {
                    None
                }
            }
        }
    }
}

/**
 * Represents the "meat" of a partially-evaluated expression
 */
pub struct PartialExpression<V: Value + 'static> {
    operation: Operation<V>,
    operands: RefCell<OperandList<V>>,
    listener: Cell<Option<Weak<EvaluationListener<V>>>>,
    /// The operand's index in the parent expression
    index: usize,
}

// Since we can't derive Debug for Cell<Option<Weak<...>>>, we have to implement it manually.
impl<V: Value + 'static> Debug for PartialExpression<V> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        // TODO: implement properly.
        write!(f, "PartialExpression")
    }
}

impl<V: Value + 'static> PartialExpression<V> {
    pub fn new(op: Operation<V>, operands: OperandList<V>) -> Rc<PartialExpression<V>> {
        let exp = Rc::new(PartialExpression {
            operation: op,
            operands: RefCell::new(operands),
            listener: Cell::new(None),
            index: 0,
        });

        // Set operands' listeners.
        {
            let operands = &*exp.operands.borrow();
            if let &OperandList::Partial(ref operands, _) = operands {
                for operand in operands.iter() {
                    if let &Expression::Partial(ref oi) = operand {
                        oi.listener.set(Some(Rc::<PartialExpression<V>>::downgrade(&exp)));
                    }
                }
            }
        }

        exp
    }
}

impl<V: Value + 'static> EvaluationListener<V> for PartialExpression<V> {
    fn on_evaluated(&mut self, partial: &PartialExpression<V>, value: V) {
        let operands = &mut *self.operands.borrow_mut();
        if let &mut OperandList::Partial(ref mut operands, ref mut num_partial) = operands {
            if let Expression::Partial(_) = operands[partial.index] {
                operands[partial.index] = Expression::Total(value);
                *num_partial -= 1;
                // TODO: do something when we have no partials left.
            }
        }
    }
}

/**
 * An expression is either a value or an operation applied to a list of expressions.
 */
#[derive(Debug)]
pub enum Expression<V: Value + 'static> {
    /// An expression that has been totally evaluated
    Total(V),
    /// An expression which has not been totally evaluated
    Partial(Rc<PartialExpression<V>>),
}

impl<V: Value + 'static> Expression<V> {
    /**
     * Builds an Expression from an Operation and a list of Operands
     */
    pub fn from_op(op: Operation<V>, operands: Vec<Expression<V>>) -> Expression<V> {
        let op_list = OperandList::new(operands);

        if let OperandList::Total(operand_values) = op_list {
            let eval_result = op.evaluate(&operand_values);

            return match eval_result {
                EvaluationResult::Total(val) => {
                    Expression::Total(val)
                }
                EvaluationResult::Pending => {
                    let partial = PartialExpression::new(op, OperandList::Total(operand_values));
                    Expression::Partial(partial)
                }
            }
        }

        Expression::Partial(PartialExpression::new(op, op_list))
    }

    pub fn from_value(value: V) -> Rc<Expression<V>> {
        Rc::new(Expression::Total(value))
    }
}

pub enum EvaluationResult<V: Value + 'static> {
    Total(V),
    Pending
}

// TODO: remove this type?
pub type Evaluator<V: Value + 'static> = fn(&[V]) -> EvaluationResult<V>;

// TODO: create an Arguments type? (useful for eager ops)
// TODO: handle lazy ops. (Consuming a stream of ProtoNodes *might* be a workable solution).
#[derive(Copy)]
pub struct Operation<V: Value + 'static> {
    name: &'static str,
    evaluator: Evaluator<V>,
}

impl<V: Value + 'static> Debug for Operation<V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Operation {{ name: {} }}", self.name)
    }
}

impl<V: Value + 'static> Operation<V> {
    pub const fn new(name: &'static str, evaluator: Evaluator<V>) -> Operation<V> {
        Operation { name: name, evaluator: evaluator }
    }

    pub fn evaluate(&self, operands: &Vec<V>) -> EvaluationResult<V> {
        (self.evaluator)(operands)
    }
}

// Manual implementation required to get around Rust bug #28229
impl<V: Value + 'static> Clone for Operation<V> {
    fn clone(&self) -> Operation<V> {
        Operation {
            name: self.name,
            evaluator: self.evaluator
        }
    }
}

pub struct OperationGroup<V: Value + 'static> {
    map: HashMap<Box<str>, Operation<V>>,
}

impl<V: Value + 'static> OperationGroup<V> {
    pub const fn new(map: HashMap<Box<str>, Operation<V>>) -> OperationGroup<V> {
        OperationGroup { map: map }
    }

    pub fn get(&self, name: &str) -> Option<&Operation<V>> {
        self.map.get(name)
    }
}
<commit_msg>Implement upward propagation of on_evaluated calls<commit_after>use std;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::rc::{Rc, Weak};

/**
 * A trait for all values that can be handled by Operation
 */
pub trait Value: Clone + Debug {}

// TODO: use this.
pub trait ExpressionContext<V: Value + 'static> {
}

/**
 * Responds to expressions becoming total
 */
pub trait EvaluationListener<V: Value + 'static> : Debug {
    fn on_evaluated(&self, partial: &PartialExpression<V>, value: V);
}

/**
 * A list of operands
 */
#[derive(Debug)]
pub enum OperandList<V: Value + 'static> {
    Total(Vec<V>),
    Partial(Vec<Expression<V>>, usize)
}

impl<V: Value + 'static> OperandList<V> {
    pub fn new(operands: Vec<Expression<V>>) -> OperandList<V> {
        let num_partial = operands.iter().filter(|operand| {
            match *operand {
                &Expression::Total(_) => false,
                &Expression::Partial(_) => true,
            }
        }).count();

        if num_partial == 0 {
            OperandList::Total(operands.into_iter().map(|operand| {
                match operand {
                    Expression::Total(ref value) => value.clone(),
                    Expression::Partial(_) => unreachable!()
                }
            }).collect::<Vec<_>>())
        } else {
            // Set children's indices
            let mut index: usize = 0;
            for operand in operands.iter() {
                if let &Expression::Partial(ref partial) = operand {
                    partial.index.set(index);
                }
                index += 1;
            }

            OperandList::Partial(operands, num_partial)
        }
    }
}

/**
 * Represents the "meat" of a partially-evaluated expression
 */
pub struct PartialExpression<V: Value + 'static> {
    operation: Operation<V>,
    operands: RefCell<OperandList<V>>,
    listener: Cell<Option<Weak<EvaluationListener<V>>>>,
    /**
     * The operand's index in the parent expression
     *
     * Will be set when the PartialExpression is placed in an OperandList
     */
    index: Cell<usize>,
}

// Since we can't derive Debug for Cell<Option<Weak<...>>>, we have to implement it manually.
impl<V: Value + 'static> Debug for PartialExpression<V> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
        // TODO: implement properly.
        write!(f, "PartialExpression")
    }
}

impl<V: Value + 'static> PartialExpression<V> {
    pub fn new(op: Operation<V>, operands: OperandList<V>) -> Rc<PartialExpression<V>> {
        let exp = Rc::new(PartialExpression {
            operation: op,
            operands: RefCell::new(operands),
            listener: Cell::new(None),
            index: Cell::new(0),
        });

        // Set operands' listeners.
        {
            let operands = &*exp.operands.borrow();
            if let &OperandList::Partial(ref operands, _) = operands {
                for operand in operands.iter() {
                    if let &Expression::Partial(ref oi) = operand {
                        oi.listener.set(Some(Rc::<PartialExpression<V>>::downgrade(&exp)));
                    }
                }
            }
        }

        exp
    }
}

impl<V: Value + 'static> EvaluationListener<V> for PartialExpression<V> {
    fn on_evaluated(&self, partial: &PartialExpression<V>, value: V) {
        let operand_list = &mut *self.operands.borrow_mut();

        let mut eval_result = EvaluationResult::Pending;
        // If the OperandList becomes total, the new total list will be stored here.
        let mut new_operands: Option<OperandList<V>> = None;

        if let &mut OperandList::Partial(ref mut operands, ref mut num_partial) = operand_list {
            if let Expression::Partial(_) = operands[partial.index.get()] {
                operands[partial.index.get()] = Expression::Total(value);
                *num_partial -= 1;

                // Are we ready to evaluate?
                if *num_partial == 0 {
                    let total_operands = operands.iter().map(|o| {
                        match o {
                            &Expression::Total(ref value) => value.clone(),
                            _ => unreachable!()
                        }
                    }).collect::<Vec<_>>();

                    eval_result = self.operation.evaluate(&total_operands);
                    new_operands = Some(OperandList::Total(total_operands));
                }
            }
        }

        if let Some(operands) = new_operands {
            *operand_list = operands;
        }

        if let EvaluationResult::Total(value) = eval_result {
            // We know that there won't be a mutable borrow here because no one else should
            // be setting the listener.
            let maybe_listener = unsafe{ &*self.listener.as_ptr() };
            if let &Some(ref weak_listener) = maybe_listener {
                if let Some(ref listener) = weak_listener.upgrade() {
                    listener.on_evaluated(&self, value);
                }
            }
        }
    }
}

/**
 * An expression is either a value or an operation applied to a list of expressions.
 */
#[derive(Debug)]
pub enum Expression<V: Value + 'static> {
    /// An expression that has been totally evaluated
    Total(V),
    /// An expression which has not been totally evaluated
    Partial(Rc<PartialExpression<V>>),
}

impl<V: Value + 'static> Expression<V> {
    /**
     * Builds an Expression from an Operation and a list of Operands
     */
    pub fn from_op(op: Operation<V>, operands: Vec<Expression<V>>) -> Expression<V> {
        let op_list = OperandList::new(operands);

        if let OperandList::Total(operand_values) = op_list {
            let eval_result = op.evaluate(&operand_values);

            return match eval_result {
                EvaluationResult::Total(val) => {
                    Expression::Total(val)
                }
                EvaluationResult::Pending => {
                    let partial = PartialExpression::new(op, OperandList::Total(operand_values));
                    Expression::Partial(partial)
                }
            }
        }

        Expression::Partial(PartialExpression::new(op, op_list))
    }

    pub fn from_value(value: V) -> Rc<Expression<V>> {
        Rc::new(Expression::Total(value))
    }
}

pub enum EvaluationResult<V: Value + 'static> {
    Total(V),
    Pending
}

// TODO: create an Arguments type? (useful for eager ops)
// TODO: handle lazy ops. (Consuming a stream of ProtoNodes *might* be a workable solution).
#[derive(Copy)]
pub struct Operation<V: Value + 'static> {
    name: &'static str,
    evaluator: fn(&[V]) -> EvaluationResult<V>,
}

impl<V: Value + 'static> Debug for Operation<V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Operation {{ name: {} }}", self.name)
    }
}

impl<V: Value + 'static> Operation<V> {
    pub const fn new(name: &'static str, evaluator: fn(&[V]) -> EvaluationResult<V>) -> Operation<V> {
        Operation { name: name, evaluator: evaluator }
    }

    pub fn evaluate(&self, operands: &Vec<V>) -> EvaluationResult<V> {
        (self.evaluator)(operands)
    }
}

// Manual implementation required to get around Rust bug #28229
impl<V: Value + 'static> Clone for Operation<V> {
    fn clone(&self) -> Operation<V> {
        Operation {
            name: self.name,
            evaluator: self.evaluator
        }
    }
}

pub struct OperationGroup<V: Value + 'static> {
    map: HashMap<Box<str>, Operation<V>>,
}

impl<V: Value + 'static> OperationGroup<V> {
    pub const fn new(map: HashMap<Box<str>, Operation<V>>) -> OperationGroup<V> {
        OperationGroup { map: map }
    }

    pub fn get(&self, name: &str) -> Option<&Operation<V>> {
        self.map.get(name)
    }
}
<|endoftext|>