<commit_before>use alloc::arc::Weak;
use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{mem, usize};
use spin::{Mutex, RwLock};

use arch;
use arch::paging::{InactivePageTable, Page, VirtualAddress, entry};
use arch::paging::temporary_page::TemporaryPage;
use context::{self, Context};
use context::memory::Grant;
use syscall::data::{Packet, Stat};
use syscall::error::*;
use syscall::number::*;
use syscall::scheme::Scheme;

pub struct UserInner {
    pub scheme_id: AtomicUsize,
    next_id: AtomicUsize,
    context: Weak<RwLock<Context>>,
    todo: Mutex<VecDeque<Packet>>,
    done: Mutex<BTreeMap<usize, usize>>
}

impl UserInner {
    pub fn new(context: Weak<RwLock<Context>>) -> UserInner {
        UserInner {
            scheme_id: AtomicUsize::new(0),
            next_id: AtomicUsize::new(1),
            context: context,
            todo: Mutex::new(VecDeque::new()),
            done: Mutex::new(BTreeMap::new())
        }
    }

    pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
        let id = self.next_id.fetch_add(1, Ordering::SeqCst);

        let packet = Packet {
            id: id,
            a: a,
            b: b,
            c: c,
            d: d
        };

        self.todo.lock().push_back(packet);

        loop {
            {
                let mut done = self.done.lock();
                if let Some(a) = done.remove(&id) {
                    return Error::demux(a);
                }
            }

            unsafe { context::switch(); } //TODO: Block
        }
    }

    pub fn capture(&self, buf: &[u8]) -> Result<usize> {
        self.capture_inner(buf.as_ptr() as usize, buf.len(), false)
    }

    pub fn capture_mut(&self, buf: &mut [u8]) -> Result<usize> {
        self.capture_inner(buf.as_mut_ptr() as usize, buf.len(), true)
    }

    fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> {
        if size == 0 {
            Ok(0)
        } else {
            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
            let context = context_lock.read();

            let mut grants = context.grants.lock();

            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));

            let from_address = (address/4096) * 4096;
            let offset = address - from_address;
            let full_size = ((offset + size + 4095)/4096) * 4096;
            let mut to_address = arch::USER_GRANT_OFFSET;

            let mut flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE;
            if writable {
                flags |= entry::WRITABLE;
            }

            for i in 0 .. grants.len() {
                let start = grants[i].start_address().get();
                if to_address + full_size < start {
                    grants.insert(i, Grant::map_inactive(
                        VirtualAddress::new(from_address),
                        VirtualAddress::new(to_address),
                        full_size,
                        flags,
                        &mut new_table,
                        &mut temporary_page
                    ));

                    return Ok(to_address + offset);
                } else {
                    let pages = (grants[i].size() + 4095) / 4096;
                    let end = start + pages * 4096;
                    to_address = end;
                }
            }

            grants.push(Grant::map_inactive(
                VirtualAddress::new(from_address),
                VirtualAddress::new(to_address),
                full_size,
                flags,
                &mut new_table,
                &mut temporary_page
            ));

            Ok(to_address + offset)
        }
    }

    pub fn release(&self, address: usize) -> Result<()> {
        if address == 0 {
            Ok(())
        } else {
            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
            let context = context_lock.read();

            let mut grants = context.grants.lock();

            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));

            for i in 0 .. grants.len() {
                let start = grants[i].start_address().get();
                let end = start + grants[i].size();
                if address >= start && address < end {
                    grants.remove(i).unmap_inactive(&mut new_table, &mut temporary_page);

                    return Ok(());
                }
            }

            Err(Error::new(EFAULT))
        }
    }

    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let packet_size = mem::size_of::<Packet>();
        let len = buf.len()/packet_size;
        if len > 0 {
            loop {
                let mut i = 0;
                {
                    let mut todo = self.todo.lock();
                    while ! todo.is_empty() && i < len {
                        let packet = todo.pop_front().unwrap();
                        unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = packet; }
                        i += 1;
                    }
                }

                if i > 0 {
                    return Ok(i * packet_size);
                } else {
                    unsafe { context::switch(); } //TODO: Block
                }
            }
        } else {
            Ok(0)
        }
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        let packet_size = mem::size_of::<Packet>();
        let len = buf.len()/packet_size;
        let mut i = 0;
        while i < len {
            let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
            if packet.id == 0 {
                match packet.a {
                    SYS_FEVENT => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d),
                    _ => println!("Unknown scheme -> kernel message {}", packet.a)
                }
            } else {
                self.done.lock().insert(packet.id, packet.a);
            }
            i += 1;
        }

        Ok(i * packet_size)
    }
}

/// UserInner has to be wrapped
pub struct UserScheme {
    inner: Weak<UserInner>
}

impl UserScheme {
    pub fn new(inner: Weak<UserInner>) -> UserScheme {
        UserScheme {
            inner: inner
        }
    }
}

impl Scheme for UserScheme {
    fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture(path)?;
        let result = inner.call(SYS_OPEN, address, path.len(), flags);
        let _ = inner.release(address);
        result
    }

    fn dup(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_DUP, file, 0, 0)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture_mut(buf)?;
        let result = inner.call(SYS_READ, file, address, buf.len());
        let _ = inner.release(address);
        result
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture(buf)?;
        let result = inner.call(SYS_WRITE, file, address, buf.len());
        let _ = inner.release(address);
        result
    }

    fn seek(&self, file: usize, position: usize, whence: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_LSEEK, file, position, whence)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FEVENT, file, flags, 0)
    }

    fn fstat(&self, file: usize, stat: &mut Stat) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture_mut(stat)?;
        let result = inner.call(SYS_FSTAT, file, address, 0);
        let _ = inner.release(address);
        result
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FSYNC, file, 0, 0)
    }

    fn ftruncate(&self, file: usize, len: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FTRUNCATE, file, len, 0)
    }

    fn close(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_CLOSE, file, 0, 0)
    }
}
<commit_msg>Fix kernel user scheme fpath<commit_after>use alloc::arc::Weak;
use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{mem, usize};
use spin::{Mutex, RwLock};

use arch;
use arch::paging::{InactivePageTable, Page, VirtualAddress, entry};
use arch::paging::temporary_page::TemporaryPage;
use context::{self, Context};
use context::memory::Grant;
use syscall::data::{Packet, Stat};
use syscall::error::*;
use syscall::number::*;
use syscall::scheme::Scheme;

pub struct UserInner {
    pub scheme_id: AtomicUsize,
    next_id: AtomicUsize,
    context: Weak<RwLock<Context>>,
    todo: Mutex<VecDeque<Packet>>,
    done: Mutex<BTreeMap<usize, usize>>
}

impl UserInner {
    pub fn new(context: Weak<RwLock<Context>>) -> UserInner {
        UserInner {
            scheme_id: AtomicUsize::new(0),
            next_id: AtomicUsize::new(1),
            context: context,
            todo: Mutex::new(VecDeque::new()),
            done: Mutex::new(BTreeMap::new())
        }
    }

    pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
        let id = self.next_id.fetch_add(1, Ordering::SeqCst);

        let packet = Packet {
            id: id,
            a: a,
            b: b,
            c: c,
            d: d
        };

        self.todo.lock().push_back(packet);

        loop {
            {
                let mut done = self.done.lock();
                if let Some(a) = done.remove(&id) {
                    return Error::demux(a);
                }
            }

            unsafe { context::switch(); } //TODO: Block
        }
    }

    pub fn capture(&self, buf: &[u8]) -> Result<usize> {
        self.capture_inner(buf.as_ptr() as usize, buf.len(), false)
    }

    pub fn capture_mut(&self, buf: &mut [u8]) -> Result<usize> {
        self.capture_inner(buf.as_mut_ptr() as usize, buf.len(), true)
    }

    fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> {
        if size == 0 {
            Ok(0)
        } else {
            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
            let context = context_lock.read();

            let mut grants = context.grants.lock();

            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));

            let from_address = (address/4096) * 4096;
            let offset = address - from_address;
            let full_size = ((offset + size + 4095)/4096) * 4096;
            let mut to_address = arch::USER_GRANT_OFFSET;

            let mut flags = entry::PRESENT | entry::NO_EXECUTE | entry::USER_ACCESSIBLE;
            if writable {
                flags |= entry::WRITABLE;
            }

            for i in 0 .. grants.len() {
                let start = grants[i].start_address().get();
                if to_address + full_size < start {
                    grants.insert(i, Grant::map_inactive(
                        VirtualAddress::new(from_address),
                        VirtualAddress::new(to_address),
                        full_size,
                        flags,
                        &mut new_table,
                        &mut temporary_page
                    ));

                    return Ok(to_address + offset);
                } else {
                    let pages = (grants[i].size() + 4095) / 4096;
                    let end = start + pages * 4096;
                    to_address = end;
                }
            }

            grants.push(Grant::map_inactive(
                VirtualAddress::new(from_address),
                VirtualAddress::new(to_address),
                full_size,
                flags,
                &mut new_table,
                &mut temporary_page
            ));

            Ok(to_address + offset)
        }
    }

    pub fn release(&self, address: usize) -> Result<()> {
        if address == 0 {
            Ok(())
        } else {
            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
            let context = context_lock.read();

            let mut grants = context.grants.lock();

            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));

            for i in 0 .. grants.len() {
                let start = grants[i].start_address().get();
                let end = start + grants[i].size();
                if address >= start && address < end {
                    grants.remove(i).unmap_inactive(&mut new_table, &mut temporary_page);

                    return Ok(());
                }
            }

            Err(Error::new(EFAULT))
        }
    }

    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
        let packet_size = mem::size_of::<Packet>();
        let len = buf.len()/packet_size;
        if len > 0 {
            loop {
                let mut i = 0;
                {
                    let mut todo = self.todo.lock();
                    while ! todo.is_empty() && i < len {
                        let packet = todo.pop_front().unwrap();
                        unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = packet; }
                        i += 1;
                    }
                }

                if i > 0 {
                    return Ok(i * packet_size);
                } else {
                    unsafe { context::switch(); } //TODO: Block
                }
            }
        } else {
            Ok(0)
        }
    }

    pub fn write(&self, buf: &[u8]) -> Result<usize> {
        let packet_size = mem::size_of::<Packet>();
        let len = buf.len()/packet_size;
        let mut i = 0;
        while i < len {
            let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
            if packet.id == 0 {
                match packet.a {
                    SYS_FEVENT => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d),
                    _ => println!("Unknown scheme -> kernel message {}", packet.a)
                }
            } else {
                self.done.lock().insert(packet.id, packet.a);
            }
            i += 1;
        }

        Ok(i * packet_size)
    }
}

