<commit_before>/*!

Various BWT-DC compression models

*/

use compress::entropy::ari;

/// Old Dark-0.51 model
pub mod dark;
/// Original BWT-DC compression model
pub mod exp;
/// A attempt to reproduce YBS model
pub mod ybs;

pub type Distance = u32;
pub type Symbol = u8;

/// A generic BWT-DC output coding model
pub trait DistanceModel {
	/// Create a new default instance
	fn new_default() -> Self;
	/// Reset current estimations
	fn reset(&mut self);
	/// Encode a distance for some symbol
	fn encode<W: Writer>(&mut self, Distance, Symbol, &mut ari::Encoder<W>);
	/// Decode a distance for some symbol
	fn decode<R: Reader>(&mut self, Symbol, &mut ari::Decoder<R>) -> Distance;
}

#[cfg(test)]
pub mod test {
	use std::{io, rand, vec};
	use compress::entropy::ari;
	use super::{Distance, DistanceModel};
	use super::Symbol;

	fn roundtrip<M: DistanceModel>(input: &[(Symbol,Distance)]) {
		let mut m: M = DistanceModel::new_default();
		let mut eh = ari::Encoder::new(io::MemWriter::new());
		m.reset();
		for &(sym,dist) in input.iter() {
			debug!("Encode: {}", dist);
			m.encode(dist, sym, &mut eh);
		}
		let (mem, err) = eh.finish();
		err.unwrap();
		let buffer = mem.unwrap();
		m.reset();
		let mut dh = ari::Decoder::new(io::BufReader::new(buffer));
		dh.start().unwrap();
		for &(sym,dist) in input.iter() {
			let d2 = m.decode(sym, &mut dh);
			debug!("Actual: {}, Decoded: {}", dist, d2);
			assert_eq!(d2, dist);
		}
	}

	fn gen_data(size: uint, max_dist: Distance) -> ~[(Symbol,Distance)] {
		use std::rand::Rng;
		let mut rng = rand::rng();
		vec::from_fn(size, |_| {
			(rng.gen::<Symbol>(), rng.gen_range(0, max_dist))
		})
	}

	fn roundtrips<M: DistanceModel>() {
		roundtrip::<M>([(1,1),(2,2),(3,3),(4,4)]);
		roundtrip::<M>(gen_data(1000,200));
	}

	#[test]
	fn roundtrips_dark() {
		roundtrips::<super::dark::Model>();
	}

	#[test]
	fn roundtrips_exp() {
		roundtrips::<super::exp::Model>();
	}

	#[test]
	fn roundtrips_ybs() {
		roundtrips::<super::ybs::Model>();
	}
}
<commit_msg>Implemented the Raw coding model.<commit_after>/*!

Various BWT-DC compression models

*/

use compress::entropy::ari;

/// Old Dark-0.51 model
pub mod dark;
/// Original BWT-DC compression model
pub mod exp;
/// A attempt to reproduce YBS model
pub mod ybs;

pub type Distance = u32;
pub type Symbol = u8;

/// A generic BWT-DC output coding model
pub trait DistanceModel {
	/// Create a new default instance
	fn new_default() -> Self;
	/// Reset current estimations
	fn reset(&mut self);
	/// Encode a distance for some symbol
	fn encode<W: Writer>(&mut self, Distance, Symbol, &mut ari::Encoder<W>);
	/// Decode a distance for some symbol
	fn decode<R: Reader>(&mut self, Symbol, &mut ari::Decoder<R>) -> Distance;
}

/// Raw (Dist,Sym) pairs output
pub struct Raw;

impl ari::Model for Raw {
	fn get_range(&self, value: ari::Value) -> (ari::Border, ari::Border) {
		(value as ari::Border, value as ari::Border+1)
	}
	fn find_value(&self, offset: ari::Border) -> (ari::Value, ari::Border, ari::Border) {
		(offset as ari::Value, offset, offset+1)
	}
	fn get_denominator(&self) -> ari::Border {
		0x100
	}
}

impl DistanceModel for Raw {
	fn new_default() -> Raw {Raw}
	fn reset(&mut self) {}

	fn encode<W: Writer>(&mut self, d: Distance, s: Symbol, enc: &mut ari::Encoder<W>) {
		enc.encode(s as ari::Value, &Raw).unwrap();
		enc.encode(((d>> 0)&0xFF) as ari::Value, &Raw).unwrap();
		enc.encode(((d>> 8)&0xFF) as ari::Value, &Raw).unwrap();
		enc.encode(((d>>16)&0xFF) as ari::Value, &Raw).unwrap();
		enc.encode(((d>>24)&0xFF) as ari::Value, &Raw).unwrap();
	}

	fn decode<R: Reader>(&mut self, s: Symbol, dec: &mut ari::Decoder<R>) -> Distance {
		let sym = dec.decode(&Raw).unwrap() as Symbol;
		assert_eq!(s, sym);
		let d0 = dec.decode(&Raw).unwrap() as Distance;
		let d1 = dec.decode(&Raw).unwrap() as Distance;
		let d2 = dec.decode(&Raw).unwrap() as Distance;
		let d3 = dec.decode(&Raw).unwrap() as Distance;
		d0 + (d1<<8) + (d2<<16) + (d3<<24)
	}
}

#[cfg(test)]
pub mod test {
	use std::{io, rand, vec};
	use compress::entropy::ari;
	use super::{Distance, DistanceModel};
	use super::Symbol;

	fn roundtrip<M: DistanceModel>(input: &[(Symbol,Distance)]) {
		let mut m: M = DistanceModel::new_default();
		let mut eh = ari::Encoder::new(io::MemWriter::new());
		m.reset();
		for &(sym,dist) in input.iter() {
			debug!("Encode: {}", dist);
			m.encode(dist, sym, &mut eh);
		}
		let (mem, err) = eh.finish();
		err.unwrap();
		let buffer = mem.unwrap();
		m.reset();
		let mut dh = ari::Decoder::new(io::BufReader::new(buffer));
		dh.start().unwrap();
		for &(sym,dist) in input.iter() {
			let d2 = m.decode(sym, &mut dh);
			debug!("Actual: {}, Decoded: {}", dist, d2);
			assert_eq!(d2, dist);
		}
	}

	fn gen_data(size: uint, max_dist: Distance) -> ~[(Symbol,Distance)] {
		use std::rand::Rng;
		let mut rng = rand::rng();
		vec::from_fn(size, |_| {
			(rng.gen::<Symbol>(), rng.gen_range(0, max_dist))
		})
	}

	fn roundtrips<M: DistanceModel>() {
		roundtrip::<M>([(1,1),(2,2),(3,3),(4,4)]);
		roundtrip::<M>(gen_data(1000,200));
	}

	#[test]
	fn roundtrips_raw() {
		roundtrips::<super::Raw>();
	}

	#[test]
	fn roundtrips_dark() {
		roundtrips::<super::dark::Model>();
	}

	#[test]
	fn roundtrips_exp() {
		roundtrips::<super::exp::Model>();
	}

	#[test]
	fn roundtrips_ybs() {
		roundtrips::<super::ybs::Model>();
	}
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::FnBox;
use alloc::heap;
use arch::cpu;
use arch::isr;
use arch::thread;
use collections::vec_deque::VecDeque;
use core::mem;
use core::slice;
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use deferred::Deferred;
use libc::{self,jmp_buf};
use mutex::Mutex;
use phys_mem::PhysicalBitmap;
use prelude::*;
use process::Process;
use ptr::Align;
use singleton::Singleton;
use virt_mem::VirtualTree;

static SCHEDULER: Singleton<Mutex<SchedulerState>> = Singleton::new();

fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

struct HWToken {
    process: Arc<Process>,
    stack_ptr: *mut u8
}

impl HWToken {
    pub unsafe fn switch(self) {
        self.process.switch();
        isr::set_kernel_stack(self.stack_ptr);
    }
}

struct Thread {
    _id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>,
    exited: Deferred<i32>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            _id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process,
            exited: Deferred::new()
        }
    }

    pub fn hw_token(&mut self) -> HWToken {
        HWToken {
            process: self.process.clone(),
            stack_ptr: Align::down(unsafe { self.stack.as_mut_ptr().offset(self.stack.len() as isize) }, 16)
        }
    }
}

pub struct BlockedThread(jmp_buf, Thread);

struct SchedulerState {
    current: Thread,
    threads: VecDeque<BlockedThread>,
    garbage_stacks: Vec<&'static mut [u8]>
}

impl Drop for SchedulerState {
    fn drop(&mut self) {
        let garbage_stacks = mem::replace(&mut self.garbage_stacks, Vec::new());

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub fn with_scheduler<F: FnOnce()>(f: F) {
    let phys = Arc::new(PhysicalBitmap::parse_multiboot());
    let kernel_virt = Arc::new(VirtualTree::for_kernel());
    let idle_process = Arc::new(Process::new(phys, kernel_virt).unwrap());

    let state = SchedulerState {
        current: Thread::new(idle_process.clone(), &mut []),
        threads: VecDeque::new(),
        garbage_stacks: Vec::new()
    };

    let _d = SCHEDULER.register(Mutex::new(state));
    unsafe { idle_process.switch() };
    f()
}

fn current_sched() -> &'static Mutex<SchedulerState> {
    SCHEDULER.get().expect("no Scheduler registered")
}

macro_rules! lock_sched {
    () => (lock!(current_sched()))
}

pub fn current_process() -> Arc<Process> {
    lock_sched!().current.process.clone()
}

pub fn block<F: FnOnce(BlockedThread)>(park: F) -> bool {
    let mut state = lock_sched!();
    match state.threads.pop_front() {
        Some(BlockedThread(new_jmp_buf, mut new_current)) => {
            let switch = {
                let new_token = new_current.hw_token();
                let old_current = mem::replace(&mut state.current, new_current);
                mem::drop(state);

                move |old_jmp_buf| {
                    park(BlockedThread(old_jmp_buf, old_current));
                    assert!(cpu::interrupts_enabled(), "current thread is holding a spinlock and it's about to be blocked");
                    unsafe {
                        new_token.switch();
                        libc::longjmp(&new_jmp_buf, 1)
                    }
                }
            };

            match setjmp() {
                Some(old_jmp_buf) => switch(old_jmp_buf),
                None => { mem::forget(switch); true }
            }
        },

        None => false
    }
}

impl BlockedThread {
    pub fn resume(self) {
        let mut state = lock_sched!();
        state.threads.push_back(self);
    }
}

pub fn schedule() {
    block(move |thread| thread.resume());
}

pub fn exit(code: i32) -> ! {
    let exited = lock_sched!().current.exited.clone();
    exited.resolve(code);

    block(move |thread| {
        let mut state = lock_sched!();
        state.garbage_stacks.push(thread.1.stack);
    });

    panic!("exit: no more threads")
}

fn spawn_inner<'a>(process: Arc<Process>, start: Box<FnBox() + 'a>) -> Deferred<i32> {
    let stack_len = 4096;
    let stack_base_ptr = unsafe { heap::allocate(stack_len, 16) };
    let b: Box<FnBox() + 'a> = Box::new(start);
    let jmp_buf = thread::new_jmp_buf(b, unsafe { stack_base_ptr.offset(stack_len as isize) });
    let thread = Thread::new(process, unsafe { slice::from_raw_parts_mut(stack_base_ptr, stack_len) });
    let exited = thread.exited.clone();
    BlockedThread(jmp_buf, thread).resume();
    exited
}

