<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use context;
use syscall::error::*;
use syscall::scheme::Scheme;
use scheme::{self, SchemeNamespace, SchemeId};
use scheme::user::{UserInner, UserScheme};

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Arc<UserInner>>>,
    ls_handles: RwLock<BTreeMap<usize, AtomicUsize>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
            ls_handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        use syscall::flag::*;

        if uid == 0 {
            if flags & O_DIRECTORY == O_DIRECTORY {
                if flags & O_ACCMODE != O_RDONLY {
                    return Err(Error::new(EACCES));
                }
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.ls_handles.write().insert(id, AtomicUsize::new(0));
                return Ok(id);
            }

            let context = {
                let contexts = context::contexts();
                let context = contexts.current().ok_or(Error::new(ESRCH))?;
                Arc::downgrade(&context)
            };

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);

            let inner = {
                use scheme;
                let path_box = path.to_vec().into_boxed_slice();
                let mut schemes = scheme::schemes_mut();
                let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                        inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                        Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                    })?;
                inner
            };

            self.handles.write().insert(id, inner);

            Ok(id)
        } else {
            Err(Error::new(EACCES))
        }
    }

    fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let inner = {
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        handles.insert(id, inner);

        Ok(id)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            handles.get(&file).map(Clone::clone)
        };

        if let Some(inner) = inner {
            inner.read(buf)
        } else {
            let scheme_ns = {
                let contexts = context::contexts();
                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                let context = context_lock.read();
                context.ens
            };

            let schemes = scheme::schemes();
            let mut schemes_iter = schemes.iter_name(scheme_ns);

            let num = {
                let handles = self.ls_handles.read();
                let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                inner.load(Ordering::SeqCst)
            };

            if let Some(scheme) = schemes_iter.nth(num) {
                let mut i = 0;
                while i < buf.len() && i < scheme.0.len() {
                    buf[i] = scheme.0[i];
                    i += 1;
                }

                {
                    let handles = self.ls_handles.read();
                    let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                    inner.fetch_add(1, Ordering::SeqCst)
                };

                Ok(i)
            } else {
                Ok(0)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.write(buf)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fevent(flags)
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < inner.name.len() {
            buf[i] = inner.name[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fsync()
    }

    fn close(&self, file: usize) -> Result<usize> {
        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<commit_msg>Remove unnecessary change<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use context;
use syscall::error::*;
use syscall::scheme::Scheme;
use scheme::{self, SchemeNamespace, SchemeId};
use scheme::user::{UserInner, UserScheme};

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Arc<UserInner>>>,
    ls_handles: RwLock<BTreeMap<usize, AtomicUsize>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
            ls_handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        use syscall::flag::*;

        if uid == 0 {
            if flags & O_DIRECTORY == O_DIRECTORY {
                if flags & O_ACCMODE != O_RDONLY {
                    return Err(Error::new(EACCES));
                }
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.ls_handles.write().insert(id, AtomicUsize::new(0));
                return Ok(id);
            }

            let context = {
                let contexts = context::contexts();
                let context = contexts.current().ok_or(Error::new(ESRCH))?;
                Arc::downgrade(&context)
            };

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);

            let inner = {
                use scheme;
                let path_box = path.to_vec().into_boxed_slice();
                let mut schemes = scheme::schemes_mut();
                let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                    inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                    Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                })?;
                inner
            };

            self.handles.write().insert(id, inner);

            Ok(id)
        } else {
            Err(Error::new(EACCES))
        }
    }

    fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let inner = {
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        handles.insert(id, inner);

        Ok(id)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            handles.get(&file).map(Clone::clone)
        };

        if let Some(inner) = inner {
            inner.read(buf)
        } else {
            let scheme_ns = {
                let contexts = context::contexts();
                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                let context = context_lock.read();
                context.ens
            };

            let schemes = scheme::schemes();
            let mut schemes_iter = schemes.iter_name(scheme_ns);

            let num = {
                let handles = self.ls_handles.read();
                let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                inner.load(Ordering::SeqCst)
            };

            if let Some(scheme) = schemes_iter.nth(num) {
                let mut i = 0;
                while i < buf.len() && i < scheme.0.len() {
                    buf[i] = scheme.0[i];
                    i += 1;
                }

                {
                    let handles = self.ls_handles.read();
                    let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                    inner.fetch_add(1, Ordering::SeqCst)
                };

                Ok(i)
            } else {
                Ok(0)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.write(buf)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fevent(flags)
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < inner.name.len() {
            buf[i] = inner.name[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fsync()
    }

    fn close(&self, file: usize) -> Result<usize> {
        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<|endoftext|>


<commit_before>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]

#![allow(unused_imports)]

extern crate typenum;
extern crate momms;

use std::time::{Instant};
use typenum::{Unsigned,U1};

use momms::kern::KernelNM;
use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix, Hierarch};
use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB, UnpackC, SpawnThreads, ParallelM, ParallelN, TheRest};
use momms::thread_comm::ThreadInfo;
use momms::util;

fn test_blas_dgemm ( m:usize, n: usize, k: usize, flusher: &mut Vec<f64>, n_reps: usize ) -> (f64, f64)
{
    let mut best_time: f64 = 9999999999.0;
    let mut worst_err: f64 = 0.0;

    for _ in 0..n_reps {
        //Create matrices.
        let mut a : Matrix<f64> = Matrix::new(m, k);
        let mut b : Matrix<f64> = Matrix::new(k, n);
        let mut c : Matrix<f64> = Matrix::new(m, n);

        //Fill the matrices
        a.fill_rand(); c.fill_zero(); b.fill_rand();

        //Read a buffer so that A, B, and C are cold in cache.
        for i in flusher.iter_mut() { *i += 1.0; }

        //Time and run algorithm
        let start = Instant::now();
        util::blas_dgemm( &mut a, &mut b, &mut c);
        best_time = best_time.min(util::dur_seconds(start));
        let err = util::test_c_eq_a_b( &mut a, &mut b, &mut c);
        worst_err = worst_err.max(err);
    }
    (best_time, worst_err)
}

fn test_algorithm_flat<T: Scalar, S: GemmNode<T, Matrix<T>, Matrix<T>, Matrix<T>>>
    ( m:usize, n: usize, k: usize, algo: &mut S, flusher: &mut Vec<f64>, n_reps: usize ) -> (f64, T)
{
    let mut best_time: f64 = 9999999999.0;
    let mut worst_err: T = T::zero();

    for _ in 0..n_reps {
        //Create matrices.
        let mut a = <Matrix<T>>::new(m, k);
        let mut b = <Matrix<T>>::new(k, n);

        //The micro-kernel used is more efficient with row-major C.
        let mut c = <Matrix<T>>::new(n, m);
        c.transpose();

        //Fill the matrices
        a.fill_rand(); c.fill_zero(); b.fill_rand();

        //Read a buffer so that A, B, and C are cold in cache.
        for i in flusher.iter_mut() { *i += 1.0; }

        //Time and run algorithm
        let start = Instant::now();
        unsafe{ algo.run( &mut a, &mut b, &mut c, &ThreadInfo::single_thread() ); }
        best_time = best_time.min(util::dur_seconds(start));
        let err = util::test_c_eq_a_b( &mut a, &mut b, &mut c);
        worst_err = worst_err.max(err);
    }
    (best_time, worst_err)
}

fn test() {
    use typenum::{UInt, B0};
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;
    type HA<T> = Hierarch<T, Mr, Kc, U1, Mr>;
    type HB<T> = Hierarch<T, Kc, Nr, Nr, U1>;
    type HC<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    type Goto<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T,Nr>,
          PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
          PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
          ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
          KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>>;

    type U3600 = UInt<UInt<typenum::U900, B0>, B0>;
    type NcL4 = U3600;
    type McL4 = U3600;
    type L4C<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartM<T, MTA, MTB, MTC, McL4,
          PartN<T, MTA, MTB, MTC, NcL4,
          UnpackC<T, MTA, MTB, MTC, HC<T>,
          PartK<T, MTA, MTB, HC<T>, Kc,
          PackB<T, MTA, MTB, HC<T>, HB<T>,
          PartM<T, MTA, HB<T>, HC<T>, Mc,
          PackA<T, MTA, HB<T>, HC<T>, HA<T>,
          ParallelN<T, HA<T>, HB<T>, HC<T>, Nr, TheRest,
          KernelNM<T, HA<T>, HB<T>, HC<T>, Nr, Mr>>>>>>>>>>;

    let mut goto = <Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    let mut l4c = <L4C<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    goto.set_n_threads(4);
    l4c.set_n_threads(4);

    let flusher_len = 32*1024*1024; //256MB
    let mut flusher : Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    println!("m\tn\tk\t{: <13}{: <13}{: <15}{: <15}", "goto", "l4c", "goto", "l4c");
    for index in 01..41 {
        let size = index*500;
        let (m, n, k) = (size, size, size);

        let n_reps = 5;
        let (goto_time, goto_err) = test_algorithm_flat(m, n, k, &mut goto, &mut flusher, n_reps);
        let (l4c_time, l4c_err) = test_algorithm_flat(m, n, k, &mut l4c, &mut flusher, n_reps);

        println!("{}\t{}\t{}\t{}{}{}{}",
                 m, n, k,
                 format!("{: <13.5}", util::gflops(m,n,k,goto_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l4c_time)),
                 format!("{: <15.5e}", goto_err.sqrt()),
                 format!("{: <15.5e}", l4c_err.sqrt()));
    }

    let mut sum = 0.0;
    for a in flusher.iter() {
        sum += *a;
    }
    println!("Flush value {}", sum);
}

fn main() {
    test( );
}
<commit_msg>Remove test_blas_gemm from l4_packing<commit_after>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]