/// UserInner has to be wrapped
pub struct UserScheme {
    inner: Weak<UserInner>
}

impl UserScheme {
    pub fn new(inner: Weak<UserInner>) -> UserScheme {
        UserScheme {
            inner: inner
        }
    }
}

impl Scheme for UserScheme {
    fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture(path)?;
        let result = inner.call(SYS_OPEN, address, path.len(), flags);
        let _ = inner.release(address);
        result
    }

    fn dup(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_DUP, file, 0, 0)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture_mut(buf)?;
        let result = inner.call(SYS_READ, file, address, buf.len());
        let _ = inner.release(address);
        result
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture(buf)?;
        let result = inner.call(SYS_WRITE, file, address, buf.len());
        let _ = inner.release(address);
        result
    }

    fn seek(&self, file: usize, position: usize, whence: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_LSEEK, file, position, whence)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FEVENT, file, flags, 0)
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture_mut(buf)?;
        let result = inner.call(SYS_FPATH, file, address, buf.len());
        let _ = inner.release(address);
        result
    }

    fn fstat(&self, file: usize, stat: &mut Stat) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        let address = inner.capture_mut(stat)?;
        let result = inner.call(SYS_FSTAT, file, address, 0);
        let _ = inner.release(address);
        result
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FSYNC, file, 0, 0)
    }

    fn ftruncate(&self, file: usize, len: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_FTRUNCATE, file, len, 0)
    }

    fn close(&self, file: usize) -> Result<usize> {
        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
        inner.call(SYS_CLOSE, file, 0, 0)
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&find_args(s)[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<commit_msg>Added in debug flag forwarding<commit_after>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };
    let is_debug = env::args().skip(1).filter(|x| x == "--debug").next().is_some();

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            let subcommand_args = &find_args(s)[..];
            if is_debug {
                subcommand_args.push("--debug");
            }
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(subcommand_args)
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<|endoftext|>


<commit_before>use neb::ram::schema::Field;
use neb::ram::cell::{MAX_CELL_SIZE, Cell};
use neb::ram::types::{TypeId, Id, Map, Value, id_io, u32_io, key_hash};
use neb::client::transaction::{Transaction, TxnError};

use std::collections::BTreeSet;

use utils::transaction::set_map_by_key_id;

pub const NEXT_KEY: &'static str = "_next";
pub const LIST_KEY: &'static str = "_list";

pub enum IdListError {
    ContainerCellNotFound,
    FormatError,
    Unexpected,
    TxnError(TxnError)
}

pub static ID_LIST_SCHEMA_ID: u32 = 100;

lazy_static! {
    pub static ref ID_LINKED_LIST: Vec<Field> = vec![
            Field::new(&String::from(NEXT_KEY), TypeId::Id as u32, false, false, None),
            Field::new(&String::from(LIST_KEY), TypeId::Id as u32, false, true, None)
          ];
    pub static ref LIST_CAPACITY: usize =
        ((MAX_CELL_SIZE - u32_io::size(0) - id_io::size(0)) / id_io::size(0));
    pub static ref NEXT_KEY_ID: u64 = key_hash(&String::from(NEXT_KEY));
    pub static ref LIST_KEY_ID: u64 = key_hash(&String::from(LIST_KEY));
    pub static ref NEXT_KEY_ID_VEC: Vec<u64> = vec![*NEXT_KEY_ID];
}

pub struct IdList<'a> {
    txn: &'a mut Transaction,
    container_id: Id,
    field_id: u64
}

fn empty_list_segment(container_id: &Id, level: usize) -> (Id, Value) {
    let str_id = format!("IDLIST-{},{}-{}", container_id.higher, container_id.lower, 1);
    let list_id = Id::new(container_id.higher, key_hash(&str_id));
    let mut list_map = Map::new();
    list_map.insert_key_id(*NEXT_KEY_ID, Value::Id(Id::unit_id()));
    list_map.insert_key_id(*LIST_KEY_ID, Value::Array(Vec::<Value>::new()));
    return (list_id, Value::Map(list_map));
}

fn count_cell_list(seg: &Cell) -> Result<usize, IdListError> {
    if let &Value::Map(ref map) = &seg.data {
        if let &Value::Array(ref array) = map.get_by_key_id(*LIST_KEY_ID) {
            Ok(array.len())
        } else {
            Err(IdListError::FormatError)
        }
    } else {
        Err(IdListError::FormatError)
    }
}

fn val_is_id(val: &Value, id: &Id) -> bool {
    if let &Value::Id(ref val_id) = val {
        return val_id != id;
    } else {
        return true;
    }
}

fn seg_cell_by_id(txn: &mut Transaction, id: Option<Id>) -> Result<Option<Cell>, IdListError> {
    match id {
        Some(id) => match txn.read(&id) {
            Ok(cell) => Ok(cell),
            Err(e) => Err(IdListError::TxnError(e))
        },
        None => Ok(None)
    }
}