pub fn spawn_user_mode(pc: *const u8, stack: &mut [u8]) -> Deferred<i32> {
    let stack_ptr = stack.as_mut_ptr();
    let stack_len = stack.len();

    let start = move || {
        unsafe {
            thread::jmp_user_mode(pc, stack_ptr.offset(stack_len as isize))
        }
        // TODO: free stack
    };

    let process = lock_sched!().current.process.clone();
    spawn_inner(process, Box::new(start))
}

pub fn spawn_remote<T>(process: Arc<Process>, start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let start = || { exit(start()) };
    spawn_inner(process, Box::new(start))
}

pub fn spawn<T>(start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let process = lock_sched!().current.process.clone();
    spawn_remote(process, start)
}

#[cfg(feature = "test")]
pub mod test {
    use prelude::*;
    use super::*;

    test! {
        fn can_spawn_exit_thread() {
            with_scheduler(|| {
                let d = spawn(|| 123);
                assert_eq!(123, d.get());
            });
        }

        fn can_spawn_exit_two_threads() {
            with_scheduler(|| {
                let d1 = spawn(|| 456);
                let d2 = spawn(|| 789);
                assert_eq!(456, d1.get());
                assert_eq!(789, d2.get());
            });
        }

        fn can_closure() {
            with_scheduler(|| {
                let s = String::from("hello");
                let d = spawn(move || (s + &" world").len() as i32);
                assert_eq!(11, d.get());
            });
        }

        fn threads_can_spawn_more_threads() {
            with_scheduler(|| {
                let thread2_fn = || 1234;

                let thread1_fn = {
                    || {
                        let d = spawn(thread2_fn);
                        d.get() * 2
                    }
                };

                let d = spawn(thread1_fn);
                assert_eq!(1234 * 2, d.get());
            });
        }
    }
}
<commit_msg>Not using thread::spawn_user_mode after all<commit_after>use alloc::arc::Arc;
use alloc::boxed::FnBox;
use alloc::heap;
use arch::cpu;
use arch::isr;
use arch::thread;
use collections::vec_deque::VecDeque;
use core::mem;
use core::slice;
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use deferred::Deferred;
use libc::{self,jmp_buf};
use mutex::Mutex;
use phys_mem::PhysicalBitmap;
use prelude::*;
use process::Process;
use ptr::Align;
use singleton::Singleton;
use virt_mem::VirtualTree;

static SCHEDULER: Singleton<Mutex<SchedulerState>> = Singleton::new();

fn setjmp() -> Option<jmp_buf> {
    unsafe {
        let mut jmp_buf = mem::uninitialized();
        if libc::setjmp(&mut jmp_buf) == 0 {
            Some(jmp_buf)
        } else {
            None
        }
    }
}

struct HWToken {
    process: Arc<Process>,
    stack_ptr: *mut u8
}

impl HWToken {
    pub unsafe fn switch(self) {
        self.process.switch();
        isr::set_kernel_stack(self.stack_ptr);
    }
}

struct Thread {
    _id: usize,
    stack: &'static mut [u8],
    process: Arc<Process>,
    exited: Deferred<i32>
}

impl Thread {
    pub fn new(process: Arc<Process>, stack: &'static mut [u8]) -> Thread {
        static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT;
        Thread {
            _id: NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed),
            stack: stack,
            process: process,
            exited: Deferred::new()
        }
    }

    pub fn hw_token(&mut self) -> HWToken {
        HWToken {
            process: self.process.clone(),
            stack_ptr: Align::down(unsafe { self.stack.as_mut_ptr().offset(self.stack.len() as isize) }, 16)
        }
    }
}

pub struct BlockedThread(jmp_buf, Thread);

struct SchedulerState {
    current: Thread,
    threads: VecDeque<BlockedThread>,
    garbage_stacks: Vec<&'static mut [u8]>
}

impl Drop for SchedulerState {
    fn drop(&mut self) {
        let garbage_stacks = mem::replace(&mut self.garbage_stacks, Vec::new());

        for stack in garbage_stacks {
            unsafe { heap::deallocate(stack.as_mut_ptr(), stack.len(), 16) };
        }
    }
}

pub fn with_scheduler<F: FnOnce()>(f: F) {
    let phys = Arc::new(PhysicalBitmap::parse_multiboot());
    let kernel_virt = Arc::new(VirtualTree::for_kernel());
    let idle_process = Arc::new(Process::new(phys, kernel_virt).unwrap());

    let state = SchedulerState {
        current: Thread::new(idle_process.clone(), &mut []),
        threads: VecDeque::new(),
        garbage_stacks: Vec::new()
    };

    let _d = SCHEDULER.register(Mutex::new(state));
    unsafe { idle_process.switch() };
    f()
}

fn current_sched() -> &'static Mutex<SchedulerState> {
    SCHEDULER.get().expect("no Scheduler registered")
}

macro_rules! lock_sched {
    () => (lock!(current_sched()))
}

pub fn current_process() -> Arc<Process> {
    lock_sched!().current.process.clone()
}

pub fn block<F: FnOnce(BlockedThread)>(park: F) -> bool {
    let mut state = lock_sched!();
    match state.threads.pop_front() {
        Some(BlockedThread(new_jmp_buf, mut new_current)) => {
            let switch = {
                let new_token = new_current.hw_token();
                let old_current = mem::replace(&mut state.current, new_current);
                mem::drop(state);

                move |old_jmp_buf| {
                    park(BlockedThread(old_jmp_buf, old_current));
                    assert!(cpu::interrupts_enabled(), "current thread is holding a spinlock and it's about to be blocked");
                    unsafe {
                        new_token.switch();
                        libc::longjmp(&new_jmp_buf, 1)
                    }
                }
            };

            match setjmp() {
                Some(old_jmp_buf) => switch(old_jmp_buf),
                None => { mem::forget(switch); true }
            }
        },

        None => false
    }
}

impl BlockedThread {
    pub fn resume(self) {
        let mut state = lock_sched!();
        state.threads.push_back(self);
    }
}

pub fn schedule() {
    block(move |thread| thread.resume());
}

pub fn exit(code: i32) -> ! {
    let exited = lock_sched!().current.exited.clone();
    exited.resolve(code);

    block(move |thread| {
        let mut state = lock_sched!();
        state.garbage_stacks.push(thread.1.stack);
    });

    panic!("exit: no more threads")
}

fn spawn_inner<'a>(process: Arc<Process>, start: Box<FnBox() + 'a>) -> Deferred<i32> {
    let stack_len = 4096;
    let stack_base_ptr = unsafe { heap::allocate(stack_len, 16) };
    let b: Box<FnBox() + 'a> = Box::new(start);
    let jmp_buf = thread::new_jmp_buf(b, unsafe { stack_base_ptr.offset(stack_len as isize) });
    let thread = Thread::new(process, unsafe { slice::from_raw_parts_mut(stack_base_ptr, stack_len) });
    let exited = thread.exited.clone();
    BlockedThread(jmp_buf, thread).resume();
    exited
}

pub fn spawn_remote<T>(process: Arc<Process>, start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let start = || { exit(start()) };
    spawn_inner(process, Box::new(start))
}

pub fn spawn<T>(start: T) -> Deferred<i32> where T : FnOnce() -> i32 {
    let process = lock_sched!().current.process.clone();
    spawn_remote(process, start)
}

#[cfg(feature = "test")]
pub mod test {
    use prelude::*;
    use super::*;

    test! {
        fn can_spawn_exit_thread() {
            with_scheduler(|| {
                let d = spawn(|| 123);
                assert_eq!(123, d.get());
            });
        }

        fn can_spawn_exit_two_threads() {
            with_scheduler(|| {
                let d1 = spawn(|| 456);
                let d2 = spawn(|| 789);
                assert_eq!(456, d1.get());
                assert_eq!(789, d2.get());
            });
        }

        fn can_closure() {
            with_scheduler(|| {
                let s = String::from("hello");
                let d = spawn(move || (s + &" world").len() as i32);
                assert_eq!(11, d.get());
            });
        }

        fn threads_can_spawn_more_threads() {
            with_scheduler(|| {
                let thread2_fn = || 1234;

                let thread1_fn = {
                    || {
                        let d = spawn(thread2_fn);
                        d.get() * 2
                    }
                };

                let d = spawn(thread1_fn);
                assert_eq!(1234 * 2, d.get());
            });
        }
    }
}
<|endoftext|>


<commit_before>//! Various object detection algorithms, such as Haar feature-based cascade
//! classifier for object detection and histogram of oriented gradients (HOG).

use libc::{c_double, c_char, c_int};
use std::ffi::CString;
use std::path::Path;
use std::vec::Vec;
use super::core::*;

/// An object detect trait.
pub trait ObjectDetect {
    /// Detects the object inside this image and returns a list of detections
    /// with their confidence.
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)>;
}

/// The opaque type for C
enum CCascadeClassifier {}

/// Cascade classifier class for object detection.
#[derive(Debug)]
pub struct CascadeClassifier {
    inner: *mut CCascadeClassifier,
}

/// We can safely send the classifier (a mutable pointer) to a different thread
unsafe impl Send for CascadeClassifier {}