#![allow(unused_imports)]

extern crate typenum;
extern crate momms;

use std::time::{Instant};
use typenum::{Unsigned,U1};

use momms::kern::KernelNM;
use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix, Hierarch};
use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB, UnpackC, SpawnThreads, ParallelM, ParallelN, TheRest};
use momms::thread_comm::ThreadInfo;
use momms::util;

fn test_algorithm_flat<T: Scalar, S: GemmNode<T, Matrix<T>, Matrix<T>, Matrix<T>>>
    ( m:usize, n: usize, k: usize, algo: &mut S, flusher: &mut Vec<f64>, n_reps: usize ) -> (f64, T)
{
    let mut best_time: f64 = 9999999999.0;
    let mut worst_err: T = T::zero();

    for _ in 0..n_reps {
        //Create matrices.
        let mut a = <Matrix<T>>::new(m, k);
        let mut b = <Matrix<T>>::new(k, n);

        //The micro-kernel used is more efficient with row-major C.
        let mut c = <Matrix<T>>::new(n, m);
        c.transpose();

        //Fill the matrices
        a.fill_rand(); c.fill_zero(); b.fill_rand();

        //Read a buffer so that A, B, and C are cold in cache.
        for i in flusher.iter_mut() { *i += 1.0; }

        //Time and run algorithm
        let start = Instant::now();
        unsafe{ algo.run( &mut a, &mut b, &mut c, &ThreadInfo::single_thread() ); }
        best_time = best_time.min(util::dur_seconds(start));
        let err = util::test_c_eq_a_b( &mut a, &mut b, &mut c);
        worst_err = worst_err.max(err);
    }
    (best_time, worst_err)
}

fn test() {
    use typenum::{UInt, B0};
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;
    type HA<T> = Hierarch<T, Mr, Kc, U1, Mr>;
    type HB<T> = Hierarch<T, Kc, Nr, Nr, U1>;
    type HC<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    type Goto<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T,Nr>,
          PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
          PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
          ParallelN<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, TheRest,
          KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>>>;

    type U3600 = UInt<UInt<typenum::U900, B0>, B0>;
    type NcL4 = U3600;
    type McL4 = U3600;
    type L4C<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartM<T, MTA, MTB, MTC, McL4,
          PartN<T, MTA, MTB, MTC, NcL4,
          UnpackC<T, MTA, MTB, MTC, HC<T>,
          PartK<T, MTA, MTB, HC<T>, Kc,
          PackB<T, MTA, MTB, HC<T>, HB<T>,
          PartM<T, MTA, HB<T>, HC<T>, Mc,
          PackA<T, MTA, HB<T>, HC<T>, HA<T>,
          ParallelN<T, HA<T>, HB<T>, HC<T>, Nr, TheRest,
          KernelNM<T, HA<T>, HB<T>, HC<T>, Nr, Mr>>>>>>>>>>;

    let mut goto = <Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    let mut l4c = <L4C<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    goto.set_n_threads(4);
    l4c.set_n_threads(4);

    let flusher_len = 32*1024*1024; //256MB
    let mut flusher : Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    println!("m\tn\tk\t{: <13}{: <13}{: <15}{: <15}", "goto", "l4c", "goto", "l4c");
    for index in 01..41 {
        let size = index*500;
        let (m, n, k) = (size, size, size);

        let n_reps = 5;
        let (goto_time, goto_err) = test_algorithm_flat(m, n, k, &mut goto, &mut flusher, n_reps);
        let (l4c_time, l4c_err) = test_algorithm_flat(m, n, k, &mut l4c, &mut flusher, n_reps);

        println!("{}\t{}\t{}\t{}{}{}{}",
                 m, n, k,
                 format!("{: <13.5}", util::gflops(m,n,k,goto_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l4c_time)),
                 format!("{: <15.5e}", goto_err.sqrt()),
                 format!("{: <15.5e}", l4c_err.sqrt()));
    }

    let mut sum = 0.0;
    for a in flusher.iter() {
        sum += *a;
    }
    println!("Flush value {}", sum);
}

fn main() {
    test( );
}
<|endoftext|>


<commit_before>use core::clone::Clone;
use core::mem::size_of;
use core::option::Option;

use common::memory::*;
use common::safeptr::*;
use common::string::*;
use common::vector::*;

use drivers::disk::*;

#[derive(Copy, Clone)]
pub struct Block {
    address: u64
}

#[derive(Copy, Clone)]
struct Extent{
    block: Block,
    length: u64
}

pub struct Header {
    pub signature: [u8; 4],
    pub version: u32,
    pub root_sector_list: Block,
    pub free_sector_list: Block,
    pub name: [u8; 256],
    reserved: [u8; 232]
}

struct Node {
    parent_collection: Block,
    data_sector_list: Block,
    data_size: u64,
    user_id: u64,
    group_id: u64,
    mode: u64,
    create_time: u64,
    modify_time: u64,
    access_time: u64,
    name: [u8; 256],
    reserved: [u8; 184]
}

struct SectorList {
    parent_node: Block,
    fragment_number: u64,
    last_fragment: Block,
    next_fragment: Block,
    extents: [Extent; 30]
}

pub struct UnFS {
    disk: Disk,
    pub header: &'static Header
}

impl UnFS {
    pub fn new() -> UnFS{
        unsafe{
            return UnFS::from_disk(Disk::new());
        }
    }

    pub unsafe fn from_disk(disk: Disk) -> UnFS{
        // TODO: Do not use header loaded in memory
        UnFS { disk:disk, header: &*(0x7E00 as *const Header) }
    }