impl<'a> IdList <'a> {
    pub fn from_txn_and_container(txn: &'a mut Transaction, container_id: &Id, field_id: u64) -> IdList<'a> {
        IdList {
            txn: txn,
            container_id: *container_id,
            field_id: field_id,
        }
    }
    fn get_root_list_id(&mut self, ensure_container: bool) -> Result<Id, IdListError> {
        match self.txn.read_selected(&self.container_id, &vec![self.field_id]) {
            Err(e) => Err(IdListError::TxnError(e)),
            Ok(Some(fields)) => {
                if let Some(&Value::Id(id)) = fields.get(0) {
                    if id == Id::unit_id() && ensure_container {
                        let (list_id, list_value) = empty_list_segment(&self.container_id, 0);
                        let list_cell = Cell::new_with_id(ID_LIST_SCHEMA_ID, &list_id, list_value);
                        match self.txn.write(&list_cell) {
                            Ok(()) => {},
                            Err(e) => return Err(IdListError::TxnError(e))
                        }
                        set_map_by_key_id(self.txn, &self.container_id, self.field_id, Value::Id(list_id));
                        Ok(list_id)
                    } else {
                        Ok(id)
                    }
                } else {
                    Err(IdListError::FormatError)
                }
            },
            Ok(None) => {
                Err(IdListError::ContainerCellNotFound)
            }
        }
    }
    pub fn iter(&mut self) -> Result<IdListIterator, IdListError> {
        let list_root_id = self.get_root_list_id(false)?;
        let mut segments = IdListSegmentIterator::new(&mut self.txn, list_root_id);
        let current_seg = segments.next();
        Ok(IdListIterator {
            segments: segments,
            current_seg: current_seg,
            current_pos: 0,
        })
    }
    pub fn all(&mut self) -> Result<Vec<Id>, IdListError> {
        Ok(self.iter()?.collect())
    }
    pub fn count(&mut self) -> Result<usize, IdListError> {
        Ok(self.iter()?.count())
    }
    pub fn add(&mut self, id: Id) -> Result<(), IdListError> {
        let list_root_id = self.get_root_list_id(true)?;
        let mut list_level = 0;
        let mut last_seg = {
            let last_seg_id = {
                let mut segments = IdListSegmentIdIterator::new(&mut self.txn, list_root_id);
                let mut last_seg_id = None;
                for seg in segments {
                    list_level += 1;
                    last_seg_id = Some(seg);
                }
                last_seg_id
            };
            let last_seg = seg_cell_by_id(&mut self.txn, last_seg_id)?;
            if let Some(seg) = last_seg { seg } else { return Err(IdListError::Unexpected); }
        };
        if count_cell_list(&mut last_seg)? >= *LIST_CAPACITY { // create new segment to prevent cell overflow
            list_level += 1;
            let (next_seg_id, next_seg_value) = empty_list_segment(&self.container_id, list_level);
            let next_seg_cell = Cell::new_with_id(ID_LIST_SCHEMA_ID, &next_seg_id, next_seg_value);
            match self.txn.write(&next_seg_cell) {
                Ok(()) => {},
                Err(e) => return Err(IdListError::TxnError(e))
            }
            set_map_by_key_id(&mut self.txn, &last_seg.id(), *NEXT_KEY_ID, Value::Id(next_seg_id));
            last_seg = next_seg_cell;
        }
        if let &mut Value::Map(ref mut map) = &mut last_seg.data {
            if let Some(&mut Value::Array(ref mut array)) = map.get_mut_by_key_id(*LIST_KEY_ID) {
                array.push(Value::Id(id));
            } else {
                return Err(IdListError::FormatError);
            }
        } else {
            return Err(IdListError::FormatError);
        }
        match self.txn.update(&last_seg) {
            Ok(()) => Ok(()),
            Err(e) => Err(IdListError::TxnError(e))
        }
    }
    pub fn remove(&mut self, id: Id, all: bool) -> Result<(), IdListError> {
        let id_value = Value::Id(id);
        let mut contained_segs = { // collect affected segment cell ids
            let mut iter = self.iter()?;
            let mut seg_ids = BTreeSet::new();
            while true {
                if let Some(iter_id) = iter.next() {
                    if iter_id == id {
                        if let Some(ref seg) = iter.current_seg {
                            seg_ids.insert(seg.id());
                        } else {
                            return Err(IdListError::Unexpected);
                        }
                    }
                } else {
                    break;
                }
            }
            seg_ids
        };
        for seg_id in &contained_segs { // mutate cell array
            match self.txn.read(seg_id) {
                Ok(Some(mut seg)) => {
                    if let &mut Value::Map(ref mut map) = &mut seg.data {
                        if let Some(&mut Value::Array(ref mut array)) = map.get_mut_by_key_id(*LIST_KEY_ID) {
                            if all {
                                array.retain(|v| { !val_is_id(v, &id) });
                            } else {
                                let index = match array.iter().position(|v| { val_is_id(v, &id) }) {
                                    Some(pos) => pos, None => return Err(IdListError::Unexpected)
                                };
                                array.remove(index);
                            }
                        } else {
                            return Err(IdListError::FormatError);
                        }
                    } else {
                        return Err(IdListError::FormatError);
                    }
                    self.txn.update(&seg);
                    if !all { break; }
                },
                Ok(None) => return Err(IdListError::Unexpected),
                Err(e) => return Err(IdListError::TxnError(e)),
            }
        }
        return Ok(());
    }
    pub fn clear(&mut self) -> Result<(), IdListError> {
        let list_root_id = self.get_root_list_id(true)?;
        let segments: Vec<_> = IdListSegmentIdIterator::new(&mut self.txn, list_root_id).collect();
        for seg_id in segments {
            match self.txn.remove(&seg_id) {
                Ok(()) => {},
                Err(e) => return Err(IdListError::TxnError(e))
            }
        }
        set_map_by_key_id(self.txn, &self.container_id, self.field_id, Value::Id(Id::unit_id()));
        return Ok(())
    }
}

pub struct IdListSegmentIdIterator<'a> {
    txn: &'a mut Transaction,
    next: Id,
    level: u32
}

impl <'a> IdListSegmentIdIterator<'a> {
    pub fn new(txn: &'a mut Transaction, head_id: Id) -> IdListSegmentIdIterator<'a> {
        IdListSegmentIdIterator {
            txn: txn,
            next: head_id,
            level: 1
        }
    }
}

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

    type Item = Id;

    fn next(&mut self) -> Option<Self::Item> {
        if !self.next.is_unit_id() {
            match self.txn.read_selected(&self.next, &*NEXT_KEY_ID_VEC) {
                Ok(Some(fields)) => {
                    let current_id = self.next;
                    if let Some(&Value::Id(ref id)) = fields.get(0) {
                        self.next = *id;
                        self.level += 1;
                        return Some(current_id);
                    }
                },
                _ => {}
            }
        }
        None
    }
}

pub struct IdListSegmentIterator<'a> {
    id_iter: IdListSegmentIdIterator<'a>
}

impl <'a>IdListSegmentIterator<'a> {
    pub fn new(txn: &'a mut Transaction, head_id: Id) -> IdListSegmentIterator<'a> {
        IdListSegmentIterator {
            id_iter: IdListSegmentIdIterator::new(txn, head_id)
        }
    }
}

impl <'a> Iterator for IdListSegmentIterator <'a> {
    type Item = Cell;

    fn next(&mut self) -> Option<Self::Item> {
        let next_id = self.id_iter.next();
        if let Ok(Some(cell)) = seg_cell_by_id(self.id_iter.txn, next_id) {
            Some(cell)
        } else {
            None
        }
    }
}

pub struct IdListIterator<'a> {
    segments: IdListSegmentIterator<'a>,
    current_seg: Option<Cell>,
    current_pos: u32
}

impl <'a> IdListIterator <'a> {
    pub fn next_seg(&mut self) {
        self.current_seg = self.segments.next();
        self.current_pos = 0;
    }
}

impl <'a> Iterator for IdListIterator<'a> {
    type Item = Id;

    fn next(&mut self) -> Option<Self::Item> {
        let mut need_next_seg = false;
        if let Some(ref cell) = self.current_seg {
            let pos = self.current_pos;
            self.current_pos += 1;
            if let &Value::Map(ref map) = &cell.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    if let Some(&Value::Id(id)) = list.get(pos as usize) {
                        return Some(id);
                    } else {
                        need_next_seg = true
                    }
                }
            }
        };
        if need_next_seg {
            self.next_seg();
            self.next()
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> where Self: Sized {
        if let Some(last_seg) = self.segments.last() {
            if let &Value::Map(ref map) = &last_seg.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    if let Some(&Value::Id(id)) = list.last() {
                        return Some(id);
                    }
                }
            }
        }
        return None;
    }
    fn count(self) -> usize where Self: Sized {
        let mut count = 0;
        for seg in self.segments {
            if let &Value::Map(ref map) = &seg.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    count += list.len();
                }
            }
        }
        return count;
    }
}

<commit_msg>fix list segment id from level<commit_after>use neb::ram::schema::Field;
use neb::ram::cell::{MAX_CELL_SIZE, Cell};
use neb::ram::types::{TypeId, Id, Map, Value, id_io, u32_io, key_hash};
use neb::client::transaction::{Transaction, TxnError};

use std::collections::BTreeSet;

use utils::transaction::set_map_by_key_id;

pub const NEXT_KEY: &'static str = "_next";
pub const LIST_KEY: &'static str = "_list";

pub enum IdListError {
    ContainerCellNotFound,
    FormatError,
    Unexpected,
    TxnError(TxnError)
}

pub static ID_LIST_SCHEMA_ID: u32 = 100;

lazy_static! {
    pub static ref ID_LINKED_LIST: Vec<Field> = vec![
            Field::new(&String::from(NEXT_KEY), TypeId::Id as u32, false, false, None),
            Field::new(&String::from(LIST_KEY), TypeId::Id as u32, false, true, None)
          ];
    pub static ref LIST_CAPACITY: usize =
        ((MAX_CELL_SIZE - u32_io::size(0) - id_io::size(0)) / id_io::size(0));
    pub static ref NEXT_KEY_ID: u64 = key_hash(&String::from(NEXT_KEY));
    pub static ref LIST_KEY_ID: u64 = key_hash(&String::from(LIST_KEY));
    pub static ref NEXT_KEY_ID_VEC: Vec<u64> = vec![*NEXT_KEY_ID];
}

pub struct IdList<'a> {
    txn: &'a mut Transaction,
    container_id: Id,
    field_id: u64
}

fn empty_list_segment(container_id: &Id, level: usize) -> (Id, Value) {
    let str_id = format!("IDLIST-{},{}-{}", container_id.higher, container_id.lower, level);
    let list_id = Id::new(container_id.higher, key_hash(&str_id));
    let mut list_map = Map::new();
    list_map.insert_key_id(*NEXT_KEY_ID, Value::Id(Id::unit_id()));
    list_map.insert_key_id(*LIST_KEY_ID, Value::Array(Vec::<Value>::new()));
    return (list_id, Value::Map(list_map));
}

fn count_cell_list(seg: &Cell) -> Result<usize, IdListError> {
    if let &Value::Map(ref map) = &seg.data {
        if let &Value::Array(ref array) = map.get_by_key_id(*LIST_KEY_ID) {
            Ok(array.len())
        } else {
            Err(IdListError::FormatError)
        }
    } else {
        Err(IdListError::FormatError)
    }
}

fn val_is_id(val: &Value, id: &Id) -> bool {
    if let &Value::Id(ref val_id) = val {
        return val_id != id;
    } else {
        return true;
    }
}