extern "C" {
    fn cv_cascade_classifier_new() -> *mut CCascadeClassifier;
    fn cv_cascade_classifier_load(cc: *mut CCascadeClassifier, p: *const c_char) -> bool;
    fn cv_cascade_classifier_drop(p: *mut CCascadeClassifier);
    fn cv_cascade_classifier_detect(cc: *mut CCascadeClassifier,
                                    cmat: *mut CMat,
                                    vec_of_rect: *mut CVecOfRect,
                                    scale_factor: c_double,
                                    min_neighbors: c_int,
                                    flags: c_int,
                                    min_size: Size2i,
                                    max_size: Size2i);
}

impl ObjectDetect for CascadeClassifier {
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)> {
        self.detect_multiscale(image).into_iter().map(|r| (r, 0f64)).collect::<Vec<_>>()
    }
}

impl CascadeClassifier {
    /// Creates a cascade classifier, uninitialized. Before use, call load.
    pub fn new() -> CascadeClassifier {
        CascadeClassifier { inner: unsafe { cv_cascade_classifier_new() } }
    }

    /// Creates a cascade classifier using the model specified.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Option<Self> {
        let cc = CascadeClassifier::new();
        if cc.load(path) { Some(cc) } else { None }
    }

    /// Loads the classifier model from a path.
    pub fn load<P: AsRef<Path>>(&self, path: P) -> bool {
        let s = CString::new(path.as_ref()
                .to_str()
                .expect("only UTF-8 path is allowed"))
            .expect("failed to create CString to load cascade");
        unsafe { cv_cascade_classifier_load(self.inner, (&s).as_ptr()) }
    }

    /// The default detection uses scale factor 1.1, minNeighbors 3, no min size
    /// or max size.
    pub fn detect_multiscale(&self, mat: &Mat) -> Vec<Rect> {
        self.detect_with_params(mat, 1.1, 3, Size2i::default(), Size2i::default())
    }

    /// Detects the object using parameters specified.
    ///
    /// * `mat` - Matrix of the type CV_8U containing an image where objects are
    ///   detected.
    /// * `scale_factor` - Parameter specifying how much the image size is
    ///   reduced at each image scale.
    /// * `min_neighbors` - Parameter specifying how many neighbors each
    ///   candidate rectangle should have to retain it.
    /// * `min_size` - Minimum possible object size. Objects smaller than that
    ///   are ignored.
    /// * `max_size` - Maximum possible object size. Objects larger than that
    ///   are ignored
    ///
    /// OpenCV has a parameter (`flags`) that's not used at all.
    pub fn detect_with_params(&self,
                              mat: &Mat,
                              scale_factor: f32,
                              min_neighbors: i32,
                              min_size: Size2i,
                              max_size: Size2i)
                              -> Vec<Rect> {
        let mut c_result = CVecOfRect::default();
        unsafe {
            cv_cascade_classifier_detect(self.inner,
                                         mat.inner,
                                         &mut c_result,
                                         scale_factor as c_double,
                                         min_neighbors,
                                         0,
                                         min_size,
                                         max_size)
        }
        c_result.rustify()
    }
}

impl Drop for CascadeClassifier {
    fn drop(&mut self) {
        unsafe {
            cv_cascade_classifier_drop(self.inner);
        }
    }
}

#[derive(Debug, Clone, Copy)]
/// Opaque type for C/C++ SvmDetector object
pub enum CSvmDetector {}

/// SvmDetector
#[derive(Debug)]
pub struct SvmDetector {
    /// Pointer to the inner data structure
    pub inner: *mut CSvmDetector,
}

extern "C" {
    fn cv_hog_default_people_detector() -> *mut CSvmDetector;
    fn cv_hog_daimler_people_detector() -> *mut CSvmDetector;
    fn cv_hog_detector_drop(d: *mut CSvmDetector);
}

impl SvmDetector {
    /// The built-in people detector.
    ///
    /// The size of the default people detector is 64x128, that mean that the
    /// people you would want to detect have to be atleast 64x128.
    pub fn default_people_detector() -> SvmDetector {
        SvmDetector { inner: unsafe { cv_hog_default_people_detector() } }
    }

    /// Returns the Daimler people detector.
    pub fn daimler_people_detector() -> SvmDetector {
        SvmDetector { inner: unsafe { cv_hog_daimler_people_detector() } }
    }
}

impl Drop for SvmDetector {
    fn drop(&mut self) {
        unsafe {
            cv_hog_detector_drop(self.inner);
        }
    }
}

/// Parameters that controls the behavior of HOG
#[derive(Debug, Clone, Copy)]
pub struct HogParams {
    /// Detection window size. Align to block size and block stride
    pub win_size: Size2i,

    /// Block size in pixels. Align to cell size. Only (16,16) is supported for now.
    pub block_size: Size2i,

    /// Block stride. It must be a multiple of cell size.
    pub block_stride: Size2i,

    /// Cell size. Only (8, 8) is supported for now.
    pub cell_size: Size2i,

    /// Number of bins. Only 9 bins per cell are supported for now.
    pub nbins: i32,

    /// Gaussian smoothing window parameter.
    pub win_sigma: f64,

    /// L2-Hys normalization method shrinkage.
    pub l2hys_threshold: f64,

    /// Flag to specify whether the gamma correction preprocessing is required or not.
    pub gamma_correction: bool,

    /// Maximum number of detection window increases.
    pub nlevels: usize,

    // =======================================================================
    //  Functions from detect function
    // =======================================================================
    /// Threshold for the distance between features and SVM classifying
    /// plane. Usually it is 0 and should be specfied in the detector
    /// coefficients (as the last free coefficient). But if the free coefficient
    /// is omitted (which is allowed), you can specify it manually here.
    pub hit_threshold: f64,

    /// Window stride. It must be a multiple of block stride.
    pub win_stride: Size2i,

    /// Padding
    pub padding: Size2i,

    /// Coefficient of the detection window increase.
    pub scale: f64,

    /// Coefficient to regulate the similarity threshold. When detected, some
    /// objects can be covered by many rectangles. 0 means not to perform
    /// grouping.
    pub group_threshold: i32,
}

const DEFAULT_WIN_SIGMA: f64 = -1f64;
const DEFAULT_NLEVELS: usize = 64;

impl Default for HogParams {
    fn default() -> HogParams {

        let win_sigma = {
            if cfg!(feature = "gpu") {
                4.0
            } else {
                DEFAULT_WIN_SIGMA
            }
        };

        HogParams {
            win_size: Size2i::new(64, 128),
            block_size: Size2i::new(16, 16),
            block_stride: Size2i::new(8, 8),
            cell_size: Size2i::new(8, 8),
            nbins: 9,

            win_sigma: win_sigma,
            l2hys_threshold: 0.2,
            gamma_correction: true,
            nlevels: DEFAULT_NLEVELS,

            hit_threshold: 0f64,
            win_stride: Size2i::new(8, 8),
            padding: Size2i::default(),
            scale: 1.05,
            group_threshold: 2,
        }
    }
}

enum CHogDescriptor {}

/// `HogDescriptor` implements Histogram of Oriented Gradients.
#[derive(Debug)]
pub struct HogDescriptor {
    inner: *mut CHogDescriptor,

    /// Hog parameters.
    pub params: HogParams,
}

unsafe impl Send for HogDescriptor {}

extern "C" {
    fn cv_hog_new() -> *mut CHogDescriptor;
    fn cv_hog_drop(hog: *mut CHogDescriptor);
    fn cv_hog_set_svm_detector(hog: *mut CHogDescriptor, svm: *mut CSvmDetector);
    fn cv_hog_detect(hog: *mut CHogDescriptor,
                     image: *mut CMat,
                     objs: *mut CVecOfRect,
                     weights: *mut CVecDouble,
                     win_stride: Size2i,
                     padding: Size2i,
                     scale: c_double,
                     final_threshold: c_double,
                     use_means_shift: bool);
}

impl Default for HogDescriptor {
    fn default() -> HogDescriptor {
        HogDescriptor {
            inner: unsafe { cv_hog_new() },
            params: HogParams::default(),
        }
    }
}

impl ObjectDetect for HogDescriptor {
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)> {
        let mut detected = CVecOfRect::default();
        let mut weights = CVecDouble::default();
        unsafe {
            cv_hog_detect(self.inner,
                          image.inner,
                          &mut detected,
                          &mut weights,
                          self.params.win_stride,
                          self.params.padding,
                          self.params.scale,
                          2.0, // finalThreshold
                          false /* useMeanshiftGrouping */);
        }

        let results = detected.rustify();
        let weights = weights.rustify();
        results.into_iter().zip(weights).collect::<Vec<_>>()
    }
}

impl HogDescriptor {
    /// Creates a HogDescriptor with provided parameters.
    pub fn with_params(params: HogParams) -> HogDescriptor {
        HogDescriptor {
            inner: unsafe { cv_hog_new() },
            params: params,
        }
    }

    /// Sets the SVM detector.
    pub fn set_svm_detector(&mut self, detector: SvmDetector) {
        unsafe { cv_hog_set_svm_detector(self.inner, detector.inner) }
    }
}

impl Drop for HogDescriptor {
    fn drop(&mut self) {
        unsafe { cv_hog_drop(self.inner) }
    }
}
<commit_msg>feat: add more hog params and improve docs<commit_after>//! Various object detection algorithms, such as Haar feature-based cascade
//! classifier for object detection and histogram of oriented gradients (HOG).

use super::core::*;
use libc::{c_double, c_char, c_int};
use std::ffi::CString;
use std::path::Path;
use std::vec::Vec;

/// An object detect trait.
pub trait ObjectDetect {
    /// Detects the object inside this image and returns a list of detections
    /// with their confidence.
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)>;
}

/// The opaque type for C
enum CCascadeClassifier {}

/// Cascade classifier class for object detection.
#[derive(Debug)]
pub struct CascadeClassifier {
    inner: *mut CCascadeClassifier,
}

/// We can safely send the classifier (a mutable pointer) to a different thread
unsafe impl Send for CascadeClassifier {}

extern "C" {
    fn cv_cascade_classifier_new() -> *mut CCascadeClassifier;
    fn cv_cascade_classifier_load(cc: *mut CCascadeClassifier, p: *const c_char) -> bool;
    fn cv_cascade_classifier_drop(p: *mut CCascadeClassifier);
    fn cv_cascade_classifier_detect(cc: *mut CCascadeClassifier,
                                    cmat: *mut CMat,
                                    vec_of_rect: *mut CVecOfRect,
                                    scale_factor: c_double,
                                    min_neighbors: c_int,
                                    flags: c_int,
                                    min_size: Size2i,
                                    max_size: Size2i);
}