    pub unsafe fn node(&self, filename: String) -> *const Node{
        let mut ret: *const Node = 0 as *const Node;
        let mut node_matches = false;

        let root_sector_list = alloc(size_of::<SectorList>()) as *const SectorList;
        let mut root_sector_list_address = self.header.root_sector_list.address;
        while root_sector_list_address > 0 {
            self.disk.read(root_sector_list_address, 1, root_sector_list as usize);

            for extent_i in 0..30 {
                let extent = (*root_sector_list).extents[extent_i];
                if extent.block.address > 0 {
                    for node_address in extent.block.address..extent.block.address + extent.length {
                        let node = alloc(size_of::<Node>()) as *const Node;
                        self.disk.read(node_address, 1, node as usize);

                        node_matches = true;
                        let mut i = 0;
                        for c in filename.chars()  {
                            if !(i < 256 && (*node).name[i] == c as u8) {
                                node_matches = false;
                                break;
                            }
                            i += 1;
                        }
                        if !(i < 256 && (*node).name[i] == 0) {
                            node_matches = false;
                        }

                        unalloc(node as usize);

                        if node_matches {
                            ret = node;
                            break;
                        }
                    }
                }

                if node_matches {
                    break;
                }
            }

            root_sector_list_address = (*root_sector_list).next_fragment.address;

            if node_matches{
                break;
            }
        }

        unalloc(root_sector_list as usize);

        ret
    }

    pub fn list(&self, directory: String) -> Vector<String> {
        let mut ret = Vector::<String>::new();

        unsafe{
            let root_sector_list = alloc(size_of::<SectorList>()) as *const SectorList;
            let mut root_sector_list_address = self.header.root_sector_list.address;
            while root_sector_list_address > 0 {
                self.disk.read(root_sector_list_address, 1, root_sector_list as usize);

                for extent_i in 0..30 {
                    let extent = (*root_sector_list).extents[extent_i];
                    if extent.block.address > 0 {
                        for node_address in extent.block.address..extent.block.address + extent.length {
                            let node = alloc(size_of::<Node>()) as *const Node;
                            self.disk.read(node_address, 1, node as usize);

                            let node_name = String::from_c_slice(&(*node).name);
                            if node_name.starts_with(directory.clone()) {
                                ret = ret + node_name;
                            }

                            unalloc(node as usize);
                        }
                    }
                }

                root_sector_list_address = (*root_sector_list).next_fragment.address;
            }

            unalloc(root_sector_list as usize);
        }

        ret
    }

    pub unsafe fn load(&self, filename: String) -> usize{
        let mut destination = 0;

        let node = self.node(filename);

        if node as usize > 0{
            if (*node).data_sector_list.address > 0 {
                let sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
                match sector_list_ptr.get() {
                    Option::Some(sector_list) => {
                        self.disk.read((*node).data_sector_list.address, 1, sector_list_ptr.unsafe_ptr() as usize);

                        //TODO: More than one extent, extent sector count > 64K
                        let mut size = 0;
                        for i in 0..1 {
                            if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                size += (*sector_list).extents[i].length * 512;
                            }
                        }

                        destination = alloc(size as usize);
                        if destination > 0 {
                            for i in 0..1 {
                                if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                    self.disk.read(sector_list.extents[i].block.address, sector_list.extents[i].length as u16, destination);
                                }
                            }
                        }
                    },
                    Option::None => ()
                }
            }

            unalloc(node as usize);
        }

        return destination;
    }

    // TODO: Support realloc of LBAs
    pub unsafe fn save(&self, filename: String, source: usize){
        let node = self.node(filename);

        if node as usize > 0{
            if (*node).data_sector_list.address > 0 {
                let sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
                match sector_list_ptr.get() {
                    Option::Some(sector_list) => {
                        self.disk.read((*node).data_sector_list.address, 1, sector_list_ptr.unsafe_ptr() as usize);

                        if source > 0 {
                            for i in 0..1 {
                                if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                    self.disk.write(sector_list.extents[i].block.address, sector_list.extents[i].length as u16, source);
                                }
                            }
                        }
                    },
                    Option::None => ()
                }
            }

            unalloc(node as usize);
        }
    }
}
<commit_msg>Finally! Fixed the bug in unfs.rs The bug was a use after free Stuff that my new safeptr class would have protected me against, had I used it there<commit_after>use core::clone::Clone;
use core::mem::size_of;
use core::option::Option;

use common::memory::*;
use common::safeptr::*;
use common::string::*;
use common::vector::*;

use drivers::disk::*;

#[derive(Copy, Clone)]
pub struct Block {
    address: u64
}

#[derive(Copy, Clone)]
struct Extent{
    block: Block,
    length: u64
}

pub struct Header {
    pub signature: [u8; 4],
    pub version: u32,
    pub root_sector_list: Block,
    pub free_sector_list: Block,
    pub name: [u8; 256],
    reserved: [u8; 232]
}

struct Node {
    parent_collection: Block,
    data_sector_list: Block,
    data_size: u64,
    user_id: u64,
    group_id: u64,
    mode: u64,
    create_time: u64,
    modify_time: u64,
    access_time: u64,
    name: [u8; 256],
    reserved: [u8; 184]
}

struct SectorList {
    parent_node: Block,
    fragment_number: u64,
    last_fragment: Block,
    next_fragment: Block,
    extents: [Extent; 30]
}

pub struct UnFS {
    disk: Disk,
    pub header: &'static Header
}

impl UnFS {
    pub fn new() -> UnFS{
        unsafe{
            return UnFS::from_disk(Disk::new());
        }
    }

    pub unsafe fn from_disk(disk: Disk) -> UnFS{
        // TODO: Do not use header loaded in memory
        UnFS { disk:disk, header: &*(0x7E00 as *const Header) }
    }

    pub unsafe fn node(&self, filename: String) -> *const Node{
        let mut ret: *const Node = 0 as *const Node;
        let mut node_matches = false;

        let root_sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
        match root_sector_list_ptr.get() {
            Option::Some(root_sector_list) => {
                let mut root_sector_list_address = self.header.root_sector_list.address;
                while root_sector_list_address > 0 {
                    self.disk.read(root_sector_list_address, 1, root_sector_list_ptr.unsafe_ptr() as usize);

                    for extent_i in 0..30 {
                        let extent = (*root_sector_list).extents[extent_i];
                        if extent.block.address > 0 {
                            for node_address in extent.block.address..extent.block.address + extent.length {
                                let node = alloc(size_of::<Node>()) as *const Node;
                                self.disk.read(node_address, 1, node as usize);

                                node_matches = true;
                                let mut i = 0;
                                for c in filename.chars()  {
                                    if !(i < 256 && (*node).name[i] == c as u8) {
                                        node_matches = false;
                                        break;
                                    }
                                    i += 1;
                                }
                                if !(i < 256 && (*node).name[i] == 0) {
                                    node_matches = false;
                                }

                                if node_matches {
                                    ret = node;
                                    break;
                                }else{
                                    unalloc(node as usize);
                                }
                            }
                        }

                        if node_matches {
                            break;
                        }
                    }

                    root_sector_list_address = (*root_sector_list).next_fragment.address;

                    if node_matches{
                        break;
                    }
                }
            },
            Option::None => ()
        }
        ret
    }

    pub fn list(&self, directory: String) -> Vector<String> {
        let mut ret = Vector::<String>::new();

        unsafe{
            let root_sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
            match root_sector_list_ptr.get() {
                Option::Some(root_sector_list) => {
                    let mut root_sector_list_address = self.header.root_sector_list.address;
                    while root_sector_list_address > 0 {
                        self.disk.read(root_sector_list_address, 1, root_sector_list_ptr.unsafe_ptr() as usize);

                        for extent_i in 0..30 {
                            let extent = (*root_sector_list).extents[extent_i];
                            if extent.block.address > 0 {
                                for node_address in extent.block.address..extent.block.address + extent.length {
                                    let node = alloc(size_of::<Node>()) as *const Node;
                                    self.disk.read(node_address, 1, node as usize);

                                    let node_name = String::from_c_slice(&(*node).name);
                                    if node_name.starts_with(directory.clone()) {
                                        ret = ret + node_name;
                                    }

                                    unalloc(node as usize);
                                }
                            }
                        }

                        root_sector_list_address = (*root_sector_list).next_fragment.address;
                    }
                },
                Option::None => ()
            }
        }

        ret
    }