fn seg_cell_by_id(txn: &mut Transaction, id: Option<Id>) -> Result<Option<Cell>, IdListError> {
    match id {
        Some(id) => match txn.read(&id) {
            Ok(cell) => Ok(cell),
            Err(e) => Err(IdListError::TxnError(e))
        },
        None => Ok(None)
    }
}

impl<'a> IdList <'a> {
    pub fn from_txn_and_container(txn: &'a mut Transaction, container_id: &Id, field_id: u64) -> IdList<'a> {
        IdList {
            txn: txn,
            container_id: *container_id,
            field_id: field_id,
        }
    }
    fn get_root_list_id(&mut self, ensure_container: bool) -> Result<Id, IdListError> {
        match self.txn.read_selected(&self.container_id, &vec![self.field_id]) {
            Err(e) => Err(IdListError::TxnError(e)),
            Ok(Some(fields)) => {
                if let Some(&Value::Id(id)) = fields.get(0) {
                    if id == Id::unit_id() && ensure_container {
                        let (list_id, list_value) = empty_list_segment(&self.container_id, 0);
                        let list_cell = Cell::new_with_id(ID_LIST_SCHEMA_ID, &list_id, list_value);
                        match self.txn.write(&list_cell) {
                            Ok(()) => {},
                            Err(e) => return Err(IdListError::TxnError(e))
                        }
                        set_map_by_key_id(self.txn, &self.container_id, self.field_id, Value::Id(list_id));
                        Ok(list_id)
                    } else {
                        Ok(id)
                    }
                } else {
                    Err(IdListError::FormatError)
                }
            },
            Ok(None) => {
                Err(IdListError::ContainerCellNotFound)
            }
        }
    }
    pub fn iter(&mut self) -> Result<IdListIterator, IdListError> {
        let list_root_id = self.get_root_list_id(false)?;
        let mut segments = IdListSegmentIterator::new(&mut self.txn, list_root_id);
        let current_seg = segments.next();
        Ok(IdListIterator {
            segments: segments,
            current_seg: current_seg,
            current_pos: 0,
        })
    }
    pub fn all(&mut self) -> Result<Vec<Id>, IdListError> {
        Ok(self.iter()?.collect())
    }
    pub fn count(&mut self) -> Result<usize, IdListError> {
        Ok(self.iter()?.count())
    }
    pub fn add(&mut self, id: Id) -> Result<(), IdListError> {
        let list_root_id = self.get_root_list_id(true)?;
        let mut list_level = 0;
        let mut last_seg = {
            let last_seg_id = {
                let mut segments = IdListSegmentIdIterator::new(&mut self.txn, list_root_id);
                let mut last_seg_id = None;
                for seg in segments {
                    list_level += 1;
                    last_seg_id = Some(seg);
                }
                last_seg_id
            };
            let last_seg = seg_cell_by_id(&mut self.txn, last_seg_id)?;
            if let Some(seg) = last_seg { seg } else { return Err(IdListError::Unexpected); }
        };
        if count_cell_list(&mut last_seg)? >= *LIST_CAPACITY { // create new segment to prevent cell overflow
            list_level += 1;
            let (next_seg_id, next_seg_value) = empty_list_segment(&self.container_id, list_level);
            let next_seg_cell = Cell::new_with_id(ID_LIST_SCHEMA_ID, &next_seg_id, next_seg_value);
            match self.txn.write(&next_seg_cell) {
                Ok(()) => {},
                Err(e) => return Err(IdListError::TxnError(e))
            }
            set_map_by_key_id(&mut self.txn, &last_seg.id(), *NEXT_KEY_ID, Value::Id(next_seg_id));
            last_seg = next_seg_cell;
        }
        if let &mut Value::Map(ref mut map) = &mut last_seg.data {
            if let Some(&mut Value::Array(ref mut array)) = map.get_mut_by_key_id(*LIST_KEY_ID) {
                array.push(Value::Id(id));
            } else {
                return Err(IdListError::FormatError);
            }
        } else {
            return Err(IdListError::FormatError);
        }
        match self.txn.update(&last_seg) {
            Ok(()) => Ok(()),
            Err(e) => Err(IdListError::TxnError(e))
        }
    }
    pub fn remove(&mut self, id: Id, all: bool) -> Result<(), IdListError> {
        let id_value = Value::Id(id);
        let mut contained_segs = { // collect affected segment cell ids
            let mut iter = self.iter()?;
            let mut seg_ids = BTreeSet::new();
            while true {
                if let Some(iter_id) = iter.next() {
                    if iter_id == id {
                        if let Some(ref seg) = iter.current_seg {
                            seg_ids.insert(seg.id());
                        } else {
                            return Err(IdListError::Unexpected);
                        }
                    }
                } else {
                    break;
                }
            }
            seg_ids
        };
        for seg_id in &contained_segs { // mutate cell array
            match self.txn.read(seg_id) {
                Ok(Some(mut seg)) => {
                    if let &mut Value::Map(ref mut map) = &mut seg.data {
                        if let Some(&mut Value::Array(ref mut array)) = map.get_mut_by_key_id(*LIST_KEY_ID) {
                            if all {
                                array.retain(|v| { !val_is_id(v, &id) });
                            } else {
                                let index = match array.iter().position(|v| { val_is_id(v, &id) }) {
                                    Some(pos) => pos, None => return Err(IdListError::Unexpected)
                                };
                                array.remove(index);
                            }
                        } else {
                            return Err(IdListError::FormatError);
                        }
                    } else {
                        return Err(IdListError::FormatError);
                    }
                    self.txn.update(&seg);
                    if !all { break; }
                },
                Ok(None) => return Err(IdListError::Unexpected),
                Err(e) => return Err(IdListError::TxnError(e)),
            }
        }
        return Ok(());
    }
    pub fn clear(&mut self) -> Result<(), IdListError> {
        let list_root_id = self.get_root_list_id(true)?;
        let segments: Vec<_> = IdListSegmentIdIterator::new(&mut self.txn, list_root_id).collect();
        for seg_id in segments {
            match self.txn.remove(&seg_id) {
                Ok(()) => {},
                Err(e) => return Err(IdListError::TxnError(e))
            }
        }
        set_map_by_key_id(self.txn, &self.container_id, self.field_id, Value::Id(Id::unit_id()));
        return Ok(())
    }
}

pub struct IdListSegmentIdIterator<'a> {
    txn: &'a mut Transaction,
    next: Id,
    level: u32
}

impl <'a> IdListSegmentIdIterator<'a> {
    pub fn new(txn: &'a mut Transaction, head_id: Id) -> IdListSegmentIdIterator<'a> {
        IdListSegmentIdIterator {
            txn: txn,
            next: head_id,
            level: 1
        }
    }
}

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

    type Item = Id;

    fn next(&mut self) -> Option<Self::Item> {
        if !self.next.is_unit_id() {
            match self.txn.read_selected(&self.next, &*NEXT_KEY_ID_VEC) {
                Ok(Some(fields)) => {
                    let current_id = self.next;
                    if let Some(&Value::Id(ref id)) = fields.get(0) {
                        self.next = *id;
                        self.level += 1;
                        return Some(current_id);
                    }
                },
                _ => {}
            }
        }
        None
    }
}

pub struct IdListSegmentIterator<'a> {
    id_iter: IdListSegmentIdIterator<'a>
}

impl <'a>IdListSegmentIterator<'a> {
    pub fn new(txn: &'a mut Transaction, head_id: Id) -> IdListSegmentIterator<'a> {
        IdListSegmentIterator {
            id_iter: IdListSegmentIdIterator::new(txn, head_id)
        }
    }
}

impl <'a> Iterator for IdListSegmentIterator <'a> {
    type Item = Cell;

    fn next(&mut self) -> Option<Self::Item> {
        let next_id = self.id_iter.next();
        if let Ok(Some(cell)) = seg_cell_by_id(self.id_iter.txn, next_id) {
            Some(cell)
        } else {
            None
        }
    }
}

pub struct IdListIterator<'a> {
    segments: IdListSegmentIterator<'a>,
    current_seg: Option<Cell>,
    current_pos: u32
}

impl <'a> IdListIterator <'a> {
    pub fn next_seg(&mut self) {
        self.current_seg = self.segments.next();
        self.current_pos = 0;
    }
}

impl <'a> Iterator for IdListIterator<'a> {
    type Item = Id;

    fn next(&mut self) -> Option<Self::Item> {
        let mut need_next_seg = false;
        if let Some(ref cell) = self.current_seg {
            let pos = self.current_pos;
            self.current_pos += 1;
            if let &Value::Map(ref map) = &cell.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    if let Some(&Value::Id(id)) = list.get(pos as usize) {
                        return Some(id);
                    } else {
                        need_next_seg = true
                    }
                }
            }
        };
        if need_next_seg {
            self.next_seg();
            self.next()
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> where Self: Sized {
        if let Some(last_seg) = self.segments.last() {
            if let &Value::Map(ref map) = &last_seg.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    if let Some(&Value::Id(id)) = list.last() {
                        return Some(id);
                    }
                }
            }
        }
        return None;
    }
    fn count(self) -> usize where Self: Sized {
        let mut count = 0;
        for seg in self.segments {
            if let &Value::Map(ref map) = &seg.data {
                if let &Value::Array(ref list) = map.get_by_key_id(*LIST_KEY_ID) {
                    count += list.len();
                }
            }
        }
        return count;
    }
}