impl ObjectDetect for CascadeClassifier {
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)> {
        self.detect_multiscale(image)
            .into_iter()
            .map(|r| (r, 0f64))
            .collect::<Vec<_>>()
    }
}

impl CascadeClassifier {
    /// Creates a cascade classifier, uninitialized. Before use, call load.
    pub fn new() -> CascadeClassifier {
        CascadeClassifier { inner: unsafe { cv_cascade_classifier_new() } }
    }

    /// Creates a cascade classifier using the model specified.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Option<Self> {
        let cc = CascadeClassifier::new();
        if cc.load(path) { Some(cc) } else { None }
    }

    /// Loads the classifier model from a path.
    pub fn load<P: AsRef<Path>>(&self, path: P) -> bool {
        let s = CString::new(path.as_ref()
                .to_str()
                .expect("only UTF-8 path is allowed"))
            .expect("failed to create CString to load cascade");
        unsafe { cv_cascade_classifier_load(self.inner, (&s).as_ptr()) }
    }

    /// The default detection uses scale factor 1.1, minNeighbors 3, no min size
    /// or max size.
    pub fn detect_multiscale(&self, mat: &Mat) -> Vec<Rect> {
        self.detect_with_params(mat, 1.1, 3, Size2i::default(), Size2i::default())
    }

    /// Detects the object using parameters specified.
    ///
    /// * `mat` - Matrix of the type CV_8U containing an image where objects are
    ///   detected.
    /// * `scale_factor` - Parameter specifying how much the image size is
    ///   reduced at each image scale.
    /// * `min_neighbors` - Parameter specifying how many neighbors each
    ///   candidate rectangle should have to retain it.
    /// * `min_size` - Minimum possible object size. Objects smaller than that
    ///   are ignored.
    /// * `max_size` - Maximum possible object size. Objects larger than that
    ///   are ignored
    ///
    /// OpenCV has a parameter (`flags`) that's not used at all.
    pub fn detect_with_params(&self,
                              mat: &Mat,
                              scale_factor: f32,
                              min_neighbors: i32,
                              min_size: Size2i,
                              max_size: Size2i)
                              -> Vec<Rect> {
        let mut c_result = CVecOfRect::default();
        unsafe {
            cv_cascade_classifier_detect(self.inner,
                                         mat.inner,
                                         &mut c_result,
                                         scale_factor as c_double,
                                         min_neighbors,
                                         0,
                                         min_size,
                                         max_size)
        }
        c_result.rustify()
    }
}

impl Drop for CascadeClassifier {
    fn drop(&mut self) {
        unsafe {
            cv_cascade_classifier_drop(self.inner);
        }
    }
}

#[derive(Debug, Clone, Copy)]
/// Opaque type for C/C++ SvmDetector object
pub enum CSvmDetector {}

/// SvmDetector
#[derive(Debug)]
pub struct SvmDetector {
    /// Pointer to the inner data structure
    pub inner: *mut CSvmDetector,
}

extern "C" {
    fn cv_hog_default_people_detector() -> *mut CSvmDetector;
    fn cv_hog_daimler_people_detector() -> *mut CSvmDetector;
    fn cv_hog_detector_drop(d: *mut CSvmDetector);
}

impl SvmDetector {
    /// The built-in people detector.
    ///
    /// The size of the default people detector is 64x128, that mean that the
    /// people you would want to detect have to be atleast 64x128.
    pub fn default_people_detector() -> SvmDetector {
        SvmDetector { inner: unsafe { cv_hog_default_people_detector() } }
    }

    /// Returns the Daimler people detector.
    pub fn daimler_people_detector() -> SvmDetector {
        SvmDetector { inner: unsafe { cv_hog_daimler_people_detector() } }
    }
}

impl Drop for SvmDetector {
    fn drop(&mut self) {
        unsafe {
            cv_hog_detector_drop(self.inner);
        }
    }
}

/// Parameters that controls the behavior of HOG.
#[derive(Debug, Clone, Copy)]
pub struct HogParams {
    /// Detection window size. Align to block size and block stride. The default
    /// is 64x128, trained the same as original paper.
    pub win_size: Size2i,

    /// Block size in pixels. Align to cell size. Only (16,16) is supported for
    /// now (at least for GPU).
    pub block_size: Size2i,

    /// Block stride. It must be a multiple of cell size.
    pub block_stride: Size2i,

    /// Cell size. Only (8, 8) is supported for now.
    pub cell_size: Size2i,

    /// Number of bins. Only 9 bins per cell are supported for now.
    pub nbins: i32,

    /// Gaussian smoothing window parameter. Default -1 for CPU and 4.0 for GPU.
    pub win_sigma: f64,

    /// L2-Hys normalization method shrinkage. Default 0.2.
    pub l2hys_threshold: f64,

    /// Flag to specify whether the gamma correction preprocessing is required
    /// or not. Default false.
    pub gamma_correction: bool,

    /// Maximum number of detection window increases (HOG scales). Default: 64.
    pub nlevels: usize,

    // =======================================================================
    //  Functions from detect function
    // =======================================================================
    /// Threshold for the distance between features and SVM classifying
    /// plane. Usually it is 0 and should be specfied in the detector
    /// coefficients (as the last free coefficient). But if the free coefficient
    /// is omitted (which is allowed), you can specify it manually here.
    pub hit_threshold: f64,

    /// Window stride. It must be a multiple of block stride.
    pub win_stride: Size2i,

    /// Padding
    pub padding: Size2i,

    /// Coefficient of the detection window increase.
    pub scale: f64,

    /// Coefficient to regulate the similarity threshold. When detected, some
    /// objects can be covered by many rectangles. 0 means not to perform
    /// grouping.
    pub group_threshold: i32,

    /// The useMeanShiftGrouping parameter is a boolean indicating whether or
    /// not mean-shift grouping should be performed to handle potential
    /// overlapping bounding boxes. While this value should not be set and users
    /// should employ non-maxima suppression instead, we support setting it as a
    /// library function.
    pub use_meanshift_grouping: bool,

    /// The `finalThreshold` parameter is mainly used to select the clusters
    /// that have at least `finalThreshold + 1` rectangles. This parameter is
    /// passed when meanShift is enabled; the function rejects the small
    /// clusters containing less than or equal to `finalThreshold` rectangles,
    /// computes the average rectangle size for the rest of the accepted
    /// clusters and adds those to the output rectangle list.
    pub final_threshold: f64,
}

const DEFAULT_WIN_SIGMA: f64 = -1f64;
const DEFAULT_NLEVELS: usize = 64;

impl Default for HogParams {
    fn default() -> HogParams {

        let win_sigma = {
            if cfg!(feature = "gpu") {
                4.0
            } else {
                DEFAULT_WIN_SIGMA
            }
        };

        HogParams {
            win_size: Size2i::new(64, 128),
            block_size: Size2i::new(16, 16),
            block_stride: Size2i::new(8, 8),
            cell_size: Size2i::new(8, 8),
            nbins: 9,

            win_sigma: win_sigma,
            l2hys_threshold: 0.2,
            gamma_correction: false,
            nlevels: DEFAULT_NLEVELS,

            hit_threshold: 0f64,
            win_stride: Size2i::new(8, 8),
            padding: Size2i::default(),
            scale: 1.05,
            group_threshold: 2,

            final_threshold: 2.0,
            use_meanshift_grouping: false,
        }
    }
}

enum CHogDescriptor {}

/// `HogDescriptor` implements Histogram of Oriented Gradients.
#[derive(Debug)]
pub struct HogDescriptor {
    inner: *mut CHogDescriptor,

    /// Hog parameters.
    pub params: HogParams,
}

unsafe impl Send for HogDescriptor {}

extern "C" {
    fn cv_hog_new() -> *mut CHogDescriptor;
    fn cv_hog_drop(hog: *mut CHogDescriptor);
    fn cv_hog_set_svm_detector(hog: *mut CHogDescriptor, svm: *mut CSvmDetector);
    fn cv_hog_detect(hog: *mut CHogDescriptor,
                     image: *mut CMat,
                     objs: *mut CVecOfRect,
                     weights: *mut CVecDouble,
                     win_stride: Size2i,
                     padding: Size2i,
                     scale: c_double,
                     final_threshold: c_double,
                     use_means_shift: bool);
}

impl Default for HogDescriptor {
    fn default() -> HogDescriptor {
        HogDescriptor {
            inner: unsafe { cv_hog_new() },
            params: HogParams::default(),
        }
    }
}

impl ObjectDetect for HogDescriptor {
    fn detect(&self, image: &Mat) -> Vec<(Rect, f64)> {
        let mut detected = CVecOfRect::default();
        let mut weights = CVecDouble::default();
        unsafe {
            cv_hog_detect(self.inner,
                          image.inner,
                          &mut detected,
                          &mut weights,
                          self.params.win_stride,
                          self.params.padding,
                          self.params.scale,
                          self.params.final_threshold,
                          self.params.use_meanshift_grouping)
        }

        let results = detected.rustify();
        let weights = weights.rustify();
        results.into_iter().zip(weights).collect::<Vec<_>>()
    }
}

impl HogDescriptor {
    /// Creates a HogDescriptor with provided parameters.
    pub fn with_params(params: HogParams) -> HogDescriptor {
        HogDescriptor {
            inner: unsafe { cv_hog_new() },
            params: params,
        }
    }

    /// Sets the SVM detector.
    pub fn set_svm_detector(&mut self, detector: SvmDetector) {
        unsafe { cv_hog_set_svm_detector(self.inner, detector.inner) }
    }
}

impl Drop for HogDescriptor {
    fn drop(&mut self) {
        unsafe { cv_hog_drop(self.inner) }
    }
}
<|endoftext|>


<commit_before>#[deriving(PartialEq, Show)]
pub struct ObjectId {
    pub hash: &'static str,
    bytes: Vec<u8>
}

impl ObjectId {
    pub fn new(hash: &'static str) -> ObjectId {
        ObjectId {
            hash: hash,
            bytes: Vec::new()
        }
    }
}
<commit_msg>Make sure ObjectId always has the hash version and the raw version<commit_after>use conversion;

pub static RAW_SIZE: uint = 20;
pub static HEX_SIZE: uint = 40;

#[deriving(PartialEq, Show)]
pub struct ObjectId {
    pub hash: String,
    bytes: Vec<u8>
}