    pub unsafe fn load(&self, filename: String) -> usize{
        let mut destination = 0;

        let node = self.node(filename);

        if node as usize > 0{
            if (*node).data_sector_list.address > 0 {
                let sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
                match sector_list_ptr.get() {
                    Option::Some(sector_list) => {
                        self.disk.read((*node).data_sector_list.address, 1, sector_list_ptr.unsafe_ptr() as usize);

                        //TODO: More than one extent, extent sector count > 64K
                        let mut size = 0;
                        for i in 0..1 {
                            if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                size += (*sector_list).extents[i].length * 512;
                            }
                        }

                        destination = alloc(size as usize);
                        if destination > 0 {
                            for i in 0..1 {
                                if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                    self.disk.read(sector_list.extents[i].block.address, sector_list.extents[i].length as u16, destination);
                                }
                            }
                        }
                    },
                    Option::None => ()
                }
            }

            unalloc(node as usize);
        }

        return destination;
    }

    // TODO: Support realloc of LBAs
    pub unsafe fn save(&self, filename: String, source: usize){
        let node = self.node(filename);

        if node as usize > 0{
            if (*node).data_sector_list.address > 0 {
                let sector_list_ptr: SafePtr<SectorList> = SafePtr::new();
                match sector_list_ptr.get() {
                    Option::Some(sector_list) => {
                        self.disk.read((*node).data_sector_list.address, 1, sector_list_ptr.unsafe_ptr() as usize);

                        if source > 0 {
                            for i in 0..1 {
                                if sector_list.extents[i].block.address > 0 && sector_list.extents[i].length > 0{
                                    self.disk.write(sector_list.extents[i].block.address, sector_list.extents[i].length as u16, source);
                                }
                            }
                        }
                    },
                    Option::None => ()
                }
            }

            unalloc(node as usize);
        }
    }
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
    ///
    /// ### Why is this bad?
    /// `TryFrom` should be used if there's a possibility of failure.
    ///
    /// ### Example
    /// ```rust
    /// struct Foo(i32);
    ///
    /// // Bad
    /// impl From<String> for Foo {
    ///     fn from(s: String) -> Self {
    ///         Foo(s.parse().unwrap())
    ///     }
    /// }
    /// ```
    ///
    /// ```rust
    /// // Good
    /// struct Foo(i32);
    ///
    /// use std::convert::TryFrom;
    /// impl TryFrom<String> for Foo {
    ///     type Error = ();
    ///     fn try_from(s: String) -> Result<Self, Self::Error> {
    ///         if let Ok(parsed) = s.parse() {
    ///             Ok(Foo(parsed))
    ///         } else {
    ///             Err(())
    ///         }
    ///     }
    /// }
    /// ```
    pub FALLIBLE_IMPL_FROM,
    nursery,
    "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
}

declare_lint_pass!(FallibleImplFrom => [FALLIBLE_IMPL_FROM]);

impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
        // check for `impl From<???> for ..`
        if_chain! {
            if let hir::ItemKind::Impl(impl_) = &item.kind;
            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
            if cx.tcx.is_diagnostic_item(sym::from_trait, impl_trait_ref.def_id);
            then {
                lint_impl_body(cx, item.span, impl_.items);
            }
        }
    }
}

fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef<'_>]) {
    use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
    use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath};

    struct FindPanicUnwrap<'a, 'tcx> {
        lcx: &'a LateContext<'tcx>,
        typeck_results: &'tcx ty::TypeckResults<'tcx>,
        result: Vec<Span>,
    }

    impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
        type Map = Map<'tcx>;

        fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
            // check for `begin_panic`
            if_chain! {
                if let ExprKind::Call(func_expr, _) = expr.kind;
                if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
                if let Some(path_def_id) = path.res.opt_def_id();
                if match_panic_def_id(self.lcx, path_def_id);
                if is_expn_of(expr.span, "unreachable").is_none();
                then {
                    self.result.push(expr.span);
                }
            }

            // check for `unwrap`
            if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
                let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
                if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type)
                    || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type)
                {
                    self.result.push(expr.span);
                }
            }

            // and check sub-expressions
            intravisit::walk_expr(self, expr);
        }

        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
            NestedVisitorMap::None
        }
    }

    for impl_item in impl_items {
        if_chain! {
            if impl_item.ident.name == sym::from;
            if let ImplItemKind::Fn(_, body_id) =
                cx.tcx.hir().impl_item(impl_item.id).kind;
            then {
                // check the body for `begin_panic` or `unwrap`
                let body = cx.tcx.hir().body(body_id);
                let mut fpu = FindPanicUnwrap {
                    lcx: cx,
                    typeck_results: cx.tcx.typeck(impl_item.id.def_id),
                    result: Vec::new(),
                };
                fpu.visit_expr(&body.value);

                // if we've found one, lint
                if !fpu.result.is_empty() {
                    span_lint_and_then(
                        cx,
                        FALLIBLE_IMPL_FROM,
                        impl_span,
                        "consider implementing `TryFrom` instead",
                        move |diag| {
                            diag.help(
                                "`From` is intended for infallible conversions only. \
                                Use `TryFrom` if there's a possibility for the conversion to fail");
                            diag.span_note(fpu.result, "potential failure(s)");
                        });
                }
            }
        }
    }
}
<commit_msg>Do not store visibility in *ItemRef.<commit_after>use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
    ///
    /// ### Why is this bad?
    /// `TryFrom` should be used if there's a possibility of failure.
    ///
    /// ### Example
    /// ```rust
    /// struct Foo(i32);
    ///
    /// // Bad
    /// impl From<String> for Foo {
    ///     fn from(s: String) -> Self {
    ///         Foo(s.parse().unwrap())
    ///     }
    /// }
    /// ```
    ///
    /// ```rust
    /// // Good
    /// struct Foo(i32);
    ///
    /// use std::convert::TryFrom;
    /// impl TryFrom<String> for Foo {
    ///     type Error = ();
    ///     fn try_from(s: String) -> Result<Self, Self::Error> {
    ///         if let Ok(parsed) = s.parse() {
    ///             Ok(Foo(parsed))
    ///         } else {
    ///             Err(())
    ///         }
    ///     }
    /// }
    /// ```
    pub FALLIBLE_IMPL_FROM,
    nursery,
    "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
}

declare_lint_pass!(FallibleImplFrom => [FALLIBLE_IMPL_FROM]);

impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
        // check for `impl From<???> for ..`
        if_chain! {
            if let hir::ItemKind::Impl(impl_) = &item.kind;
            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
            if cx.tcx.is_diagnostic_item(sym::from_trait, impl_trait_ref.def_id);
            then {
                lint_impl_body(cx, item.span, impl_.items);
            }
        }
    }
}

fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
    use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
    use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath};

    struct FindPanicUnwrap<'a, 'tcx> {
        lcx: &'a LateContext<'tcx>,
        typeck_results: &'tcx ty::TypeckResults<'tcx>,
        result: Vec<Span>,
    }

    impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
        type Map = Map<'tcx>;

        fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
            // check for `begin_panic`
            if_chain! {
                if let ExprKind::Call(func_expr, _) = expr.kind;
                if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
                if let Some(path_def_id) = path.res.opt_def_id();
                if match_panic_def_id(self.lcx, path_def_id);
                if is_expn_of(expr.span, "unreachable").is_none();
                then {
                    self.result.push(expr.span);
                }
            }

            // check for `unwrap`
            if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
                let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
                if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type)
                    || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type)
                {
                    self.result.push(expr.span);
                }
            }

            // and check sub-expressions
            intravisit::walk_expr(self, expr);
        }

        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
            NestedVisitorMap::None
        }
    }

    for impl_item in impl_items {
        if_chain! {
            if impl_item.ident.name == sym::from;
            if let ImplItemKind::Fn(_, body_id) =
                cx.tcx.hir().impl_item(impl_item.id).kind;
            then {
                // check the body for `begin_panic` or `unwrap`
                let body = cx.tcx.hir().body(body_id);
                let mut fpu = FindPanicUnwrap {
                    lcx: cx,
                    typeck_results: cx.tcx.typeck(impl_item.id.def_id),
                    result: Vec::new(),
                };
                fpu.visit_expr(&body.value);

                // if we've found one, lint
                if !fpu.result.is_empty() {
                    span_lint_and_then(
                        cx,
                        FALLIBLE_IMPL_FROM,
                        impl_span,
                        "consider implementing `TryFrom` instead",
                        move |diag| {
                            diag.help(
                                "`From` is intended for infallible conversions only. \
                                Use `TryFrom` if there's a possibility for the conversion to fail");
                            diag.span_note(fpu.result, "potential failure(s)");
                        });
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::rc::Rc;
use std::collections::HashMap;
use std::path::PathBuf;
use super::super::{Result, Document, DocumentMetadata, DocumentContent};

pub struct IndexGenerator;

impl super::Generator for IndexGenerator {
    fn new() -> IndexGenerator { IndexGenerator }

    fn generate(&self, docs: &[Rc<DocumentMetadata>]) -> Result<Vec<Rc<Document>>> {
        let mut indexes: HashMap<String, Vec<Rc<DocumentMetadata>>> = HashMap::new();

        for doc in docs.iter() {
            let dir: String = PathBuf::from(&doc.url)
                .parent()
                .and_then(|p| p.to_str())
                .unwrap_or("")
                .into();

            println!("Adding page {} to the index {}...", doc.url, dir);
            let documents = indexes.entry(dir).or_insert_with(Vec::new);
            documents.push(doc.clone());
        }

        Ok(indexes.into_iter()
                  .map(|(url, docs)| {

                      let meta = DocumentMetadata {
                          url: format!("{}/index.html", url),
                          title: format!("Index of {}", url),
                          ..DocumentMetadata::default()
                      };
                      let content = DocumentContent::Index(docs);

                      Rc::new(Document::new(meta, content))
                  })
                  .collect())
    }
}
<commit_msg>Entries are sorted by date in indexes<commit_after>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::rc::Rc;
use std::collections::HashMap;
use std::path::PathBuf;
use super::super::{Result, Document, DocumentMetadata, DocumentContent};

pub struct IndexGenerator;

impl super::Generator for IndexGenerator {
    fn new() -> IndexGenerator { IndexGenerator }

    fn generate(&self, docs: &[Rc<DocumentMetadata>]) -> Result<Vec<Rc<Document>>> {
        let mut indexes: HashMap<String, Vec<Rc<DocumentMetadata>>> = HashMap::new();

        for doc in docs.iter() {
            let dir: String = PathBuf::from(&doc.url)
                .parent()
                .and_then(|p| p.to_str())
                .unwrap_or("")
                .into();

            println!("Adding page {} to the index {}...", doc.url, dir);
            let documents = indexes.entry(dir).or_insert_with(Vec::new);
            documents.push(doc.clone());
        }

        Ok(indexes.into_iter()
                  .map(|(url, mut docs)| {

                      let meta = DocumentMetadata {
                          url: format!("{}/index.html", url),
                          title: format!("Index of {}", url),
                          ..DocumentMetadata::default()
                      };

                      docs.sort_by(|b, a| a.created.cmp(&b.created));
                      let content = DocumentContent::Index(docs);

                      Rc::new(Document::new(meta, content))
                  })
                  .collect())
    }
}
<|endoftext|>


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

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, scheme};

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

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::number::*;

use context::ContextId;
use interrupt::syscall::SyscallStack;
use scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => clone(b, bp).map(ContextId::into),
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, d),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { ::core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/bin/cargo" || name == "file:/bin/rustc" {
                if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

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

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

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

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

    /*
    if debug {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

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

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

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

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, scheme};

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

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::number::*;

use context::ContextId;
use interrupt::syscall::SyscallStack;
use scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut SyscallStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => clone(b, bp).map(ContextId::into),
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, d),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { ::core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/bin/cargo" || name == "file:/bin/rustc" {
                if a == SYS_CLOCK_GETTIME {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

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

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

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

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

    /*
    if debug {
        let contexts = ::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

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

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

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


<commit_before>use ::Point2f;
use interaction::SurfaceInteraction;

mod constant;
mod checkerboard;
mod image;

pub use self::constant::ConstantTexture;
pub use self::checkerboard::CheckerboardTexture;
pub use self::image::ImageTexture;

pub trait Texture<T> {
    fn evaluate(&self, si: &SurfaceInteraction) -> T;
}

// Texture mappings

pub trait TextureMapping2D {
    fn map(&self, si: &SurfaceInteraction) -> Point2f;
}

pub struct UVMapping2D {
    su: f32,
    sv: f32,
    du: f32,
    dv: f32,
}

impl UVMapping2D {
    pub fn new(su: f32, sv: f32, du: f32, dv: f32) -> UVMapping2D {
        UVMapping2D {
            su: su,
            sv: sv,
            du: du,
            dv: dv,
        }
    }
}

impl TextureMapping2D for UVMapping2D {
    fn map(&self, si: &SurfaceInteraction) -> Point2f {
        Point2f::new(self.su * si.uv.x + self.du, self.sv * si.uv.y + self.dv)
    }
}
<commit_msg>Add UVTexture (useful for debugging)<commit_after>use std::sync::Arc;

use ::Point2f;
use interaction::SurfaceInteraction;
use spectrum::Spectrum;

mod constant;
mod checkerboard;
mod image;

pub use self::constant::ConstantTexture;
pub use self::checkerboard::CheckerboardTexture;
pub use self::image::ImageTexture;

pub trait Texture<T> {
    fn evaluate(&self, si: &SurfaceInteraction) -> T;
}

pub struct UVTexture {
    mapping: Box<TextureMapping2D + Send + Sync>,
}

impl UVTexture {
    pub fn new() -> UVTexture {
        UVTexture { mapping: Box::new(UVMapping2D::new(1.0, 1.0, 0.0, 0.0)) }
    }
}

impl Texture<Spectrum> for UVTexture {
    fn evaluate(&self, si: &SurfaceInteraction) -> Spectrum {
        let st = self.mapping.map(si);
        Spectrum::rgb(st[0] - st[0].floor(), st[1] - st[1].floor(), 0.0)
    }
}

// Texture mappings

pub trait TextureMapping2D {
    fn map(&self, si: &SurfaceInteraction) -> Point2f;
}

pub struct UVMapping2D {
    su: f32,
    sv: f32,
    du: f32,
    dv: f32,
}

impl UVMapping2D {
    pub fn new(su: f32, sv: f32, du: f32, dv: f32) -> UVMapping2D {
        UVMapping2D {
            su: su,
            sv: sv,
            du: du,
            dv: dv,
        }
    }
}

impl TextureMapping2D for UVMapping2D {
    fn map(&self, si: &SurfaceInteraction) -> Point2f {
        Point2f::new(self.su * si.uv.x + self.du, self.sv * si.uv.y + self.dv)
    }
}
<|endoftext|>


<commit_before>/// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/theme.rs
/// released under the MIT license by @defuz

use std::str::FromStr;

use theme::settings::{ParseSettings, Settings};
use theme::style::*;
use theme::selector::*;
use scope::{ParseScopeError};

use self::ParseThemeError::*;

#[derive(Debug, Default)]
pub struct Theme {
    pub name: Option<String>,
    pub author: Option<String>,
    pub settings: ThemeSettings,
    pub scopes: Vec<ThemeItem>
}

#[derive(Debug, Default)]
pub struct ThemeSettings {
    /// Foreground color for the view.
    pub foreground: Option<Color>,
    /// Backgound color of the view.
    pub background: Option<Color>,
    /// Color of the caret.
    pub caret: Option<Color>,
    /// Color of the line the caret is in.
    /// Only used when the `higlight_line` setting is set to `true`.
    pub line_highlight: Option<Color>,

    /// Color of bracketed sections of text when the caret is in a bracketed section.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub bracket_contents_foreground: Option<Color>,
    /// Controls certain options when the caret is in a bracket section.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub bracket_contents_options: Option<UnderlineOption>,
    /// Foreground color of the brackets when the caret is next to a bracket.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub brackets_foreground: Option<Color>,
    /// Background color of the brackets when the caret is next to a bracket.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub brackets_background: Option<Color>,
    /// Controls certain options when the caret is next to a bracket.
    /// Only applied when the match_brackets setting is set to `true`.
    pub brackets_options: Option<UnderlineOption>,

    /// Color of tags when the caret is next to a tag.
    /// Only used when the `match_tags` setting is set to `true`.
    pub tags_foreground: Option<Color>,
    /// Controls certain options when the caret is next to a tag.
    /// Only applied when the match_tags setting is set to `true`.
    pub tags_options: Option<UnderlineOption>,

    /// Background color of regions matching the current search.
    pub find_highlight: Option<Color>,
    /// Background color of regions matching the current search.
    pub find_highlight_foreground: Option<Color>,

    /// Background color of the gutter.
    pub gutter: Option<Color>,
    /// Foreground color of the gutter.
    pub gutter_foreground: Option<Color>,

    /// Color of the selection regions.
    pub selection: Option<Color>,
    /// Background color of the selection regions.
    pub selection_background: Option<Color>,
    /// Color of the selection regions border.
    pub selection_border: Option<Color>,
    /// Color of inactive selections (inactive view).
    pub inactive_selection: Option<Color>,

    /// Color of the guides displayed to indicate nesting levels.
    pub guide: Option<Color>,
    /// Color of the guide lined up with the caret.
    /// Only applied if the `indent_guide_options` setting is set to `draw_active`.
    pub active_guide: Option<Color>,
    /// Color of the current guide’s parent guide level.
    /// Only used if the `indent_guide_options` setting is set to `draw_active`.
    pub stack_guide: Option<Color>,

    /// Background color for regions added via `sublime.add_regions()`
    /// with the `sublime.DRAW_OUTLINED` flag added.
    pub highlight: Option<Color>,
    /// Foreground color for regions added via `sublime.add_regions()`
    /// with the `sublime.DRAW_OUTLINED` flag added.
    pub highlight_foreground: Option<Color>
}

#[derive(Debug, Default)]
pub struct ThemeItem {
    /// Target scope name.
    pub scope: ScopeSelectors,
    pub style: StyleModifier
}

#[derive(Debug)]
pub enum UnderlineOption {
    None,
    Underline,
    StippledUnderline,
    SquigglyUnderline
}

#[derive(Debug)]
pub enum ParseThemeError {
    IncorrectUnderlineOption,
    IncorrectFontStyle(String),
    IncorrectColor,
    IncorrectSyntax,
    IncorrectSettings,
    UndefinedSettings,
    UndefinedScopeSettings(String),
    ColorShemeScopeIsNotObject,
    ColorShemeSettingsIsNotObject,
    ScopeSelectorIsNotString(String),
    DuplicateSettings,
    ScopeParse(ParseScopeError)
}

impl From<ParseScopeError> for ParseThemeError {
    fn from(error: ParseScopeError) -> ParseThemeError {
        ScopeParse(error)
    }
}

impl Default for UnderlineOption {
    fn default() -> UnderlineOption {
        UnderlineOption::None
    }
}

impl Default for FontStyle {
    fn default() -> FontStyle {
        FontStyle::empty()
    }
}

impl FromStr for UnderlineOption {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<UnderlineOption, Self::Err> {
        Ok(match s {
            "underline" => UnderlineOption::Underline,
            "stippled_underline" => UnderlineOption::StippledUnderline,
            "squiggly_underline" => UnderlineOption::SquigglyUnderline,
            _ => return Err(IncorrectUnderlineOption)
        })
    }
}

impl ParseSettings for UnderlineOption {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<UnderlineOption, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(UnderlineOption::from_str(&value))),
            _ => Err(IncorrectUnderlineOption)
        }
    }
}

impl FromStr for FontStyle {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<FontStyle, Self::Err> {
        let mut font_style = FontStyle::empty();
        for i in s.split_whitespace() {
            font_style.insert(match i {
                "bold" => FONT_STYLE_BOLD,
                "underline" => FONT_STYLE_UNDERLINE,
                "italic" => FONT_STYLE_ITALIC,
                s => return Err(IncorrectFontStyle(s.to_owned())),
            })
        }
        Ok(font_style)
    }
}

impl ParseSettings for FontStyle {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<FontStyle, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(FontStyle::from_str(&value))),
            c => Err(IncorrectFontStyle(c.to_string()))
        }
    }
}

impl FromStr for Color {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<Color, Self::Err> {
        let mut chars = s.chars();
        if chars.next() != Some('#') {
            return Err(IncorrectColor);
        }
        let mut d = Vec::new();
        for char in chars {
            d.push(try!(char.to_digit(16).ok_or(IncorrectColor)) as u8);
        }
        Ok(match d.len() {
            3 => Color { r: d[0], g: d[1], b: d[2], a: 255 },
            6 => Color { r: d[0]*16+d[1], g: d[2]*16+d[3], b: d[4]*16+d[5], a: 255 },
            8 => Color { r: d[0]*16+d[1], g: d[2]*16+d[3], b: d[4]*16+d[5], a: d[6]*16+d[7] },
            _ => return Err(IncorrectColor)
        })
    }
}

impl ParseSettings for Color {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Color, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(Color::from_str(&value))),
            _ => Err(IncorrectColor)
        }
    }
}

impl ParseSettings for StyleModifier {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<StyleModifier, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let font_style = match obj.remove("fontStyle") {
            Some(Settings::String(value)) => Some(try!(FontStyle::from_str(&value))),
            None => None,
            Some(c) => return Err(IncorrectFontStyle(c.to_string())),
        };
        let foreground = match obj.remove("foreground") {
            Some(Settings::String(value)) => Some(try!(Color::from_str(&value))),
            None => None,
            _ => return Err(IncorrectColor),
        };
        let background = match obj.remove("background") {
            Some(Settings::String(value)) => Some(try!(Color::from_str(&value))),
            None => None,
            _ => return Err(IncorrectColor),
        };

        Ok(StyleModifier { foreground: foreground, background: background, font_style: font_style })
    }
}

impl ParseSettings for ThemeItem {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<ThemeItem, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let scope = match obj.remove("scope") {
            Some(Settings::String(value)) => try!(ScopeSelectors::from_str(&value)),
            _ => return Err(ScopeSelectorIsNotString(format!("{:?}", obj))),
        };
        let style = match obj.remove("settings") {
            Some(settings) => try!(StyleModifier::parse_settings(settings)),
            None => return Err(IncorrectSettings)
        };
        Ok(ThemeItem { scope: scope, style: style })
    }
}

impl ParseSettings for ThemeSettings {
    type Error = ParseThemeError;

    #[allow(cyclomatic_complexity)]
    fn parse_settings(json: Settings) -> Result<ThemeSettings, Self::Error> {
        let mut settings = ThemeSettings::default();

        let obj = match json {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeSettingsIsNotObject),
        };

        for (key, value) in obj {
            match &key[..] {
                "foreground" =>
                    settings.foreground = Some(try!(Color::parse_settings(value))),
                "background" =>
                    settings.background = Some(try!(Color::parse_settings(value))),
                "caret" =>
                    settings.caret = Some(try!(Color::parse_settings(value))),
                "lineHighlight" =>
                    settings.line_highlight = Some(try!(Color::parse_settings(value))),
                "bracketContentsForeground" =>
                    settings.bracket_contents_foreground = Some(try!(Color::parse_settings(value))),
                "bracketContentsOptions" =>
                    settings.bracket_contents_options = Some(try!(UnderlineOption::parse_settings(value))),
                "bracketsForeground" =>
                    settings.brackets_foreground = Some(try!(Color::parse_settings(value))),
                "bracketsBackground" =>
                    settings.brackets_background = Some(try!(Color::parse_settings(value))),
                "bracketsOptions" =>
                    settings.brackets_options = Some(try!(UnderlineOption::parse_settings(value))),
                "tagsForeground" =>
                    settings.tags_foreground = Some(try!(Color::parse_settings(value))),
                "tagsOptions" =>
                    settings.tags_options = Some(try!(UnderlineOption::parse_settings(value))),
                "findHighlight" =>
                    settings.find_highlight = Some(try!(Color::parse_settings(value))),
                "findHighlightForeground" =>
                    settings.find_highlight_foreground = Some(try!(Color::parse_settings(value))),
                "gutter" =>
                    settings.gutter = Some(try!(Color::parse_settings(value))),
                "gutterForeground" =>
                    settings.gutter_foreground = Some(try!(Color::parse_settings(value))),
                "selection" =>
                    settings.selection = Some(try!(Color::parse_settings(value))),
                "selectionBackground" =>
                    settings.selection_background = Some(try!(Color::parse_settings(value))),
                "selectionBorder" =>
                    settings.selection_border = Some(try!(Color::parse_settings(value))),
                "inactiveSelection" =>
                    settings.inactive_selection = Some(try!(Color::parse_settings(value))),
                "guide" =>
                    settings.guide = Some(try!(Color::parse_settings(value))),
                "activeGuide" =>
                    settings.active_guide = Some(try!(Color::parse_settings(value))),
                "stackGuide" =>
                    settings.stack_guide = Some(try!(Color::parse_settings(value))),
                "highlight" =>
                    settings.highlight = Some(try!(Color::parse_settings(value))),
                "highlightForeground" =>
                    settings.highlight_foreground = Some(try!(Color::parse_settings(value))),
                "invisibles" => (), // ignored
                _ => return Err(UndefinedScopeSettings(key))
            }
        };
        Ok(settings)
    }
}

impl ParseSettings for Theme {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Theme, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(IncorrectSyntax)
        };
        let name = match obj.remove("name") {
            Some(Settings::String(name)) => Some(name),
            None => None,
            _ => return Err(IncorrectSyntax)
        };
        let author = match obj.remove("author") {
            Some(Settings::String(author)) => Some(author),
            None => None,
            _ => return Err(IncorrectSyntax)
        };
        let items = match obj.remove("settings") {
            Some(Settings::Array(items)) => items,
            _ => return Err(IncorrectSyntax)
        };
        let mut iter = items.into_iter();
        let settings = match iter.next() {
            Some(Settings::Object(mut obj)) => {
                match obj.remove("settings") {
                    Some(settings) => try!(ThemeSettings::parse_settings(settings)),
                    None => return Err(UndefinedSettings)
                }
            },
            _ => return Err(UndefinedSettings)
        };
        let mut scopes = Vec::new();
        for json in iter {
            scopes.push(try!(ThemeItem::parse_settings(json)));
        }
        Ok(Theme {
            name: name,
            author: author,
            settings: settings,
            scopes: scopes
        })
    }
}
<commit_msg>Make the theme parsing more best-effort<commit_after>/// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/theme.rs
/// released under the MIT license by @defuz

use std::str::FromStr;

use theme::settings::{ParseSettings, Settings};
use theme::style::*;
use theme::selector::*;
use scope::{ParseScopeError};

use self::ParseThemeError::*;

#[derive(Debug, Default)]
pub struct Theme {
    pub name: Option<String>,
    pub author: Option<String>,
    pub settings: ThemeSettings,
    pub scopes: Vec<ThemeItem>
}

#[derive(Debug, Default)]
pub struct ThemeSettings {
    /// Foreground color for the view.
    pub foreground: Option<Color>,
    /// Backgound color of the view.
    pub background: Option<Color>,
    /// Color of the caret.
    pub caret: Option<Color>,
    /// Color of the line the caret is in.
    /// Only used when the `higlight_line` setting is set to `true`.
    pub line_highlight: Option<Color>,

    /// Color of bracketed sections of text when the caret is in a bracketed section.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub bracket_contents_foreground: Option<Color>,
    /// Controls certain options when the caret is in a bracket section.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub bracket_contents_options: Option<UnderlineOption>,
    /// Foreground color of the brackets when the caret is next to a bracket.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub brackets_foreground: Option<Color>,
    /// Background color of the brackets when the caret is next to a bracket.
    /// Only applied when the `match_brackets` setting is set to `true`.
    pub brackets_background: Option<Color>,
    /// Controls certain options when the caret is next to a bracket.
    /// Only applied when the match_brackets setting is set to `true`.
    pub brackets_options: Option<UnderlineOption>,

    /// Color of tags when the caret is next to a tag.
    /// Only used when the `match_tags` setting is set to `true`.
    pub tags_foreground: Option<Color>,
    /// Controls certain options when the caret is next to a tag.
    /// Only applied when the match_tags setting is set to `true`.
    pub tags_options: Option<UnderlineOption>,

    /// Background color of regions matching the current search.
    pub find_highlight: Option<Color>,
    /// Background color of regions matching the current search.
    pub find_highlight_foreground: Option<Color>,

    /// Background color of the gutter.
    pub gutter: Option<Color>,
    /// Foreground color of the gutter.
    pub gutter_foreground: Option<Color>,

    /// Color of the selection regions.
    pub selection: Option<Color>,
    /// Background color of the selection regions.
    pub selection_background: Option<Color>,
    /// Color of the selection regions border.
    pub selection_border: Option<Color>,
    /// Color of inactive selections (inactive view).
    pub inactive_selection: Option<Color>,

    /// Color of the guides displayed to indicate nesting levels.
    pub guide: Option<Color>,
    /// Color of the guide lined up with the caret.
    /// Only applied if the `indent_guide_options` setting is set to `draw_active`.
    pub active_guide: Option<Color>,
    /// Color of the current guide’s parent guide level.
    /// Only used if the `indent_guide_options` setting is set to `draw_active`.
    pub stack_guide: Option<Color>,

    /// Background color for regions added via `sublime.add_regions()`
    /// with the `sublime.DRAW_OUTLINED` flag added.
    pub highlight: Option<Color>,
    /// Foreground color for regions added via `sublime.add_regions()`
    /// with the `sublime.DRAW_OUTLINED` flag added.
    pub highlight_foreground: Option<Color>
}

#[derive(Debug, Default)]
pub struct ThemeItem {
    /// Target scope name.
    pub scope: ScopeSelectors,
    pub style: StyleModifier
}

#[derive(Debug)]
pub enum UnderlineOption {
    None,
    Underline,
    StippledUnderline,
    SquigglyUnderline
}

#[derive(Debug)]
pub enum ParseThemeError {
    IncorrectUnderlineOption,
    IncorrectFontStyle(String),
    IncorrectColor,
    IncorrectSyntax,
    IncorrectSettings,
    UndefinedSettings,
    UndefinedScopeSettings(String),
    ColorShemeScopeIsNotObject,
    ColorShemeSettingsIsNotObject,
    ScopeSelectorIsNotString(String),
    DuplicateSettings,
    ScopeParse(ParseScopeError)
}

impl From<ParseScopeError> for ParseThemeError {
    fn from(error: ParseScopeError) -> ParseThemeError {
        ScopeParse(error)
    }
}

impl Default for UnderlineOption {
    fn default() -> UnderlineOption {
        UnderlineOption::None
    }
}

impl Default for FontStyle {
    fn default() -> FontStyle {
        FontStyle::empty()
    }
}

impl FromStr for UnderlineOption {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<UnderlineOption, Self::Err> {
        Ok(match s {
            "underline" => UnderlineOption::Underline,
            "stippled_underline" => UnderlineOption::StippledUnderline,
            "squiggly_underline" => UnderlineOption::SquigglyUnderline,
            _ => return Err(IncorrectUnderlineOption)
        })
    }
}

impl ParseSettings for UnderlineOption {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<UnderlineOption, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(UnderlineOption::from_str(&value))),
            _ => Err(IncorrectUnderlineOption)
        }
    }
}

impl FromStr for FontStyle {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<FontStyle, Self::Err> {
        let mut font_style = FontStyle::empty();
        for i in s.split_whitespace() {
            font_style.insert(match i {
                "bold" => FONT_STYLE_BOLD,
                "underline" => FONT_STYLE_UNDERLINE,
                "italic" => FONT_STYLE_ITALIC,
                "normal" => FontStyle::empty(),
                s => return Err(IncorrectFontStyle(s.to_owned())),
            })
        }
        Ok(font_style)
    }
}

impl ParseSettings for FontStyle {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<FontStyle, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(FontStyle::from_str(&value))),
            c => Err(IncorrectFontStyle(c.to_string()))
        }
    }
}

impl FromStr for Color {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<Color, Self::Err> {
        let mut chars = s.chars();
        if chars.next() != Some('#') {
            return Err(IncorrectColor);
        }
        let mut d = Vec::new();
        for char in chars {
            d.push(try!(char.to_digit(16).ok_or(IncorrectColor)) as u8);
        }
        Ok(match d.len() {
            3 => Color { r: d[0], g: d[1], b: d[2], a: 255 },
            6 => Color { r: d[0]*16+d[1], g: d[2]*16+d[3], b: d[4]*16+d[5], a: 255 },
            8 => Color { r: d[0]*16+d[1], g: d[2]*16+d[3], b: d[4]*16+d[5], a: d[6]*16+d[7] },
            _ => return Err(IncorrectColor)
        })
    }
}

impl ParseSettings for Color {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Color, Self::Error> {
        match settings {
            Settings::String(value) => Ok(try!(Color::from_str(&value))),
            _ => Err(IncorrectColor)
        }
    }
}

impl ParseSettings for StyleModifier {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<StyleModifier, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let font_style = match obj.remove("fontStyle") {
            Some(Settings::String(value)) => Some(try!(FontStyle::from_str(&value))),
            None => None,
            Some(c) => return Err(IncorrectFontStyle(c.to_string())),
        };
        let foreground = match obj.remove("foreground") {
            Some(Settings::String(value)) => Some(try!(Color::from_str(&value))),
            None => None,
            _ => return Err(IncorrectColor),
        };
        let background = match obj.remove("background") {
            Some(Settings::String(value)) => Some(try!(Color::from_str(&value))),
            None => None,
            _ => return Err(IncorrectColor),
        };

        Ok(StyleModifier { foreground: foreground, background: background, font_style: font_style })
    }
}

impl ParseSettings for ThemeItem {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<ThemeItem, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let scope = match obj.remove("scope") {
            Some(Settings::String(value)) => try!(ScopeSelectors::from_str(&value)),
            _ => return Err(ScopeSelectorIsNotString(format!("{:?}", obj))),
        };
        let style = match obj.remove("settings") {
            Some(settings) => try!(StyleModifier::parse_settings(settings)),
            None => return Err(IncorrectSettings)
        };
        Ok(ThemeItem { scope: scope, style: style })
    }
}

impl ParseSettings for ThemeSettings {
    type Error = ParseThemeError;

    fn parse_settings(json: Settings) -> Result<ThemeSettings, Self::Error> {
        let mut settings = ThemeSettings::default();

        let obj = match json {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeSettingsIsNotObject),
        };

        for (key, value) in obj {
            match &key[..] {
                "foreground" =>
                    settings.foreground = Color::parse_settings(value).ok(),
                "background" =>
                    settings.background = Color::parse_settings(value).ok(),
                "caret" =>
                    settings.caret = Color::parse_settings(value).ok(),
                "lineHighlight" =>
                    settings.line_highlight = Color::parse_settings(value).ok(),
                "bracketContentsForeground" =>
                    settings.bracket_contents_foreground = Color::parse_settings(value).ok(),
                "bracketContentsOptions" =>
                    settings.bracket_contents_options = UnderlineOption::parse_settings(value).ok(),
                "bracketsForeground" =>
                    settings.brackets_foreground = Color::parse_settings(value).ok(),
                "bracketsBackground" =>
                    settings.brackets_background = Color::parse_settings(value).ok(),
                "bracketsOptions" =>
                    settings.brackets_options = UnderlineOption::parse_settings(value).ok(),
                "tagsForeground" =>
                    settings.tags_foreground = Color::parse_settings(value).ok(),
                "tagsOptions" =>
                    settings.tags_options = UnderlineOption::parse_settings(value).ok(),
                "findHighlight" =>
                    settings.find_highlight = Color::parse_settings(value).ok(),
                "findHighlightForeground" =>
                    settings.find_highlight_foreground = Color::parse_settings(value).ok(),
                "gutter" =>
                    settings.gutter = Color::parse_settings(value).ok(),
                "gutterForeground" =>
                    settings.gutter_foreground = Color::parse_settings(value).ok(),
                "selection" =>
                    settings.selection = Color::parse_settings(value).ok(),
                "selectionBackground" =>
                    settings.selection_background = Color::parse_settings(value).ok(),
                "selectionBorder" =>
                    settings.selection_border = Color::parse_settings(value).ok(),
                "inactiveSelection" =>
                    settings.inactive_selection = Color::parse_settings(value).ok(),
                "guide" =>
                    settings.guide = Color::parse_settings(value).ok(),
                "activeGuide" =>
                    settings.active_guide = Color::parse_settings(value).ok(),
                "stackGuide" =>
                    settings.stack_guide = Color::parse_settings(value).ok(),
                "highlight" =>
                    settings.highlight = Color::parse_settings(value).ok(),
                "highlightForeground" =>
                    settings.highlight_foreground = Color::parse_settings(value).ok(),
                "invisibles" => (), // ignored
                _ => (),
            }
        };
        Ok(settings)
    }
}

impl ParseSettings for Theme {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Theme, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(IncorrectSyntax)
        };
        let name = match obj.remove("name") {
            Some(Settings::String(name)) => Some(name),
            None => None,
            _ => return Err(IncorrectSyntax)
        };
        let author = match obj.remove("author") {
            Some(Settings::String(author)) => Some(author),
            None => None,
            _ => return Err(IncorrectSyntax)
        };
        let items = match obj.remove("settings") {
            Some(Settings::Array(items)) => items,
            _ => return Err(IncorrectSyntax)
        };
        let mut iter = items.into_iter();
        let settings = match iter.next() {
            Some(Settings::Object(mut obj)) => {
                match obj.remove("settings") {
                    Some(settings) => try!(ThemeSettings::parse_settings(settings)),
                    None => return Err(UndefinedSettings)
                }
            },
            _ => return Err(UndefinedSettings)
        };
        let mut scopes = Vec::new();
        for json in iter {
            // TODO option to disable best effort parsing and bubble up warnings
            if let Ok(item) = ThemeItem::parse_settings(json) {
                scopes.push(item);
            }
        }
        Ok(Theme {
            name: name,
            author: author,
            settings: settings,
            scopes: scopes
        })
    }
}
<|endoftext|>