<|endoftext|>


<commit_before>
use std::fmt;
use std::path;
use std::collections::BTreeMap;
use std::convert::From;
use std::io::Read;

use sdl2;
use rusttype;
use image;
use gfx;
use gfx::traits::Device;
use gfx::traits::FactoryExt;
use gfx_device_gl;
use gfx_window_sdl;
use gfx::format::Rgba8;
use gfx::Factory;

use super::*;

/// A font that defines the shape of characters drawn on the screen.
/// Can be created from a .ttf file or from an image (bitmap fonts).
pub enum Font {
    TTFFont {
        font: rusttype::Font<'static>,
        points: u32,
    },
    BitmapFont {
        // Width, height and data for the original glyph image.
        // This is always going to be RGBA.
        bytes: Vec<u8>,
        width: usize,
        height: usize,
        // Glyph to index mapping
        glyphs: BTreeMap<char, usize>,
        glyph_width: usize,
    },
}

impl Font {
    /// Load a new TTF font from the given file.
    pub fn new
(context: &mut Context, path: P, size: u32) -> GameResult
        where P: AsRef<path::Path> + fmt::Debug
    {
        // let mut buffer: Vec<u8> = Vec::new();
        // let mut rwops = util::rwops_from_path(context, path, &mut buffer)?;
        let mut stream = context.filesystem.open(path.as_ref())?;
        let mut buf = Vec::new();
        stream.read_to_end(&mut buf)?;

        let name = format!("{:?}", path);
        Font::from_bytes(&name, &buf, size)
    }

    /// Loads a new TTF font from data copied out of the given buffer.
    pub fn from_bytes(name: &str, bytes: &[u8], size: u32) -> GameResult
    {
        let collection = rusttype::FontCollection::from_bytes(bytes.to_vec());
        let font_err = GameError::ResourceLoadError(format!("Could not load font collection for \
                                                             font {:?}",
                                                            name));
        let font = collection.into_font().ok_or(font_err)?;

        Ok(Font::TTFFont {
            font: font,
            points: size,
        })
    }

    /// Loads an `Image` and uses it to create a new bitmap font
    /// The `Image` is a 1D list of glyphs, which maybe isn't
    /// super ideal but should be fine.
    /// The `glyphs` string is the characters in the image from left to right.
    pub fn new_bitmap<P: AsRef<path::Path>>(context: &mut Context,
                                            path: P,
                                            glyphs: &str)
                                            -> GameResult {
        let img = {
            let mut buf = Vec::new();
            let mut reader = context.filesystem.open(path)?;
            reader.read_to_end(&mut buf)?;
            image::load_from_memory(&buf)?.to_rgba()
        };
        let (image_width, image_height) = img.dimensions();

        let glyph_width = (image_width as usize) / glyphs.len();
        // println!("Number of glyphs: {}, Glyph width: {}, image width: {}",
        // glyphs.len(), glyph_width, image_width);
        let mut glyphs_map: BTreeMap<char, usize> = BTreeMap::new();
        for (i, c) in glyphs.chars().enumerate() {
            glyphs_map.insert(c, i * glyph_width);
        }
        Ok(Font::BitmapFont {
            bytes: img.into_vec(),
            width: image_width as usize,
            height: image_height as usize,
            glyphs: glyphs_map,
            glyph_width: glyph_width,
        })
    }

    pub fn default_font() -> GameResult<Self> {
        let size = 16;
        let buf = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/resources/DejaVuSerif.ttf"));
        Font::from_bytes("default", &buf[..], size)
    }
}

impl fmt::Debug for Font {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Font::TTFFont { .. } => write!(f, "<TTFFont: {:p}>", &self),
            Font::BitmapFont { .. } => write!(f, "<BitmapFont: {:p}>", &self),
        }
    }
}

/// Drawable text created from a `Font`.
pub struct Text {
    texture: Image,
    contents: String,
}

/// Compute a scale for a font of a given size.
// This basically does the points->pixels unit conversion,
// taking the display DPI into account.
fn display_independent_scale(points: u32, dpi_w: f32, dpi_h: f32) -> rusttype::Scale {
    // Calculate pixels per point
    let points = points as f32;
    let points_per_inch = 72.0;
    let pixels_per_point_w = dpi_w * (1.0 / points_per_inch);
    let pixels_per_point_h = dpi_h * (1.0 / points_per_inch);

    // rusttype::Scale is in units of pixels, so.
    let scale = rusttype::Scale {
        x: pixels_per_point_w * points,
        y: pixels_per_point_h * points,
    };
    scale
}

fn render_ttf(context: &mut Context,
              text: &str,
              font: &rusttype::Font<'static>,
              size: u32)
              -> GameResult<Text> {
    // Ripped almost wholesale from
    // https://github.com/dylanede/rusttype/blob/master/examples/simple.rs

    // Get the proper DPI to scale font size accordingly
    let (_diag_dpi, x_dpi, y_dpi) = context.dpi;
    let scale = display_independent_scale(size, x_dpi, y_dpi);
    let text_height_pixels = scale.y.ceil() as usize;
    let v_metrics = font.v_metrics(scale);
    let offset = rusttype::point(0.0, v_metrics.ascent);
    // Then turn them into an array of positioned glyphs...
    // `layout()` turns an abstract glyph, which contains no concrete
    // size or position information, into a PositionedGlyph, which does.
    let glyphs: Vec<rusttype::PositionedGlyph> = font.layout(text, scale, offset).collect();
    let text_width_pixels = glyphs.iter()
        .rev()
        .filter_map(|g| {
            g.pixel_bounding_box()
                .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width)
        })
        .next()
        .unwrap_or(0.0)
        .ceil() as usize;
    // Make an array for our rendered bitmap
    let bytes_per_pixel = 4;
    let mut pixel_data = vec![0; text_width_pixels * text_height_pixels * bytes_per_pixel];
    let pitch = text_width_pixels * bytes_per_pixel;

    // Now we actually render the glyphs to a bitmap...
    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            // v is the amount of the pixel covered
            // by the glyph, in the range 0.0 to 1.0
            g.draw(|x, y, v| {
                let c = (v * 255.0) as u8;
                let x = x as i32 + bb.min.x;
                let y = y as i32 + bb.min.y;
                // There's still a possibility that the glyph clips the boundaries of the bitmap
                if x >= 0 && x < text_width_pixels as i32 && y >= 0 &&
                   y < text_height_pixels as i32 {
                    let x = x as usize * bytes_per_pixel;
                    let y = y as usize;
                    pixel_data[(x + y * pitch + 0)] = c;
                    pixel_data[(x + y * pitch + 1)] = c;
                    pixel_data[(x + y * pitch + 2)] = c;
                    pixel_data[(x + y * pitch + 3)] = c;
                }
            })
        }
    }

    // Copy the bitmap into an image, and we're basically done!
    // BUGGO: TODO: Make sure conversions will not fail
    // println!("Creating text {}, {}x{}: {:?}", text, text_width_pixels, text_height_pixels, pixel_data);
    let image = Image::from_rgba8(context,
                                       text_width_pixels as u16,
                                       text_height_pixels as u16,
                                       &pixel_data)?;

    let text_string = text.to_string();
    Ok(Text {
        texture: image,
        contents: text_string,
    })

}

/// Treats src and dst as row-major 2D arrays, and blits the given rect from src to dst.
/// Does no bounds checking or anything; if you feed it invalid bounds it will just panic.
/// Generally, you shouldn't need or use this.
fn blit(dst: &mut [u8], dst_dims: (usize,usize), dst_point: (usize,usize), src: &[u8], src_dims: (usize, usize), src_point: (usize, usize), rect_size: (usize,usize), pitch: usize) {
    // The rect properties are all f32's; we truncate them down to integers.
    let area_row_width = rect_size.0 * pitch;
    let src_row_width = src_dims.0 * pitch;
    let dst_row_width = dst_dims.0 * pitch;

    for row_idx in 0..rect_size.1 {
        let src_row = row_idx + src_point.1;
        let dst_row = row_idx + dst_point.1;
        let src_offset = src_row * src_row_width;
        let dst_offset = dst_row * dst_row_width;

        println!("from {} to {}, width {}", dst_offset, src_offset, area_row_width);
        let dst_slice = &mut dst[dst_offset..(dst_offset + area_row_width)];
        let src_slice = &src[src_offset..(src_offset + area_row_width)];
        dst_slice.copy_from_slice(src_slice);
    }
}