impl ObjectId {
    pub fn from_string(hash: &str) -> ObjectId {
        ObjectId {
            hash: hash.to_string(),
            bytes: conversion::hex_string_to_bytes(hash)
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> ObjectId {
        ObjectId {
            hash: conversion::bytes_to_hex_string(bytes),
            bytes: bytes.into_vec()
        }
    }
}
<|endoftext|>


<commit_before>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use syntax::ast::typer::resolve_type;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use std::mem::size_of;
use jit::{Context, Function, Type, Types, Compilable, CDECL};
use jit::{UByte, SysChar, SysBool, Void, Int, UInt, Pointer, Float64, Signature};
use jit;

fn compile_type(js_type:&JSType) -> Box<Type> {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => Types::get_void_ptr(),
		FunctionType => Types::get_void_ptr(),
		StringType => Type::create_pointer(Types::get_char()),
		BooleanType => jit_compile!(bool),
		NumberType => Types::get_float64(),
		IntegerType => jit_compile!(i32),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Box<Context>,
	/// An object representing the global object
	pub global: Value
}
impl JITCompiler {
	fn with_builder<R>(&self, cb: || -> R) -> R {
		self.context.build_start();
		let rv = cb();
		self.context.build_end();
		rv
	}
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Box<Function> {
		self.with_builder(|| {
			fn compile_value(func:&Function, expr: &Expr) -> Box<jit::Value> {
				let valuedata_t = jit_compile!(int);
				let valuedata_ptr_t = jit_compile!(*$valuedata_t);
				let value_t = valuedata_ptr_t;
				let cstring_t = jit_compile!(*char);
				let create_value_sig = jit_compile!(() -> $value_t);
				let undefined = || {
					let ptr = func.create_value(Types::get_void_ptr());
					let val = 0u8.compile(func);
					func.insn_store(ptr, val);
					ptr
				};
				let global = func.get_param(0);
				let scope = func.get_param(1);
				let this = func.get_param(2);
				match expr.def {
					ConstExpr(CNull) => {
						let ptr = func.create_value(jit_compile!(*void));
						let val = 1u8.compile(func);
						func.insn_store(ptr, val);
						ptr
					},
					ConstExpr(CUndefined) => {
						undefined()
					},
					ConstExpr(CBool(v)) => {
						v.compile(func)
					},
					ConstExpr(CNum(n)) => {
						n.compile(func)
					},
					ConstExpr(CString(ref s)) => {
						s.compile(func)
					},
					BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_add(i_a, i_b)
					},
					BinOpExpr(BinNum(OpSub), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_sub(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMul), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_mul(i_a, i_b)
					},
					BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_div(i_a, i_b)
					},
					BinOpExpr(BinNum(OpMod), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_rem(i_a, i_b)
					},
					BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_and(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitOr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_or(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitXor), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_xor(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShl), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shl(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinBit(BitShr), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_shr(i_a, i_b), jit_compile!(i32), false)
					},
					BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_eq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_neq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_lt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_leq(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_gt(i_a, i_b), jit_compile!(bool), false)
					},
					BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
						let i_a = compile_value(func, *a);
						let i_b = compile_value(func, *b);
						func.insn_convert(func.insn_geq(i_a, i_b), jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryMinus, ref a) => {
						func.insn_neg(compile_value(func, *a))
					},
					UnaryOpExpr(UnaryNot, ref a) => {
						let mut val = compile_value(func, *a);
						val = func.insn_convert(val, jit_compile!(bool), false);
						val = func.insn_neg(val);
						func.insn_convert(val, jit_compile!(bool), false)
					},
					UnaryOpExpr(UnaryPlus, ref a) => {
						compile_value(func, *a)
					},
					BlockExpr(ref exprs) => {
						let mut result = undefined();
						let last = exprs.last();
						for expr in exprs.iter() {
							let res = compile_value(func, expr);
							if expr == last.unwrap() {
								result = res;
							}
						}
						result
					},
					ReturnExpr(Some(ref ex)) => {
						let ret = compile_value(func, *ex);
						func.insn_return(convert_to_value(func, ret));
						ret
					}
					_ => fail!("Unimplemented {}", expr)
				}
			};
			let value_t = jit_compile!(*int);
			let default_sig_t = Type::create_signature(CDECL, value_t, &mut [&*value_t, &*value_t, &*value_t]);
			let func = self.context.create_function(default_sig_t);
			let value = compile_value(func, expr);
			func.insn_return(convert_to_value(func, value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:Box<Function>) -> ResultValue {
		// global fn(global, scope, this)
		let func: fn(Value, Value, Value) -> Value = comp.closure();
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&jit::Value) -> Box<jit::Value> {
	let value_t = jit_compile!(*int);
	let undef_value = Value::undefined;
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(bool)]);
		func.insn_call_native1("bool_value", bool_value, sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*val_type]);
			func.insn_call_native1("string_value", string_value, sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_void_ptr()]);
			func.insn_call_native1("ptr_value", ptr_value, sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(i32)]);
		func.insn_call_native1("int_value", int_value, sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_float64()]);
		func.insn_call_native1("float_value", float_value, sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}<commit_msg>Move compile_value to seperate function<commit_after>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use syntax::ast::typer::resolve_type;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use std::mem::size_of;
use jit::{Context, Function, Type, Types, Compilable, CDECL};
use jit::{UByte, SysChar, SysBool, Void, Int, UInt, Pointer, Float64, Signature};
use jit;

fn compile_type(js_type:&JSType) -> Box<Type> {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => Types::get_void_ptr(),
		FunctionType => Types::get_void_ptr(),
		StringType => Type::create_pointer(Types::get_char()),
		BooleanType => jit_compile!(bool),
		NumberType => Types::get_float64(),
		IntegerType => jit_compile!(i32),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Box<Context>,
	/// An object representing the global object
	pub global: Value
}
impl JITCompiler {
	fn with_builder<R>(&self, cb: || -> R) -> R {
		self.context.build_start();
		let rv = cb();
		self.context.build_end();
		rv
	}
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Box<Function> {
		self.with_builder(|| {
			let value_t = jit_compile!(*int);
			let default_sig_t = Type::create_signature(CDECL, value_t, &mut [&*value_t, &*value_t, &*value_t]);
			let func = self.context.create_function(default_sig_t);
			let value = compile_value(func, expr);
			func.insn_return(convert_to_value(func, value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:Box<Function>) -> ResultValue {
		// global fn(global, scope, this)
		let func: fn(Value, Value, Value) -> Value = comp.closure();
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&jit::Value) -> Box<jit::Value> {
	let value_t = jit_compile!(*int);
	let undef_value = Value::undefined;
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(bool)]);
		func.insn_call_native1("bool_value", bool_value, sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*val_type]);
			func.insn_call_native1("string_value", string_value, sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_void_ptr()]);
			func.insn_call_native1("ptr_value", ptr_value, sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*jit_compile!(i32)]);
		func.insn_call_native1("int_value", int_value, sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = Type::create_signature(CDECL, value_t, &mut [&*Types::get_float64()]);
		func.insn_call_native1("float_value", float_value, sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}

fn compile_value(func:&Function, expr: &Expr) -> Box<jit::Value> {
	let value_t = jit_compile!(*int);
	let cstring_t = jit_compile!(*char);
	let create_value_sig = jit_compile!(() -> $value_t);
	let undefined = || {
		let ptr = func.create_value(Types::get_void_ptr());
		let val = 0u8.compile(func);
		func.insn_store(ptr, val);
		ptr
	};
	let global = func.get_param(0);
	let scope = func.get_param(1);
	let this = func.get_param(2);
	match expr.def {
		ConstExpr(CNull) => {
			let ptr = func.create_value(jit_compile!(*void));
			let val = 1u8.compile(func);
			func.insn_store(ptr, val);
			ptr
		},
		ConstExpr(CUndefined) => {
			undefined()
		},
		ConstExpr(CBool(v)) => {
			v.compile(func)
		},
		ConstExpr(CNum(n)) => {
			n.compile(func)
		},
		ConstExpr(CString(ref s)) => {
			s.compile(func)
		},
		BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_add(i_a, i_b)
		},
		BinOpExpr(BinNum(OpSub), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_sub(i_a, i_b)
		},
		BinOpExpr(BinNum(OpMul), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_mul(i_a, i_b)
		},
		BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_div(i_a, i_b)
		},
		BinOpExpr(BinNum(OpMod), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_rem(i_a, i_b)
		},
		BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_and(i_a, i_b), jit_compile!(i32), false)
		},
		BinOpExpr(BinBit(BitOr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_or(i_a, i_b), jit_compile!(i32), false)
		},
		BinOpExpr(BinBit(BitXor), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_xor(i_a, i_b), jit_compile!(i32), false)
		},
		BinOpExpr(BinBit(BitShl), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_shl(i_a, i_b), jit_compile!(i32), false)
		},
		BinOpExpr(BinBit(BitShr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_shr(i_a, i_b), jit_compile!(i32), false)
		},
		BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_eq(i_a, i_b), jit_compile!(bool), false)
		},
		BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_neq(i_a, i_b), jit_compile!(bool), false)
		},
		BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_lt(i_a, i_b), jit_compile!(bool), false)
		},
		BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_leq(i_a, i_b), jit_compile!(bool), false)
		},
		BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_gt(i_a, i_b), jit_compile!(bool), false)
		},
		BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(func.insn_geq(i_a, i_b), jit_compile!(bool), false)
		},
		UnaryOpExpr(UnaryMinus, ref a) => {
			func.insn_neg(compile_value(func, *a))
		},
		UnaryOpExpr(UnaryNot, ref a) => {
			let mut val = compile_value(func, *a);
			val = func.insn_convert(val, jit_compile!(bool), false);
			val = func.insn_neg(val);
			func.insn_convert(val, jit_compile!(bool), false)
		},
		UnaryOpExpr(UnaryPlus, ref a) => {
			compile_value(func, *a)
		},
		BlockExpr(ref exprs) => {
			let mut result = undefined();
			let last = exprs.last();
			for expr in exprs.iter() {
				let res = compile_value(func, expr);
				if expr == last.unwrap() {
					result = res;
				}
			}
			result
		},
		ReturnExpr(Some(ref ex)) => {
			let ret = compile_value(func, *ex);
			func.insn_return(convert_to_value(func, ret));
			ret
		}
		_ => fail!("Unimplemented {}", expr)
	}
}<|endoftext|>


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

//! A type representing either success or failure

#[allow(missing_doc)];