fn render_bitmap(context: &mut Context,
                 text: &str,
                 bytes: &[u8],
                 width: usize,
                 height: usize,
                 glyphs_map: &BTreeMap<char, usize>,
                 glyph_width: usize)
                 -> GameResult<Text> {
    unimplemented!();
    let text_length = text.len();
    let glyph_height = height;
    let buf_len = text_length * glyph_width * glyph_height * 4;
    let mut dest_buf = Vec::with_capacity(buf_len);
    dest_buf.resize(buf_len, 0u8);
    for (i, c) in text.chars().enumerate() {
        let error_message = format!("Character '{}' not in bitmap font!", c);
        let source_offset = glyphs_map.get(&c)
            .ok_or(GameError::FontError(String::from(error_message)))?;
        let dest_offset = glyph_width * i;
        //fn blit(dst: &mut [u8], dst_dims: (usize,usize), dst_point: (usize,usize), src: &[u8], src_dims: (usize, usize), src_point: (usize, usize), rect_size: (usize,usize), pitch: usize) {
        blit(&mut dest_buf, (text_length*glyph_width, glyph_height), (0, 0), &bytes, (width, height), (0, 0), (glyph_width, glyph_height), 4);
    }
    let image = Image::from_rgba8(context, (text_length * glyph_width) as u16, glyph_height as u16, &dest_buf)?;
    let text_string = text.to_string();

    Ok(Text {
        texture: image,
        contents: text_string,
    })
}

impl Text {
    /// Renders a new `Text` from the given `Font`
    pub fn new(context: &mut Context, text: &str, font: &Font) -> GameResult<Text> {
        match *font {
            Font::TTFFont { font: ref f, points } => render_ttf(context, text, f, points),
            Font::BitmapFont { ref bytes, width, height, glyph_width, ref glyphs } => {
                render_bitmap(context, text, bytes, width, height, glyphs, glyph_width)
            }
        }
    }

    /// Returns the width of the rendered text, in pixels.
    pub fn width(&self) -> u32 {
        self.texture.width
    }

    /// Returns the height of the rendered text, in pixels.
    pub fn height(&self) -> u32 {
        self.texture.height
    }

    /// Returns the string that the text represents.
    pub fn contents(&self) -> &str {
        &self.contents
    }
}

impl Drawable for Text {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        draw_ex(ctx, &self.texture, param)
    }
}

impl fmt::Debug for Text {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "<Text: {}x{}, {:p}>",
               self.texture.width,
               self.texture.height,
               &self)

    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_blit() {
        let dst = &mut [0; 125][..];
        let src = &[
            1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            9, 9, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ][..];
        assert_eq!(src.len(), 25 * 5);

        // Test just blitting the whole thing
        let rect_dims = (25, 5);
        blit(dst, rect_dims, (0,0), src, rect_dims, (0,0), (25, 5), 1);
        //println!("{:?}", src);
        //println!("{:?}", dst);
        assert_eq!(dst, src);
        for i in 0..dst.len() {
            dst[i] = 0;
        }

        // Test blitting the whole thing with a non-1 pitch
        let rect_dims = (5, 5);
        blit(dst, rect_dims, (0,0), src, rect_dims, (0,0), (5, 5), 5);
        assert_eq!(dst, src);
    }
}
<commit_msg>Removed stray unimplemented!()<commit_after>
use std::fmt;
use std::path;
use std::collections::BTreeMap;
use std::convert::From;
use std::io::Read;

use sdl2;
use rusttype;
use image;
use gfx;
use gfx::traits::Device;
use gfx::traits::FactoryExt;
use gfx_device_gl;
use gfx_window_sdl;
use gfx::format::Rgba8;
use gfx::Factory;

use super::*;

/// A font that defines the shape of characters drawn on the screen.
/// Can be created from a .ttf file or from an image (bitmap fonts).
pub enum Font {
    TTFFont {
        font: rusttype::Font<'static>,
        points: u32,
    },
    BitmapFont {
        // Width, height and data for the original glyph image.
        // This is always going to be RGBA.
        bytes: Vec<u8>,
        width: usize,
        height: usize,
        // Glyph to index mapping
        glyphs: BTreeMap<char, usize>,
        glyph_width: usize,
    },
}

impl Font {
    /// Load a new TTF font from the given file.
    pub fn new
(context: &mut Context, path: P, size: u32) -> GameResult
        where P: AsRef<path::Path> + fmt::Debug
    {
        // let mut buffer: Vec<u8> = Vec::new();
        // let mut rwops = util::rwops_from_path(context, path, &mut buffer)?;
        let mut stream = context.filesystem.open(path.as_ref())?;
        let mut buf = Vec::new();
        stream.read_to_end(&mut buf)?;

        let name = format!("{:?}", path);
        Font::from_bytes(&name, &buf, size)
    }

    /// Loads a new TTF font from data copied out of the given buffer.
    pub fn from_bytes(name: &str, bytes: &[u8], size: u32) -> GameResult
    {
        let collection = rusttype::FontCollection::from_bytes(bytes.to_vec());
        let font_err = GameError::ResourceLoadError(format!("Could not load font collection for \
                                                             font {:?}",
                                                            name));
        let font = collection.into_font().ok_or(font_err)?;

        Ok(Font::TTFFont {
            font: font,
            points: size,
        })
    }

    /// Loads an `Image` and uses it to create a new bitmap font
    /// The `Image` is a 1D list of glyphs, which maybe isn't
    /// super ideal but should be fine.
    /// The `glyphs` string is the characters in the image from left to right.
    pub fn new_bitmap<P: AsRef<path::Path>>(context: &mut Context,
                                            path: P,
                                            glyphs: &str)
                                            -> GameResult {
        let img = {
            let mut buf = Vec::new();
            let mut reader = context.filesystem.open(path)?;
            reader.read_to_end(&mut buf)?;
            image::load_from_memory(&buf)?.to_rgba()
        };
        let (image_width, image_height) = img.dimensions();

        let glyph_width = (image_width as usize) / glyphs.len();
        // println!("Number of glyphs: {}, Glyph width: {}, image width: {}",
        // glyphs.len(), glyph_width, image_width);
        let mut glyphs_map: BTreeMap<char, usize> = BTreeMap::new();
        for (i, c) in glyphs.chars().enumerate() {
            glyphs_map.insert(c, i * glyph_width);
        }
        Ok(Font::BitmapFont {
            bytes: img.into_vec(),
            width: image_width as usize,
            height: image_height as usize,
            glyphs: glyphs_map,
            glyph_width: glyph_width,
        })
    }

    pub fn default_font() -> GameResult<Self> {
        let size = 16;
        let buf = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/resources/DejaVuSerif.ttf"));
        Font::from_bytes("default", &buf[..], size)
    }
}

impl fmt::Debug for Font {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Font::TTFFont { .. } => write!(f, "<TTFFont: {:p}>", &self),
            Font::BitmapFont { .. } => write!(f, "<BitmapFont: {:p}>", &self),
        }
    }
}

/// Drawable text created from a `Font`.
pub struct Text {
    texture: Image,
    contents: String,
}

/// Compute a scale for a font of a given size.
// This basically does the points->pixels unit conversion,
// taking the display DPI into account.
fn display_independent_scale(points: u32, dpi_w: f32, dpi_h: f32) -> rusttype::Scale {
    // Calculate pixels per point
    let points = points as f32;
    let points_per_inch = 72.0;
    let pixels_per_point_w = dpi_w * (1.0 / points_per_inch);
    let pixels_per_point_h = dpi_h * (1.0 / points_per_inch);

    // rusttype::Scale is in units of pixels, so.
    let scale = rusttype::Scale {
        x: pixels_per_point_w * points,
        y: pixels_per_point_h * points,
    };
    scale
}

fn render_ttf(context: &mut Context,
              text: &str,
              font: &rusttype::Font<'static>,
              size: u32)
              -> GameResult<Text> {
    // Ripped almost wholesale from
    // https://github.com/dylanede/rusttype/blob/master/examples/simple.rs

    // Get the proper DPI to scale font size accordingly
    let (_diag_dpi, x_dpi, y_dpi) = context.dpi;
    let scale = display_independent_scale(size, x_dpi, y_dpi);
    let text_height_pixels = scale.y.ceil() as usize;
    let v_metrics = font.v_metrics(scale);
    let offset = rusttype::point(0.0, v_metrics.ascent);
    // Then turn them into an array of positioned glyphs...
    // `layout()` turns an abstract glyph, which contains no concrete
    // size or position information, into a PositionedGlyph, which does.
    let glyphs: Vec<rusttype::PositionedGlyph> = font.layout(text, scale, offset).collect();
    let text_width_pixels = glyphs.iter()
        .rev()
        .filter_map(|g| {
            g.pixel_bounding_box()
                .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width)
        })
        .next()
        .unwrap_or(0.0)
        .ceil() as usize;
    // Make an array for our rendered bitmap
    let bytes_per_pixel = 4;
    let mut pixel_data = vec![0; text_width_pixels * text_height_pixels * bytes_per_pixel];
    let pitch = text_width_pixels * bytes_per_pixel;

    // Now we actually render the glyphs to a bitmap...
    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            // v is the amount of the pixel covered
            // by the glyph, in the range 0.0 to 1.0
            g.draw(|x, y, v| {
                let c = (v * 255.0) as u8;
                let x = x as i32 + bb.min.x;
                let y = y as i32 + bb.min.y;
                // There's still a possibility that the glyph clips the boundaries of the bitmap
                if x >= 0 && x < text_width_pixels as i32 && y >= 0 &&
                   y < text_height_pixels as i32 {
                    let x = x as usize * bytes_per_pixel;
                    let y = y as usize;
                    pixel_data[(x + y * pitch + 0)] = c;
                    pixel_data[(x + y * pitch + 1)] = c;
                    pixel_data[(x + y * pitch + 2)] = c;
                    pixel_data[(x + y * pitch + 3)] = c;
                }
            })
        }
    }

    // Copy the bitmap into an image, and we're basically done!
    // BUGGO: TODO: Make sure conversions will not fail
    // println!("Creating text {}, {}x{}: {:?}", text, text_width_pixels, text_height_pixels, pixel_data);
    let image = Image::from_rgba8(context,
                                       text_width_pixels as u16,
                                       text_height_pixels as u16,
                                       &pixel_data)?;

    let text_string = text.to_string();
    Ok(Text {
        texture: image,
        contents: text_string,
    })

}

/// Treats src and dst as row-major 2D arrays, and blits the given rect from src to dst.
/// Does no bounds checking or anything; if you feed it invalid bounds it will just panic.
/// Generally, you shouldn't need or use this.
fn blit(dst: &mut [u8], dst_dims: (usize,usize), dst_point: (usize,usize), src: &[u8], src_dims: (usize, usize), src_point: (usize, usize), rect_size: (usize,usize), pitch: usize) {
    // The rect properties are all f32's; we truncate them down to integers.
    let area_row_width = rect_size.0 * pitch;
    let src_row_width = src_dims.0 * pitch;
    let dst_row_width = dst_dims.0 * pitch;

    for row_idx in 0..rect_size.1 {
        let src_row = row_idx + src_point.1;
        let dst_row = row_idx + dst_point.1;
        let src_offset = src_row * src_row_width;
        let dst_offset = dst_row * dst_row_width;

        println!("from {} to {}, width {}", dst_offset, src_offset, area_row_width);
        let dst_slice = &mut dst[dst_offset..(dst_offset + area_row_width)];
        let src_slice = &src[src_offset..(src_offset + area_row_width)];
        dst_slice.copy_from_slice(src_slice);
    }
}

fn render_bitmap(context: &mut Context,
                 text: &str,
                 bytes: &[u8],
                 width: usize,
                 height: usize,
                 glyphs_map: &BTreeMap<char, usize>,
                 glyph_width: usize)
                 -> GameResult<Text> {
    let text_length = text.len();
    let glyph_height = height;
    let buf_len = text_length * glyph_width * glyph_height * 4;
    let mut dest_buf = Vec::with_capacity(buf_len);
    dest_buf.resize(buf_len, 0u8);
    for (i, c) in text.chars().enumerate() {
        let error_message = format!("Character '{}' not in bitmap font!", c);
        let source_offset = glyphs_map.get(&c)
            .ok_or(GameError::FontError(String::from(error_message)))?;
        let dest_offset = glyph_width * i;
        //fn blit(dst: &mut [u8], dst_dims: (usize,usize), dst_point: (usize,usize), src: &[u8], src_dims: (usize, usize), src_point: (usize, usize), rect_size: (usize,usize), pitch: usize) {
        blit(&mut dest_buf, (text_length*glyph_width, glyph_height), (0, 0), &bytes, (width, height), (0, 0), (glyph_width, glyph_height), 4);
    }
    let image = Image::from_rgba8(context, (text_length * glyph_width) as u16, glyph_height as u16, &dest_buf)?;
    let text_string = text.to_string();

    Ok(Text {
        texture: image,
        contents: text_string,
    })
}

impl Text {
    /// Renders a new `Text` from the given `Font`
    pub fn new(context: &mut Context, text: &str, font: &Font) -> GameResult<Text> {
        match *font {
            Font::TTFFont { font: ref f, points } => render_ttf(context, text, f, points),
            Font::BitmapFont { ref bytes, width, height, glyph_width, ref glyphs } => {
                render_bitmap(context, text, bytes, width, height, glyphs, glyph_width)
            }
        }
    }

    /// Returns the width of the rendered text, in pixels.
    pub fn width(&self) -> u32 {
        self.texture.width
    }

    /// Returns the height of the rendered text, in pixels.
    pub fn height(&self) -> u32 {
        self.texture.height
    }

    /// Returns the string that the text represents.
    pub fn contents(&self) -> &str {
        &self.contents
    }
}

impl Drawable for Text {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        draw_ex(ctx, &self.texture, param)
    }
}

impl fmt::Debug for Text {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "<Text: {}x{}, {:p}>",
               self.texture.width,
               self.texture.height,
               &self)

    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_blit() {
        let dst = &mut [0; 125][..];
        let src = &[
            1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            9, 9, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
            0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ][..];
        assert_eq!(src.len(), 25 * 5);

        // Test just blitting the whole thing
        let rect_dims = (25, 5);
        blit(dst, rect_dims, (0,0), src, rect_dims, (0,0), (25, 5), 1);
        //println!("{:?}", src);
        //println!("{:?}", dst);
        assert_eq!(dst, src);
        for i in 0..dst.len() {
            dst[i] = 0;
        }

        // Test blitting the whole thing with a non-1 pitch
        let rect_dims = (5, 5);
        blit(dst, rect_dims, (0,0), src, rect_dims, (0,0), (5, 5), 5);
        assert_eq!(dst, src);
    }
}
<|endoftext|>


<commit_before>use super::*;
use sys::*;
use std::marker::PhantomData;
use std::ptr::{null, null_mut};
use std::thread::panicking;

#[derive(Debug)]
pub struct HStmt<'con> {
    /// Statement may not outlive the connection used to allocate it.
    parent: PhantomData<&'con HDbc<'con>>,
    /// Invariant: Connection handle is always valid.
    handle: SQLHSTMT,
}

impl<'con, 'param> Drop for HStmt<'con> {
    fn drop(&mut self) {
        unsafe {
            match SQLFreeHandle(SQL_HANDLE_STMT, self.handle as SQLHANDLE) {
                SQL_SUCCESS => (),
                other => {
                    if !panicking() {
                        panic!("Unexepected return value of SQLFreeHandle: {:?}.", other)
                    }
                }
            }
        }
    }
}

unsafe impl<'env, 'param> Handle for HStmt<'env> {
    const HANDLE_TYPE: HandleType = SQL_HANDLE_STMT;

    fn handle(&self) -> SQLHANDLE {
        self.handle as SQLHANDLE
    }
}