use clone::Clone;
use cmp::Eq;
use either;
use iterator::Iterator;
use option::{None, Option, Some, OptionIterator};
use vec;
use vec::{OwnedVector, ImmutableVector};
use container::Container;
use to_str::ToStr;
use str::StrSlice;

/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
/// In order to provide informative error messages, `E` is reqired to implement `ToStr`.
/// It is further recommended for `E` to be a descriptive error type, eg a `enum` for
/// all possible errors cases.
#[deriving(Clone, Eq)]
pub enum Result<T, E> {
    /// Contains the successful result value
    Ok(T),
    /// Contains the error value
    Err(E)
}

impl<T, E: ToStr> Result<T, E> {
    /// Convert to the `either` type
    ///
    /// `Ok` result variants are converted to `either::Right` variants, `Err`
    /// result variants are converted to `either::Left`.
    #[inline]
    pub fn to_either(self)-> either::Either<E, T>{
        match self {
            Ok(t) => either::Right(t),
            Err(e) => either::Left(e),
        }
    }

    /// Get a reference to the value out of a successful result
    ///
    /// # Failure
    ///
    /// If the result is an error
    #[inline]
    pub fn get_ref<'a>(&'a self) -> &'a T {
        match *self {
            Ok(ref t) => t,
            Err(ref e) => fail!("called `Result::get_ref()` on `Err` value: %s", e.to_str()),
        }
    }

    /// Returns true if the result is `Ok`
    #[inline]
    pub fn is_ok(&self) -> bool {
        match *self {
            Ok(_) => true,
            Err(_) => false
        }
    }

    /// Returns true if the result is `Err`
    #[inline]
    pub fn is_err(&self) -> bool {
        !self.is_ok()
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Err` then it is
    /// immediately returned. This function can be used to compose the results
    /// of two functions.
    ///
    /// Example:
    ///
    ///     for buf in read_file(file) {
    ///         print_buf(buf)
    ///     }
    #[inline]
    pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> {
        match *self {
            Ok(ref t) => Some(t),
            Err(*) => None,
        }.consume_iter()
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Ok` then it is
    /// immediately returned.  This function can be used to pass through a
    /// successful result while handling an error.
    #[inline]
    pub fn iter_err<'r>(&'r self) -> OptionIterator<&'r E> {
        match *self {
            Ok(*) => None,
            Err(ref t) => Some(t),
        }.consume_iter()
    }

    /// Unwraps a result, yielding the content of an `Ok`.
    /// Fails if the value is a `Err` with an error message derived
    /// from `E`'s `ToStr` implementation.
    #[inline]
    pub fn unwrap(self) -> T {
        match self {
            Ok(t) => t,
            Err(e) => fail!("called `Result::unwrap()` on `Err` value: %s", e.to_str()),
        }
    }

    /// Unwraps a result, yielding the content of an `Err`.
    /// Fails if the value is a `Ok`.
    #[inline]
    pub fn unwrap_err(self) -> E {
        self.expect_err("called `Result::unwrap_err()` on `Ok` value")
    }

    /// Unwraps a result, yielding the content of an `Ok`.
    /// Fails if the value is a `Err` with a custom failure message.
    #[inline]
    pub fn expect(self, reason: &str) -> T {
        match self {
            Ok(t) => t,
            Err(_) => fail!(reason.to_owned()),
        }
    }

    /// Unwraps a result, yielding the content of an `Err`
    /// Fails if the value is a `Ok` with a custom failure message.
    #[inline]
    pub fn expect_err(self, reason: &str) -> E {
        match self {
            Err(e) => e,
            Ok(_) => fail!(reason.to_owned()),
        }
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Err` then it is
    /// immediately returned. This function can be used to compose the results
    /// of two functions.
    ///
    /// Example:
    ///
    ///     let res = do read_file(file) |buf| {
    ///         Ok(parse_bytes(buf))
    ///     };
    #[inline]
    pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
        match self {
            Ok(t) => op(t),
            Err(e) => Err(e),
        }
    }

    /// Call a function based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Ok` then it is
    /// immediately returned.  This function can be used to pass through a
    /// successful result while handling an error.
    #[inline]
    pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
        match self {
            Ok(t) => Ok(t),
            Err(e) => op(e),
        }
    }
}

impl<T: Clone, E: ToStr> Result<T, E> {
    /// Call a method based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is
    /// `Ok` then it is immediately returned.  This function can be used to pass
    /// through a successful result while handling an error.
    #[inline]
    pub fn map_err<F: Clone>(&self, op: &fn(&E) -> F) -> Result<T,F> {
        match *self {
            Ok(ref t) => Ok(t.clone()),
            Err(ref e) => Err(op(e))
        }
    }
}

impl<T, E: Clone + ToStr> Result<T, E> {
    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is
    /// `Err` then it is immediately returned.  This function can be used to
    /// compose the results of two functions.
    ///
    /// Example:
    ///
    ///     let res = do read_file(file).map |buf| {
    ///         parse_bytes(buf)
    ///     };
    #[inline]
    pub fn map<U: Clone>(&self, op: &fn(&T) -> U) -> Result<U,E> {
        match *self {
            Ok(ref t) => Ok(op(t)),
            Err(ref e) => Err(e.clone())
        }
    }
}

#[inline]
#[allow(missing_doc)]
pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
                               op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> {
    match *o_t {
        None => Ok(None),
        Some(ref t) => match op(t) {
            Ok(v) => Ok(Some(v)),
            Err(e) => Err(e)
        }
    }
}

// FIXME: #8228 Replaceable by an external iterator?
/// Maps each element in the vector `ts` using the operation `op`.  Should an
/// error occur, no further mappings are performed and the error is returned.
/// Should no error occur, a vector containing the result of each map is
/// returned.
///
/// Here is an example which increments every integer in a vector,
/// checking for overflow:
///
///     fn inc_conditionally(x: uint) -> result<uint,str> {
///         if x == uint::max_value { return Err("overflow"); }
///         else { return Ok(x+1u); }
///     }
///     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
///         assert!(incd == ~[2u, 3u, 4u]);
///     }
#[inline]
pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>)
                      -> Result<~[V],U> {
    let mut vs: ~[V] = vec::with_capacity(ts.len());
    for t in ts.iter() {
        match op(t) {
          Ok(v) => vs.push(v),
          Err(u) => return Err(u)
        }
    }
    return Ok(vs);
}

// FIXME: #8228 Replaceable by an external iterator?
/// Same as map, but it operates over two parallel vectors.
///
/// A precondition is used here to ensure that the vectors are the same
/// length.  While we do not often use preconditions in the standard
/// library, a precondition is used here because result::t is generally
/// used in 'careful' code contexts where it is both appropriate and easy
/// to accommodate an error like the vectors being of different lengths.
#[inline]
pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T],
                                   op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
    assert!(vec::same_length(ss, ts));
    let n = ts.len();
    let mut vs = vec::with_capacity(n);
    let mut i = 0u;
    while i < n {
        match op(&ss[i],&ts[i]) {
          Ok(v) => vs.push(v),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(vs);
}

// FIXME: #8228 Replaceable by an external iterator?
/// Applies op to the pairwise elements from `ss` and `ts`, aborting on
/// error.  This could be implemented using `map_zip()` but it is more efficient
/// on its own as no result vector is built.
#[inline]
pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T],
                                 op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
    assert!(vec::same_length(ss, ts));
    let n = ts.len();
    let mut i = 0u;
    while i < n {
        match op(&ss[i],&ts[i]) {
          Ok(()) => (),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(());
}

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

    pub fn op1() -> Result<int, ~str> { Ok(666) }

    pub fn op2(i: int) -> Result<uint, ~str> {
        Ok(i as uint + 1u)
    }

    pub fn op3() -> Result<int, ~str> { Err(~"sadface") }

    #[test]
    pub fn chain_success() {
        assert_eq!(op1().chain(op2).unwrap(), 667u);
    }

    #[test]
    pub fn chain_failure() {
        assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface");
    }

    #[test]
    pub fn test_impl_iter() {
        let mut valid = false;
        let okval = Ok::<~str, ~str>(~"a");
        do okval.iter().next().map |_| { valid = true; };
        assert!(valid);

        let errval = Err::<~str, ~str>(~"b");
        do errval.iter().next().map |_| { valid = false; };
        assert!(valid);
    }

    #[test]
    pub fn test_impl_iter_err() {
        let mut valid = true;
        let okval = Ok::<~str, ~str>(~"a");
        do okval.iter_err().next().map |_| { valid = false };
        assert!(valid);

        valid = false;
        let errval = Err::<~str, ~str>(~"b");
        do errval.iter_err().next().map |_| { valid = true };
        assert!(valid);
    }

    #[test]
    pub fn test_impl_map() {
        assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b"));
        assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a"));
    }

    #[test]
    pub fn test_impl_map_err() {
        assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a"));
        assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b"));
    }

    #[test]
    pub fn test_get_ref_method() {
        let foo: Result<int, ()> = Ok(100);
        assert_eq!(*foo.get_ref(), 100);
    }

    #[test]
    pub fn test_to_either() {
        let r: Result<int, ()> = Ok(100);
        let err: Result<(), int> = Err(404);

        assert_eq!(r.to_either(), either::Right(100));
        assert_eq!(err.to_either(), either::Left(404));
    }
}
<commit_msg>std: Remove unused trait bound in Result::map<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A type representing either success or failure

#[allow(missing_doc)];

use clone::Clone;
use cmp::Eq;
use either;
use iterator::Iterator;
use option::{None, Option, Some, OptionIterator};
use vec;
use vec::{OwnedVector, ImmutableVector};
use container::Container;
use to_str::ToStr;
use str::StrSlice;

/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
/// In order to provide informative error messages, `E` is reqired to implement `ToStr`.
/// It is further recommended for `E` to be a descriptive error type, eg a `enum` for
/// all possible errors cases.
#[deriving(Clone, Eq)]
pub enum Result<T, E> {
    /// Contains the successful result value
    Ok(T),
    /// Contains the error value
    Err(E)
}

impl<T, E: ToStr> Result<T, E> {
    /// Convert to the `either` type
    ///
    /// `Ok` result variants are converted to `either::Right` variants, `Err`
    /// result variants are converted to `either::Left`.
    #[inline]
    pub fn to_either(self)-> either::Either<E, T>{
        match self {
            Ok(t) => either::Right(t),
            Err(e) => either::Left(e),
        }
    }

    /// Get a reference to the value out of a successful result
    ///
    /// # Failure
    ///
    /// If the result is an error
    #[inline]
    pub fn get_ref<'a>(&'a self) -> &'a T {
        match *self {
            Ok(ref t) => t,
            Err(ref e) => fail!("called `Result::get_ref()` on `Err` value: %s", e.to_str()),
        }
    }

    /// Returns true if the result is `Ok`
    #[inline]
    pub fn is_ok(&self) -> bool {
        match *self {
            Ok(_) => true,
            Err(_) => false
        }
    }

    /// Returns true if the result is `Err`
    #[inline]
    pub fn is_err(&self) -> bool {
        !self.is_ok()
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Err` then it is
    /// immediately returned. This function can be used to compose the results
    /// of two functions.
    ///
    /// Example:
    ///
    ///     for buf in read_file(file) {
    ///         print_buf(buf)
    ///     }
    #[inline]
    pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> {
        match *self {
            Ok(ref t) => Some(t),
            Err(*) => None,
        }.consume_iter()
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Ok` then it is
    /// immediately returned.  This function can be used to pass through a
    /// successful result while handling an error.
    #[inline]
    pub fn iter_err<'r>(&'r self) -> OptionIterator<&'r E> {
        match *self {
            Ok(*) => None,
            Err(ref t) => Some(t),
        }.consume_iter()
    }

    /// Unwraps a result, yielding the content of an `Ok`.
    /// Fails if the value is a `Err` with an error message derived
    /// from `E`'s `ToStr` implementation.
    #[inline]
    pub fn unwrap(self) -> T {
        match self {
            Ok(t) => t,
            Err(e) => fail!("called `Result::unwrap()` on `Err` value: %s", e.to_str()),
        }
    }

    /// Unwraps a result, yielding the content of an `Err`.
    /// Fails if the value is a `Ok`.
    #[inline]
    pub fn unwrap_err(self) -> E {
        self.expect_err("called `Result::unwrap_err()` on `Ok` value")
    }

    /// Unwraps a result, yielding the content of an `Ok`.
    /// Fails if the value is a `Err` with a custom failure message.
    #[inline]
    pub fn expect(self, reason: &str) -> T {
        match self {
            Ok(t) => t,
            Err(_) => fail!(reason.to_owned()),
        }
    }

    /// Unwraps a result, yielding the content of an `Err`
    /// Fails if the value is a `Ok` with a custom failure message.
    #[inline]
    pub fn expect_err(self, reason: &str) -> E {
        match self {
            Err(e) => e,
            Ok(_) => fail!(reason.to_owned()),
        }
    }

    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Err` then it is
    /// immediately returned. This function can be used to compose the results
    /// of two functions.
    ///
    /// Example:
    ///
    ///     let res = do read_file(file) |buf| {
    ///         Ok(parse_bytes(buf))
    ///     };
    #[inline]
    pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
        match self {
            Ok(t) => op(t),
            Err(e) => Err(e),
        }
    }

    /// Call a function based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is returned. if `self` is `Ok` then it is
    /// immediately returned.  This function can be used to pass through a
    /// successful result while handling an error.
    #[inline]
    pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
        match self {
            Ok(t) => Ok(t),
            Err(e) => op(e),
        }
    }
}

impl<T: Clone, E: ToStr> Result<T, E> {
    /// Call a method based on a previous result
    ///
    /// If `self` is `Err` then the value is extracted and passed to `op`
    /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is
    /// `Ok` then it is immediately returned.  This function can be used to pass
    /// through a successful result while handling an error.
    #[inline]
    pub fn map_err<F: Clone>(&self, op: &fn(&E) -> F) -> Result<T,F> {
        match *self {
            Ok(ref t) => Ok(t.clone()),
            Err(ref e) => Err(op(e))
        }
    }
}

impl<T, E: Clone + ToStr> Result<T, E> {
    /// Call a method based on a previous result
    ///
    /// If `self` is `Ok` then the value is extracted and passed to `op`
    /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is
    /// `Err` then it is immediately returned.  This function can be used to
    /// compose the results of two functions.
    ///
    /// Example:
    ///
    ///     let res = do read_file(file).map |buf| {
    ///         parse_bytes(buf)
    ///     };
    #[inline]
    pub fn map<U>(&self, op: &fn(&T) -> U) -> Result<U,E> {
        match *self {
            Ok(ref t) => Ok(op(t)),
            Err(ref e) => Err(e.clone())
        }
    }
}

#[inline]
#[allow(missing_doc)]
pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
                               op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> {
    match *o_t {
        None => Ok(None),
        Some(ref t) => match op(t) {
            Ok(v) => Ok(Some(v)),
            Err(e) => Err(e)
        }
    }
}

// FIXME: #8228 Replaceable by an external iterator?
/// Maps each element in the vector `ts` using the operation `op`.  Should an
/// error occur, no further mappings are performed and the error is returned.
/// Should no error occur, a vector containing the result of each map is
/// returned.
///
/// Here is an example which increments every integer in a vector,
/// checking for overflow:
///
///     fn inc_conditionally(x: uint) -> result<uint,str> {
///         if x == uint::max_value { return Err("overflow"); }
///         else { return Ok(x+1u); }
///     }
///     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
///         assert!(incd == ~[2u, 3u, 4u]);
///     }
#[inline]
pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>)
                      -> Result<~[V],U> {
    let mut vs: ~[V] = vec::with_capacity(ts.len());
    for t in ts.iter() {
        match op(t) {
          Ok(v) => vs.push(v),
          Err(u) => return Err(u)
        }
    }
    return Ok(vs);
}

// FIXME: #8228 Replaceable by an external iterator?
/// Same as map, but it operates over two parallel vectors.
///
/// A precondition is used here to ensure that the vectors are the same
/// length.  While we do not often use preconditions in the standard
/// library, a precondition is used here because result::t is generally
/// used in 'careful' code contexts where it is both appropriate and easy
/// to accommodate an error like the vectors being of different lengths.
#[inline]
pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T],
                                   op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
    assert!(vec::same_length(ss, ts));
    let n = ts.len();
    let mut vs = vec::with_capacity(n);
    let mut i = 0u;
    while i < n {
        match op(&ss[i],&ts[i]) {
          Ok(v) => vs.push(v),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(vs);
}

// FIXME: #8228 Replaceable by an external iterator?
/// Applies op to the pairwise elements from `ss` and `ts`, aborting on
/// error.  This could be implemented using `map_zip()` but it is more efficient
/// on its own as no result vector is built.
#[inline]
pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T],
                                 op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
    assert!(vec::same_length(ss, ts));
    let n = ts.len();
    let mut i = 0u;
    while i < n {
        match op(&ss[i],&ts[i]) {
          Ok(()) => (),
          Err(u) => return Err(u)
        }
        i += 1u;
    }
    return Ok(());
}

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

    pub fn op1() -> Result<int, ~str> { Ok(666) }

    pub fn op2(i: int) -> Result<uint, ~str> {
        Ok(i as uint + 1u)
    }

    pub fn op3() -> Result<int, ~str> { Err(~"sadface") }

    #[test]
    pub fn chain_success() {
        assert_eq!(op1().chain(op2).unwrap(), 667u);
    }

    #[test]
    pub fn chain_failure() {
        assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface");
    }

    #[test]
    pub fn test_impl_iter() {
        let mut valid = false;
        let okval = Ok::<~str, ~str>(~"a");
        do okval.iter().next().map |_| { valid = true; };
        assert!(valid);

        let errval = Err::<~str, ~str>(~"b");
        do errval.iter().next().map |_| { valid = false; };
        assert!(valid);
    }

    #[test]
    pub fn test_impl_iter_err() {
        let mut valid = true;
        let okval = Ok::<~str, ~str>(~"a");
        do okval.iter_err().next().map |_| { valid = false };
        assert!(valid);

        valid = false;
        let errval = Err::<~str, ~str>(~"b");
        do errval.iter_err().next().map |_| { valid = true };
        assert!(valid);
    }

    #[test]
    pub fn test_impl_map() {
        assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b"));
        assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a"));
    }

    #[test]
    pub fn test_impl_map_err() {
        assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a"));
        assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b"));
    }

    #[test]
    pub fn test_get_ref_method() {
        let foo: Result<int, ()> = Ok(100);
        assert_eq!(*foo.get_ref(), 100);
    }

    #[test]
    pub fn test_to_either() {
        let r: Result<int, ()> = Ok(100);
        let err: Result<(), int> = Err(404);

        assert_eq!(r.to_either(), either::Right(100));
        assert_eq!(err.to_either(), either::Left(404));
    }
}
<|endoftext|>


<commit_before>use super::token::{Token, TokenSpan, Lit};
use std::str::Chars;
use super::Span;
use std::iter::{Iterator};

///A lexer with its associated query, a char iterator, and
///positions (last, current, next)
pub struct Lexer<'a> {
    query: &'a str,
    chs : Chars<'a>,
    last: Option<char>,
    last_pos: Option<usize>,
    curr: Option<char>,
    curr_pos: Option<usize>,
    next: Option<char>,
    span_start: Option<usize>
}

impl<'a> Lexer<'a> {

    ///new lexer, everything set to None
    pub fn from_query<'b>(query: &'b str) -> Lexer<'b> {
        let mut lex = Lexer {
            query: query,
            curr: None,
            curr_pos: Some(0),
            last: None,
            last_pos: Some(0),
            next: None,
            span_start: Some(0),
            chs : query.chars()
        };
        lex.dbump();
        lex
    }

    ///bumper function advances to the next char
    fn bump(&mut self){

        //advance all pointers to the next char
        self.last = self.curr;
        self.curr = self.next;
        self.next = self.chs.next();

        //TODO: position-management
        // advance last_pos to position of current char
        self.last_pos = self.curr_pos;

        // next position is current position plus the utf8 length
        // of the next character
        match self.next {
            Some(c) => {
                self.curr_pos = Some(self.curr_pos.unwrap()
                    + c.len_utf8())
            }
            _ => {}
        };

    }

    ///double bump
    fn dbump(&mut self) {
        self.bump();
        self.bump();
    }

    ///scan each new WORD from the query string
    fn scan_words(&mut self) -> String {
        let mut s = String::new();
        //loop until the end of a word (only letters and _)
        loop {
            //take current char
            match self.curr.unwrap_or(' ') {
                c @ 'a' ... 'z' |
                c @ 'A' ... 'Z' |
                c @ '0' ... '9' |
                c @ '_' => {
                    //push letter into return string
                    s.push(c);
                },
                //if no letter, then stop loop
                _ => break
            }
            //next char
            self.bump();
        }
        s
    }

    ///scan each new NUMBER from the query string
    fn scan_nums(&mut self) -> String {
        let mut s = String::new();
        let mut dot = false;
        loop {
            match self.curr.unwrap_or(' ') {
                c @ '0' ... '9' => {
                    s.push(c);
                }
                c @ '.' => {
                    if dot {
                        println!("This is not a good number, Sir!");
                    }
                    dot = true;
                    s.push(c);
                },
                _ => break
            }
            self.bump();
        }
        s
    }

    fn scan_lit(&mut self) -> String {
        //liter = everything until " | ' , bump over ' | "
        let mut s = String::new();
        self.bump(); //to first char of literal
        loop {
            match self.curr.unwrap_or(' ') {
                c @ '\'' |
                c @ '"' => {
                    break
                }
                c @ _ => {
                    s.push(c);
                }
            }
            self.bump();
        }
        s
    }

    ///skips all the whitespaces
    fn skip_whitespace(&mut self) {
        while is_whitespace(self.curr.unwrap()){
            self.bump();
        }
    }
}

///checks for whitespace/line break/tab
fn is_whitespace(c: char) -> bool {
    match c {
        ' ' | '\n' | '\t' => true,
        _ => false
    }
}

impl<'a> Iterator for Lexer<'a> {

    type Item = TokenSpan;

    fn next(&mut self) -> Option<TokenSpan> {

        //for two char ops (e.g. >=), we need to check the next char
        //if we are at the end of the string, we end
        let nexchar = self.next.unwrap_or('\x00');

        //saving the first pos of a token
        self.span_start = self.curr_pos;

        //if no current char available, return None
        if self.curr.is_none() {
            return None;
        }

        //unwrap current char and decide token class
        let token = match self.curr.unwrap_or('x') {

            //words
            'a' ... 'z' | 'A' ... 'Z' => {
                let w = self.scan_words();
                Token::Word(w)
            },

            //nums
            '0' ... '9' => {
                let n = self.scan_nums();
                Token::Num(n)

            },

            //semi
            ';' => {
                self.bump();
                Token::Semi
            },

            //dots
            '.' => {
                self.bump();
                Token::Dot
            },

            //commas
            ',' => {
                self.bump();
                Token::Comma
            },

            // //bang
            // '!' => {
            //     self.bump();
            //     Token::Bang
            // },

            // //question marks
            // '?' => {
            //     self.bump();
            //     Token::QMark
            // },

            //ParenOp
            '(' => {
                self.bump();
                Token::ParenOp
            },

            //ParenCl
            ')' => {
                self.bump();
                Token::ParenCl
            },

            //Literals
            '\'' | '"' => {
                let l = self.scan_lit();
                self.bump();
                Token::Literal(Lit::Str(l))
            },

            //Equ
            '=' => {
                self.bump();
                Token::Equ
            },

            //GEThan >=
            '>' if nexchar == '=' => {
                self.dbump(); //because two chars!
                Token::GEThan
            },

            //SEThan <=
            '<' if nexchar == '=' => {
                self.dbump();
                Token::SEThan
            },

            //GThan >
            '>' => {
                self.bump();
                Token::GThan
            },

            //SThan <
            '<' => {
                self.bump();
                Token::SThan
            },

            //NEqu !=
            '!' if nexchar == '=' => {
                self.dbump();
                Token::NEqu
            },

            //Add
            '+' => {
                self.bump();
                Token::Add
            },

            //Sub
            '-' => {
                self.bump();
                Token::Sub
            },

            //Div
            '/' => {
                self.bump();
                Token::Div
            }

            //Mod
            '%' => {
                self.bump();
                Token::Mod
            }

            //Star
            '*' => {
                self.bump();
                Token::Star
            },

            //whitespaces
            c if is_whitespace(c) => {
                self.skip_whitespace();
                Token::Whitespace
            },

            //default: everything else
            _ => {
                self.bump();
                Token::Unknown
            }

        };

        //return Option
        Some(TokenSpan {
            tok: token,
            //currently 0 TODO
            span: Span { lo: self.span_start.unwrap(), hi: self.curr_pos.unwrap()}
        })
    }
}
<commit_msg>Change words to lowercase in lexer<commit_after>use super::token::{Token, TokenSpan, Lit};
use std::str::Chars;
use super::Span;
use std::iter::{Iterator};

///A lexer with its associated query, a char iterator, and
///positions (last, current, next)
pub struct Lexer<'a> {
    query: &'a str,
    chs : Chars<'a>,
    last: Option<char>,
    last_pos: Option<usize>,
    curr: Option<char>,
    curr_pos: Option<usize>,
    next: Option<char>,
    span_start: Option<usize>
}

impl<'a> Lexer<'a> {

    ///new lexer, everything set to None
    pub fn from_query<'b>(query: &'b str) -> Lexer<'b> {
        let mut lex = Lexer {
            query: query,
            curr: None,
            curr_pos: Some(0),
            last: None,
            last_pos: Some(0),
            next: None,
            span_start: Some(0),
            chs : query.chars()
        };
        lex.dbump();
        lex
    }

    ///bumper function advances to the next char
    fn bump(&mut self){

        //advance all pointers to the next char
        self.last = self.curr;
        self.curr = self.next;
        self.next = self.chs.next();

        //TODO: position-management
        // advance last_pos to position of current char
        self.last_pos = self.curr_pos;

        // next position is current position plus the utf8 length
        // of the next character
        match self.next {
            Some(c) => {
                self.curr_pos = Some(self.curr_pos.unwrap()
                    + c.len_utf8())
            }
            _ => {}
        };

    }

    ///double bump
    fn dbump(&mut self) {
        self.bump();
        self.bump();
    }

    ///scan each new WORD from the query string
    fn scan_words(&mut self) -> String {
        let mut s = String::new();
        //loop until the end of a word (only letters and _)
        loop {
            //take current char
            match self.curr.unwrap_or(' ') {
                c @ 'a' ... 'z' |
                c @ 'A' ... 'Z' |
                c @ '0' ... '9' |
                c @ '_' => {
                    //push letter into return string
                    s.push(c);
                },
                //if no letter, then stop loop
                _ => break
            }
            //next char
            self.bump();
        }
        s
    }

    ///scan each new NUMBER from the query string
    fn scan_nums(&mut self) -> String {
        let mut s = String::new();
        let mut dot = false;
        loop {
            match self.curr.unwrap_or(' ') {
                c @ '0' ... '9' => {
                    s.push(c);
                }
                c @ '.' => {
                    if dot {
                        println!("This is not a good number, Sir!");
                    }
                    dot = true;
                    s.push(c);
                },
                _ => break
            }
            self.bump();
        }
        s
    }

    fn scan_lit(&mut self) -> String {
        //liter = everything until " | ' , bump over ' | "
        let mut s = String::new();
        self.bump(); //to first char of literal
        loop {
            match self.curr.unwrap_or(' ') {
                c @ '\'' |
                c @ '"' => {
                    break
                }
                c @ _ => {
                    s.push(c);
                }
            }
            self.bump();
        }
        s
    }

    ///skips all the whitespaces
    fn skip_whitespace(&mut self) {
        while is_whitespace(self.curr.unwrap()){
            self.bump();
        }
    }
}

///checks for whitespace/line break/tab
fn is_whitespace(c: char) -> bool {
    match c {
        ' ' | '\n' | '\t' => true,
        _ => false
    }
}

impl<'a> Iterator for Lexer<'a> {

    type Item = TokenSpan;

    fn next(&mut self) -> Option<TokenSpan> {

        //for two char ops (e.g. >=), we need to check the next char
        //if we are at the end of the string, we end
        let nexchar = self.next.unwrap_or('\x00');

        //saving the first pos of a token
        self.span_start = self.curr_pos;

        //if no current char available, return None
        if self.curr.is_none() {
            return None;
        }

        //unwrap current char and decide token class
        let token = match self.curr.unwrap_or('x') {

            //words
            'a' ... 'z' | 'A' ... 'Z' => {
                let w = self.scan_words();
                Token::Word(w.to_lowercase())
            },

            //nums
            '0' ... '9' => {
                let n = self.scan_nums();
                Token::Num(n)

            },

            //semi
            ';' => {
                self.bump();
                Token::Semi
            },

            //dots
            '.' => {
                self.bump();
                Token::Dot
            },

            //commas
            ',' => {
                self.bump();
                Token::Comma
            },

            // //bang
            // '!' => {
            //     self.bump();
            //     Token::Bang
            // },

            // //question marks
            // '?' => {
            //     self.bump();
            //     Token::QMark
            // },

            //ParenOp
            '(' => {
                self.bump();
                Token::ParenOp
            },

            //ParenCl
            ')' => {
                self.bump();
                Token::ParenCl
            },

            //Literals
            '\'' | '"' => {
                let l = self.scan_lit();
                self.bump();
                Token::Literal(Lit::Str(l))
            },

            //Equ
            '=' => {
                self.bump();
                Token::Equ
            },

            //GEThan >=
            '>' if nexchar == '=' => {
                self.dbump(); //because two chars!
                Token::GEThan
            },

            //SEThan <=
            '<' if nexchar == '=' => {
                self.dbump();
                Token::SEThan
            },

            //GThan >
            '>' => {
                self.bump();
                Token::GThan
            },

            //SThan <
            '<' => {
                self.bump();
                Token::SThan
            },

            //NEqu !=
            '!' if nexchar == '=' => {
                self.dbump();
                Token::NEqu
            },

            //Add
            '+' => {
                self.bump();
                Token::Add
            },

            //Sub
            '-' => {
                self.bump();
                Token::Sub
            },

            //Div
            '/' => {
                self.bump();
                Token::Div
            }

            //Mod
            '%' => {
                self.bump();
                Token::Mod
            }

            //Star
            '*' => {
                self.bump();
                Token::Star
            },

            //whitespaces
            c if is_whitespace(c) => {
                self.skip_whitespace();
                Token::Whitespace
            },

            //default: everything else
            _ => {
                self.bump();
                Token::Unknown
            }

        };

        //return Option
        Some(TokenSpan {
            tok: token,
            //currently 0 TODO
            span: Span { lo: self.span_start.unwrap(), hi: self.curr_pos.unwrap()}
        })
    }
}
<|endoftext|>