impl<'env, 'param> HStmt<'env> {
    pub fn as_raw(&self) -> SQLHSTMT {
        self.handle
    }

    /// Allocates a new Statement Handle
    pub fn allocate(parent: &HDbc) -> Return<Self> {
        let mut out = null_mut();
        unsafe {
            let result: Return<()> = SQLAllocHandle(SQL_HANDLE_STMT, parent.handle(), &mut out)
                .into();
            result.map(|()| {
                HStmt {
                    parent: PhantomData,
                    handle: out as SQLHSTMT,
                }
            })
        }
    }

    pub fn exec_direct<T>(&mut self, statement_text: &T) -> ReturnOption<()>
    where
        T: SqlStr + ?Sized,
    {
        unsafe {
            SQLExecDirect(
                self.handle,
                statement_text.as_text_ptr(),
                statement_text.text_length_int(),
            ).into()
        }
    }

    pub fn num_result_cols(&self) -> Return<SQLSMALLINT> {
        let mut out: SQLSMALLINT = 0;
        let ret = unsafe { SQLNumResultCols(self.handle, &mut out) };
        let ret: Return<()> = ret.into();
        ret.map(|()| out)
    }

    pub fn fetch(&mut self) -> ReturnOption<()> {
        unsafe { SQLFetch(self.handle).into() }
    }

    pub fn get_data<T>(
        &mut self,
        col_or_param_num: SQLUSMALLINT,
        target: &mut T,
    ) -> ReturnOption<Indicator>
    where
        T: CDataType + ?Sized,
    {
        let mut str_len_or_ind = 0;
        let ret: ReturnOption<()> = unsafe {
            SQLGetData(
                self.handle,
                col_or_param_num,
                T::c_data_type(),
                target.mut_sql_ptr(),
                target.buffer_len(),
                &mut str_len_or_ind,
            ).into()
        };
        ret.map(|()| str_len_or_ind.into())
    }

    pub fn close_cursor(&mut self) -> Return<()> {
        unsafe { SQLCloseCursor(self.handle).into() }
    }

    /// Binds a parameter to a parameter marker in an SQL Statement
    ///
    /// It is the callers responsibility to make sure the bound parameters live long enough.
    pub unsafe fn bind_input_parameter<T>(
        &mut self,
        parameter_number: SQLUSMALLINT,
        parameter_type: DataType,
        value: &T,
        indicator: Option<&SQLLEN>
    ) -> Return<()>
    where
        T: CDataType + ?Sized,
    {
        let indicator: *const SQLLEN = match indicator {
            Some(indicator) => indicator,
            None => null(),
        };
        SQLBindParameter(
            self.handle,
            parameter_number,
            SQL_PARAM_INPUT,
            T::c_data_type(),
            parameter_type.sql_data_type(),
            parameter_type.column_size(),
            parameter_type.decimal_digits(),
            value.sql_ptr() as SQLPOINTER,
            0,
            indicator as *mut SQLLEN,
        ).into()
    }

    pub fn prepare<T>(&mut self, statement_text: &T) -> Return<()>
    where
        T: SqlStr + ?Sized,
    {
        unsafe {
            SQLPrepare(
                self.handle,
                statement_text.as_text_ptr(),
                statement_text.text_length_int(),
            ).into()
        }
    }

    pub fn reset_parameters(&mut self) -> Return<()> {
        unsafe { SQLFreeStmt(self.handle, SQL_RESET_PARAMS).into() }
    }

    pub fn execute(&mut self) -> ReturnOption<()> {
        unsafe { SQLExecute(self.handle).into() }
    }

    /// Release all columen buffers bound by `bind_col`. Except bookmark column.
    pub fn reset_columns(&mut self) -> Return<()> {
        unsafe { SQLFreeStmt(self.handle, SQL_UNBIND).into() }
    }

    /// Binds application data buffers to columns in the result set
    ///
    /// It is the callers responsibility to make sure the bound columns live long enough.
    pub unsafe fn bind_col<T>(
        &mut self,
        column_number: SQLUSMALLINT,
        value: &mut T,
        indicator: Option<&mut SQLLEN>,
    ) -> Return<()>
    where
        T: CDataType + ?Sized,
    {
        let indicator: *mut SQLLEN = match indicator {
            Some(indicator) => indicator,
            None => null_mut(),
        };
        SQLBindCol(
            self.handle,
            column_number,
            T::c_data_type(),
            value.mut_sql_ptr(),
            value.buffer_len(),
            indicator,
        ).into()
    }

    pub fn describe_col<T>(
        &mut self,
        column_number: SQLUSMALLINT,
        column_name: &mut T,
        column_name_indicator: &mut SQLSMALLINT,
        data_type: &mut SqlDataType,
        column_size: &mut SQLULEN,
        decimal_digits: &mut SQLSMALLINT,
        nullable: &mut Nullable,
    ) -> Return<()>
    where
        T: OutputBuffer + ?Sized,
    {
        unsafe {
            SQLDescribeCol(
                self.handle,
                column_number,
                column_name.mut_buf_ptr(),
                column_name.buf_len(),
                column_name_indicator,
                data_type,
                column_size,
                decimal_digits,
                nullable,
            ).into()
        }
    }
}
<commit_msg>Make sure that user-supplied indicators never overflow the supplied values buffer length.<commit_after>use super::*;
use sys::*;
use std::marker::PhantomData;
use std::ptr::{null, null_mut};
use std::thread::panicking;

#[derive(Debug)]
pub struct HStmt<'con> {
    /// Statement may not outlive the connection used to allocate it.
    parent: PhantomData<&'con HDbc<'con>>,
    /// Invariant: Connection handle is always valid.
    handle: SQLHSTMT,
}

impl<'con, 'param> Drop for HStmt<'con> {
    fn drop(&mut self) {
        unsafe {
            match SQLFreeHandle(SQL_HANDLE_STMT, self.handle as SQLHANDLE) {
                SQL_SUCCESS => (),
                other => {
                    if !panicking() {
                        panic!("Unexepected return value of SQLFreeHandle: {:?}.", other)
                    }
                }
            }
        }
    }
}

unsafe impl<'env, 'param> Handle for HStmt<'env> {
    const HANDLE_TYPE: HandleType = SQL_HANDLE_STMT;

    fn handle(&self) -> SQLHANDLE {
        self.handle as SQLHANDLE
    }
}

impl<'env, 'param> HStmt<'env> {
    pub fn as_raw(&self) -> SQLHSTMT {
        self.handle
    }

    /// Allocates a new Statement Handle
    pub fn allocate(parent: &HDbc) -> Return<Self> {
        let mut out = null_mut();
        unsafe {
            let result: Return<()> = SQLAllocHandle(SQL_HANDLE_STMT, parent.handle(), &mut out)
                .into();
            result.map(|()| {
                HStmt {
                    parent: PhantomData,
                    handle: out as SQLHSTMT,
                }
            })
        }
    }

    pub fn exec_direct<T>(&mut self, statement_text: &T) -> ReturnOption<()>
    where
        T: SqlStr + ?Sized,
    {
        unsafe {
            SQLExecDirect(
                self.handle,
                statement_text.as_text_ptr(),
                statement_text.text_length_int(),
            ).into()
        }
    }

    pub fn num_result_cols(&self) -> Return<SQLSMALLINT> {
        let mut out: SQLSMALLINT = 0;
        let ret = unsafe { SQLNumResultCols(self.handle, &mut out) };
        let ret: Return<()> = ret.into();
        ret.map(|()| out)
    }

    pub fn fetch(&mut self) -> ReturnOption<()> {
        unsafe { SQLFetch(self.handle).into() }
    }

    pub fn get_data<T>(
        &mut self,
        col_or_param_num: SQLUSMALLINT,
        target: &mut T,
    ) -> ReturnOption<Indicator>
    where
        T: CDataType + ?Sized,
    {
        let mut str_len_or_ind = 0;
        let ret: ReturnOption<()> = unsafe {
            SQLGetData(
                self.handle,
                col_or_param_num,
                T::c_data_type(),
                target.mut_sql_ptr(),
                target.buffer_len(),
                &mut str_len_or_ind,
            ).into()
        };
        ret.map(|()| str_len_or_ind.into())
    }

    pub fn close_cursor(&mut self) -> Return<()> {
        unsafe { SQLCloseCursor(self.handle).into() }
    }

    /// Binds a parameter to a parameter marker in an SQL Statement
    ///
    /// It is the callers responsibility to make sure the bound parameters live long enough.
    pub unsafe fn bind_input_parameter<T>(
        &mut self,
        parameter_number: SQLUSMALLINT,
        parameter_type: DataType,
        value: &T,
        indicator: Option<&SQLLEN>
    ) -> Return<()>
    where
        T: CDataType + ?Sized,
    {
        let indicator: *const SQLLEN = match indicator {
            Some(indicator) => {
                assert!(*indicator <= value.buffer_len(), "Indicator cannot be larger than buffer length.");
                indicator
            }
            None => null(),
        };
        SQLBindParameter(
            self.handle,
            parameter_number,
            SQL_PARAM_INPUT,
            T::c_data_type(),
            parameter_type.sql_data_type(),
            parameter_type.column_size(),
            parameter_type.decimal_digits(),
            value.sql_ptr() as SQLPOINTER,
            0,
            indicator as *mut SQLLEN,
        ).into()
    }

    pub fn prepare<T>(&mut self, statement_text: &T) -> Return<()>
    where
        T: SqlStr + ?Sized,
    {
        unsafe {
            SQLPrepare(
                self.handle,
                statement_text.as_text_ptr(),
                statement_text.text_length_int(),
            ).into()
        }
    }

    pub fn reset_parameters(&mut self) -> Return<()> {
        unsafe { SQLFreeStmt(self.handle, SQL_RESET_PARAMS).into() }
    }

    pub fn execute(&mut self) -> ReturnOption<()> {
        unsafe { SQLExecute(self.handle).into() }
    }

    /// Release all columen buffers bound by `bind_col`. Except bookmark column.
    pub fn reset_columns(&mut self) -> Return<()> {
        unsafe { SQLFreeStmt(self.handle, SQL_UNBIND).into() }
    }

    /// Binds application data buffers to columns in the result set
    ///
    /// It is the callers responsibility to make sure the bound columns live long enough.
    pub unsafe fn bind_col<T>(
        &mut self,
        column_number: SQLUSMALLINT,
        value: &mut T,
        indicator: Option<&mut SQLLEN>,
    ) -> Return<()>
    where
        T: CDataType + ?Sized,
    {
        let indicator: *mut SQLLEN = match indicator {
            Some(indicator) => indicator,
            None => null_mut(),
        };
        SQLBindCol(
            self.handle,
            column_number,
            T::c_data_type(),
            value.mut_sql_ptr(),
            value.buffer_len(),
            indicator,
        ).into()
    }

    pub fn describe_col<T>(
        &mut self,
        column_number: SQLUSMALLINT,
        column_name: &mut T,
        column_name_indicator: &mut SQLSMALLINT,
        data_type: &mut SqlDataType,
        column_size: &mut SQLULEN,
        decimal_digits: &mut SQLSMALLINT,
        nullable: &mut Nullable,
    ) -> Return<()>
    where
        T: OutputBuffer + ?Sized,
    {
        unsafe {
            SQLDescribeCol(
                self.handle,
                column_number,
                column_name.mut_buf_ptr(),
                column_name.buf_len(),
                column_name_indicator,
                data_type,
                column_size,
                decimal_digits,
                nullable,
            ).into()
        }
    }
}
<|endoftext|>