<commit_before>use super::memory;
use num::FromPrimitive;
use std::fmt;

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum RegPair {
    BC = 0b00,
    DE = 0b01,
    HL = 0b10,
    SP = 0b11
}
}

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg {
    A = 0b111,
    B = 0b000,
    C = 0b001,
    D = 0b010,
    E = 0b011,
    H = 0b100,
    L = 0b101
}
}

#[derive(Debug)]
pub struct Cpu {
    af: u16,
    bc: u16,
    de: u16,
    hl: u16,
    af_: u16,
    bc_: u16,
    de_: u16,
    hl_: u16,
    ir: u16,
    ix: u16,
    iy: u16,
    sp: u16,
    pc: u16,

    iff1: bool,
    iff2: bool,

    memory: memory::Memory
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            af: 0,
            bc: 0,
            de: 0,
            hl: 0,
            af_: 0,
            bc_: 0,
            de_: 0,
            hl_: 0,
            ir: 0,
            ix: 0,
            iy: 0,
            sp: 0,
            pc: 0,

            iff1: false,
            iff2: false,

            memory: memory
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    // TODO have a single function called write_reg that handles multiple types
    fn write_regpair(&mut self, reg: RegPair, val: u16) {
        match reg {
            RegPair::BC => { self.bc = val; }
            RegPair::DE => { self.de = val; }
            RegPair::HL => { self.hl = val; }
            RegPair::SP => { self.sp = val; }
        }
    }

    fn write_reg(&mut self, reg: Reg, val: u8) {
        match reg {
            Reg::A => { self.af |= (val as u16) << 8 }
            Reg::B => { self.bc |= (val as u16) << 8 }
            Reg::C => { self.bc |=  val as u16       }
            Reg::D => { self.de |= (val as u16) << 8 }
            Reg::E => { self.de |=  val as u16       }
            Reg::H => { self.hl |= (val as u16) << 8 }
            Reg::L => { self.hl |=  val as u16       }

        }
    }

    // TODO have a single function called read_reg that handles multiple types
    fn read_regpair(&mut self, reg: RegPair) -> u16 {
        match reg {
            RegPair::BC => { self.bc }
            RegPair::DE => { self.de }
            RegPair::HL => { self.hl }
            RegPair::SP => { self.sp }
        }
    }

    fn read_reg(&mut self, reg: Reg) -> u8 {
        match reg {
            Reg::A => { ((self.af & 0xFF00) >> 8) as u8 }
            Reg::B => { ((self.bc & 0xFF00) >> 8) as u8 }
            Reg::C => { ((self.bc & 0x00FF)     ) as u8 }
            Reg::D => { ((self.de & 0xFF00) >> 8) as u8 }
            Reg::E => { ((self.de & 0x00FF)     ) as u8 }
            Reg::H => { ((self.hl & 0xFF00) >> 8) as u8 }
            Reg::L => { ((self.hl & 0x00FF)     ) as u8 }
        }
    }

    fn run_instruction(&mut self) {
        let instruction = self.read_word(self.pc);

        match instruction {
            instruction if instruction & 0b11000000 == 0b01000000 => {
                // TODO Better Option handling here
                let rt = Reg::from_u8((instruction >> 3) & 0b111).unwrap();
                let rs = Reg::from_u8( instruction       & 0b111).unwrap();
                let rsval = self.read_reg(rs);
                self.write_reg(rt, rsval);
                println!("{:#x}: LD {:?}, {:?}", self.pc, rt, rs);
                self.pc += 1;
            }
            0b11110011 => {
                self.iff1 = false;
                self.iff2 = false;
                println!("{:#x}: DI", self.pc);
                self.pc += 1;
            },
            0b00000001 | 0b00010001 | 0b00100001 | 0b00110001 => {
                let nn = (self.read_word(self.pc + 1) as u16) +
                        ((self.read_word(self.pc + 2) as u16) << 8);
                let regpair = RegPair::from_u8((instruction & 0b00110000) >> 4);
                match regpair {
                    Some(RegPair::BC) => { self.bc = nn; }
                    Some(RegPair::DE) => { self.de = nn; }
                    Some(RegPair::HL) => { self.hl = nn; }
                    Some(RegPair::SP) => { self.sp = nn; }
                    _ => {
                        panic!("Error when parsing \"LD dd, nn\" instruction");
                    }
                }
                println!("{:#x}: LD {:?}, ${:x}", self.pc, regpair.unwrap(), nn);
                self.pc += 3;
            },
            0b00001011 | 0b00011011 | 0b00101011 | 0b00111011 => {
                let regpair = RegPair::from_u8((instruction & 0b00110000) >> 4);
                match regpair {
                    Some(RegPair::BC) => { self.bc -= 1; }
                    Some(RegPair::DE) => { self.de -= 1; }
                    Some(RegPair::HL) => { self.hl -= 1; }
                    Some(RegPair::SP) => { self.sp -= 1; }
                    _ => {
                        panic!("Error when parsing \"DEC ss\" instruction");
                    }
                }
                println!("{:#x}: DEC {:?}", self.pc, regpair.unwrap());
                self.pc += 1;
            }
            _ => {
                panic!("Unrecognized instruction: {:#x}", instruction);
            }
        }
    }

    fn read_word(&self, addr: u16) -> u8 {
        self.memory.read_word(addr)
    }
}

<commit_msg>Refactor Cpu and registers<commit_after>use super::memory;
use num::FromPrimitive;
use std::fmt;

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg16 {
    BC = 0b00,
    DE = 0b01,
    HL = 0b10,
    SP = 0b11
}
}

enum_from_primitive! {
#[derive(Debug, Clone, Copy)]
enum Reg8 {
    A = 0b111,
    B = 0b000,
    C = 0b001,
    D = 0b010,
    E = 0b011,
    H = 0b100,
    L = 0b101
}
}

#[derive(Debug)]
pub struct Cpu {
    // main register set
    a: u8, f: u8,
    b: u8, c: u8,
    d: u8, e: u8,
    h: u8, l: u8,

    // alternate register set
    a_alt: u8, f_alt: u8,
    b_alt: u8, c_alt: u8,
    d_alt: u8, e_alt: u8,
    h_alt: u8, l_alt: u8,

    // interrupt vector
    i: u8,

    // memory refresh
    r: u8,

    // index register X
    ix: u16,

    // index register Y
    iy: u16,

    // stack pointer
    sp: u16,

    // program counter
    pc: u16,

    // interrupt flip-flops
    iff1: bool,
    iff2: bool,

    memory: memory::Memory
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        Cpu {
            a: 0, f: 0,
            b: 0, c: 0,
            d: 0, e: 0,
            h: 0, l: 0,
            a_alt: 0, f_alt: 0,
            b_alt: 0, c_alt: 0,
            d_alt: 0, e_alt: 0,
            h_alt: 0, l_alt: 0,
            i: 0,
            r: 0,
            ix: 0,
            iy: 0,
            sp: 0,
            pc: 0,
            iff1: false,
            iff2: false,

            memory: memory
        }
    }

    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    fn read_reg8(&self, reg: Reg8) -> u8 {
        match reg {
            Reg8::A => self.a,
            Reg8::B => self.b,
            Reg8::C => self.c,
            Reg8::D => self.d,
            Reg8::E => self.e,
            Reg8::H => self.h,
            Reg8::L => self.l
        }
    }

    fn write_reg8(&mut self, reg: Reg8, val: u8) {
        match reg {
            Reg8::A => self.a = val,
            Reg8::B => self.b = val,
            Reg8::C => self.c = val,
            Reg8::D => self.d = val,
            Reg8::E => self.e = val,
            Reg8::H => self.h = val,
            Reg8::L => self.l = val
        }
    }

    fn read_reg16(&self, reg: Reg16) -> u16 {
        let value = match reg {
            Reg16::SP => self.sp,
            _ => {
                let (high, low) = match reg {
                    Reg16::BC => (self.b, self.c),
                    Reg16::DE => (self.d, self.e),
                    Reg16::HL => (self.h, self.l),
                    _ => unreachable!()
                };
                (((high as u16) << 8 ) + low as u16)
            }
        };
        value
    }

    fn write_reg16(&mut self, reg: Reg16, val: u16) {
        let (high, low) = (((val & 0xFF00) >> 8) as u8, (val & 0x00FF) as u8);
        match reg {
            Reg16::BC => { self.b = high; self.c = low; }
            Reg16::DE => { self.d = high; self.e = low; }
            Reg16::HL => { self.h = high; self.l = low; }
            Reg16::SP => { self.sp = val }
        }
    }

    fn run_instruction(&mut self) {
        let instruction = self.read_word(self.pc);

        match instruction {
            instruction if instruction & 0b11000000 == 0b01000000 => {
                // TODO Better Option handling here
                let rt = Reg8::from_u8((instruction >> 3) & 0b111).unwrap();
                let rs = Reg8::from_u8( instruction       & 0b111).unwrap();
                let rsval = self.read_reg8(rs);
                self.write_reg8(rt, rsval);
                println!("{:#x}: LD {:?}, {:?}", self.pc, rt, rs);
                self.pc += 1;
            },

            0b11110011 => {
                self.iff1 = false;
                self.iff2 = false;
                println!("{:#x}: DI", self.pc);
                self.pc += 1;
            },

            0b00000001 | 0b00010001 | 0b00100001 | 0b00110001 => {
                let nn = (self.read_word(self.pc + 1) as u16) +
                        ((self.read_word(self.pc + 2) as u16) << 8);
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                self.write_reg16(regpair, nn);

                println!("{:#x}: LD {:?}, ${:x}", self.pc, regpair, nn);
                self.pc += 3;
            },
            0b00001011 | 0b00011011 | 0b00101011 | 0b00111011 => {
                let regpair = Reg16::from_u8((instruction & 0b00110000) >> 4).unwrap();
                let oldregval = self.read_reg16(regpair);
                self.write_reg16(regpair, oldregval - 1);

                println!("{:#x}: DEC {:?}", self.pc, regpair);
                self.pc += 1;
            },
            _ => {
                panic!("Unrecognized instruction: {:#x}", instruction);
            }
        }
    }

    fn read_word(&self, addr: u16) -> u8 {
        self.memory.read_word(addr)
    }
}

<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::io::{Cursor, ErrorKind, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};

#[cfg(feature = "chrono")]
use chrono::{DateTime, Date, TimeZone, Local};

use fs::{FatFileSystemRef, FatSlice};
use file::FatFile;

#[derive(Clone)]
pub(crate) enum FatDirReader<'a, 'b: 'a> {
    File(FatFile<'a, 'b>),
    Root(FatSlice<'a, 'b>),
}

impl <'a, 'b> Read for FatDirReader<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            &mut FatDirReader::File(ref mut file) => file.read(buf),
            &mut FatDirReader::Root(ref mut raw) => raw.read(buf),
        }
    }
}

impl <'a, 'b> Seek for FatDirReader<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        match self {
            &mut FatDirReader::File(ref mut file) => file.seek(pos),
            &mut FatDirReader::Root(ref mut raw) => raw.seek(pos),
        }
    }
}

bitflags! {
    #[derive(Default)]
    pub struct FatFileAttributes: u8 {
        const READ_ONLY  = 0x01;
        const HIDDEN     = 0x02;
        const SYSTEM     = 0x04;
        const VOLUME_ID  = 0x08;
        const DIRECTORY  = 0x10;
        const ARCHIVE    = 0x20;
        const LFN        = Self::READ_ONLY.bits | Self::HIDDEN.bits
                         | Self::SYSTEM.bits | Self::VOLUME_ID.bits;
    }
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct FatDirFileEntryData {
    name: [u8; 11],
    attrs: FatFileAttributes,
    reserved_0: u8,
    create_time_0: u8,
    create_time_1: u16,
    create_date: u16,
    access_date: u16,
    first_cluster_hi: u16,
    modify_time: u16,
    modify_date: u16,
    first_cluster_lo: u16,
    size: u32,
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct FatDirLfnEntryData {
    order: u8,
    name_0: [u16; 5],
    attrs: FatFileAttributes,
    entry_type: u8,
    checksum: u8,
    name_1: [u16; 6],
    reserved_0: u16,
    name_2: [u16; 2],
}

#[derive(Clone, Debug)]
enum FatDirEntryData {
    File(FatDirFileEntryData),
    Lfn(FatDirLfnEntryData),
}

#[derive(Clone)]
pub struct FatDirEntry<'a, 'b: 'a> {
    data: FatDirFileEntryData,
    lfn: Vec<u16>,
    fs: FatFileSystemRef<'a, 'b>,
}

pub struct DosDate {
    pub year: u16,
    pub month: u16,
    pub day: u16,
}

pub struct DosTime {
    pub hour: u16,
    pub min: u16,
    pub sec: u16,
}

pub struct DosDateTime {
    pub date: DosDate,
    pub time: DosTime,
}

impl DosDate {
    pub(crate) fn from_word(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        DosDate { year, month, day }
    }
}

impl DosTime {
    pub(crate) fn from_word(dos_time: u16) -> Self {
        let (hour, min, sec) = (dos_time >> 11, (dos_time >> 5) & 0x3F, (dos_time & 0x1F) * 2);
        DosTime { hour, min, sec }
    }
}

impl DosDateTime {
    pub(crate) fn from_words(dos_date: u16, dos_time: u16) -> Self {
        DosDateTime {
            date: DosDate::from_word(dos_date),
            time: DosTime::from_word(dos_time),
        }
    }
}

#[cfg(feature = "chrono")]
impl From<DosDate> for Date<Local> {
    fn from(date: DosDate) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DosDateTime> for DateTime<Local> {
    fn from(date_time: DosDateTime) -> Self {
        Date::<Local>::from(date_time.date)
            .and_hms(date_time.time.hour as u32, date_time.time.min as u32, date_time.time.sec as u32)
    }
}

impl <'a, 'b> FatDirEntry<'a, 'b> {
    pub fn short_file_name(&self) -> String {
        let name_str = String::from_utf8_lossy(&self.data.name[0..8]);
        let ext_str = String::from_utf8_lossy(&self.data.name[8..11]);
        let name_trimmed = name_str.trim_right();
        let ext_trimmed = ext_str.trim_right();
        if ext_trimmed.is_empty() {
            name_trimmed.to_string()
        } else {
            format!("{}.{}", name_trimmed, ext_trimmed)
        }
    }

    pub fn file_name(&self) -> String {
        if self.lfn.len() > 0 {
            String::from_utf16_lossy(&self.lfn)
        } else {
            self.short_file_name()
        }
    }

    pub fn attributes(&self) -> FatFileAttributes {
        self.data.attrs
    }

    pub fn is_dir(&self) -> bool {
        self.data.attrs.contains(FatFileAttributes::DIRECTORY)
    }

    pub fn is_file(&self) -> bool {
        !self.is_dir()
    }

    pub(crate) fn first_cluster(&self) -> u32 {
        ((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32
    }

    pub fn to_file(&self) -> FatFile<'a, 'b> {
        if self.is_dir() {
            panic!("This is a directory");
        }
        FatFile::new(self.first_cluster(), Some(self.data.size), self.fs)
    }

    pub fn to_dir(&self) -> FatDir<'a, 'b> {
        if !self.is_dir() {
            panic!("This is a file");
        }
        let file = FatFile::new(self.first_cluster(), None, self.fs);
        FatDir::new(FatDirReader::File(file), self.fs)
    }

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

    pub fn created(&self) -> DosDateTime {
        DosDateTime::from_words(self.data.create_date, self.data.create_time_1)
    }

    pub fn accessed(&self) -> DosDate {
        DosDate::from_word(self.data.access_date)
    }

    pub fn modified(&self) -> DosDateTime {
        DosDateTime::from_words(self.data.modify_date, self.data.modify_time)
    }
}

impl <'a, 'b> fmt::Debug for FatDirEntry<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.data.fmt(f)
    }
}

#[derive(Clone)]
pub struct FatDir<'a, 'b: 'a> {
    rdr: FatDirReader<'a, 'b>,
    fs: FatFileSystemRef<'a, 'b>,
}

impl <'a, 'b> FatDir<'a, 'b> {

    pub(crate) fn new(rdr: FatDirReader<'a, 'b>, fs: FatFileSystemRef<'a, 'b>) -> FatDir<'a, 'b> {
        FatDir { rdr, fs }
    }

    pub fn iter(&self) -> FatDirIter<'a, 'b> {
        FatDirIter {
            rdr: self.rdr.clone(),
            fs: self.fs.clone(),
        }
    }

    fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) {
        let mut path_split = path.trim_matches('/').splitn(2, "/");
        let comp = path_split.next().unwrap();
        let rest_opt = path_split.next();
        (comp, rest_opt)
    }

    fn find_entry(&mut self, name: &str) -> io::Result<FatDirEntry<'a, 'b>> {
        for r in self.iter() {
            let e = r?;
            if e.file_name().eq_ignore_ascii_case(name) {
                return Ok(e);
            }
        }
        Err(io::Error::new(ErrorKind::NotFound, "file not found"))
    }

    pub fn open_dir(&mut self, path: &str) -> io::Result<FatDir<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_dir(rest),
            None => Ok(e.to_dir())
        }
    }

    pub fn open_file(&mut self, path: &str) -> io::Result<FatFile<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_file(rest),
            None => Ok(e.to_file())
        }
    }
}

#[derive(Clone)]
pub struct FatDirIter<'a, 'b: 'a> {
    rdr: FatDirReader<'a, 'b>,
    fs: FatFileSystemRef<'a, 'b>,
}

impl <'a, 'b> FatDirIter<'a, 'b> {
    fn read_dir_entry_data(&mut self) -> io::Result<FatDirEntryData> {
        let mut name = [0; 11];
        self.rdr.read(&mut name)?;
        let attrs = FatFileAttributes::from_bits(self.rdr.read_u8()?).expect("invalid attributes");
        if attrs == FatFileAttributes::LFN {
            let mut data = FatDirLfnEntryData {
                attrs, ..Default::default()
            };
            let mut cur = Cursor::new(&name);
            data.order = cur.read_u8()?;
            cur.read_u16_into::<LittleEndian>(&mut data.name_0)?;
            data.entry_type = self.rdr.read_u8()?;
            data.checksum = self.rdr.read_u8()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?;
            data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?;
            Ok(FatDirEntryData::Lfn(data))
        } else {
            let data = FatDirFileEntryData {
                name,
                attrs,
                reserved_0:       self.rdr.read_u8()?,
                create_time_0:    self.rdr.read_u8()?,
                create_time_1:    self.rdr.read_u16::<LittleEndian>()?,
                create_date:      self.rdr.read_u16::<LittleEndian>()?,
                access_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_hi: self.rdr.read_u16::<LittleEndian>()?,
                modify_time:      self.rdr.read_u16::<LittleEndian>()?,
                modify_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
                size:             self.rdr.read_u32::<LittleEndian>()?,
            };
            Ok(FatDirEntryData::File(data))
        }
    }
}

impl <'a, 'b> Iterator for FatDirIter<'a, 'b> {
    type Item = io::Result<FatDirEntry<'a, 'b>>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut lfn_buf = Vec::<u16>::new();
        loop {
            let res = self.read_dir_entry_data();
            let data = match res {
                Ok(data) => data,
                Err(err) => return Some(Err(err)),
            };
            match data {
                FatDirEntryData::File(data) => {
                    // Check if this is end of dif
                    if data.name[0] == 0 {
                        return None;
                    }
                    // Check if this is deleted or volume ID entry
                    if data.name[0] == 0xE5 || data.attrs.contains(FatFileAttributes::VOLUME_ID) {
                        lfn_buf.clear();
                        continue;
                    }
                    // Truncate 0 and 0xFFFF characters from LFN buffer
                    let mut lfn_len = lfn_buf.len();
                    loop {
                        if lfn_len == 0 {
                            break;
                        }
                        match lfn_buf[lfn_len-1] {
                            0xFFFF | 0 => lfn_len -= 1,
                            _ => break,
                        }
                    }
                    lfn_buf.truncate(lfn_len);
                    return Some(Ok(FatDirEntry {
                        data,
                        lfn: lfn_buf,
                        fs: self.fs,
                    }));
                },
                FatDirEntryData::Lfn(data) => {
                    // Check if this is deleted entry
                    if data.order == 0xE5 {
                        lfn_buf.clear();
                        continue;
                    }
                    const LFN_PART_LEN: usize = 13;
                    let index = (data.order & 0x1F) - 1;
                    let pos = LFN_PART_LEN * index as usize;
                    // resize LFN buffer to have enough space for entire name
                    if lfn_buf.len() < pos + LFN_PART_LEN {
                       lfn_buf.resize(pos + LFN_PART_LEN, 0);
                    }
                    // copy name parts into LFN buffer
                    lfn_buf[pos+0..pos+5].clone_from_slice(&data.name_0);
                    lfn_buf[pos+5..pos+11].clone_from_slice(&data.name_1);
                    lfn_buf[pos+11..pos+13].clone_from_slice(&data.name_2);
                }
            };
        }
    }
}
<commit_msg>Fix possible deadlock if reading dir entry fails.<commit_after>use std::ascii::AsciiExt;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::io::{Cursor, ErrorKind, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};

#[cfg(feature = "chrono")]
use chrono::{DateTime, Date, TimeZone, Local};

use fs::{FatFileSystemRef, FatSlice};
use file::FatFile;

#[derive(Clone)]
pub(crate) enum FatDirReader<'a, 'b: 'a> {
    File(FatFile<'a, 'b>),
    Root(FatSlice<'a, 'b>),
}

impl <'a, 'b> Read for FatDirReader<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self {
            &mut FatDirReader::File(ref mut file) => file.read(buf),
            &mut FatDirReader::Root(ref mut raw) => raw.read(buf),
        }
    }
}

impl <'a, 'b> Seek for FatDirReader<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        match self {
            &mut FatDirReader::File(ref mut file) => file.seek(pos),
            &mut FatDirReader::Root(ref mut raw) => raw.seek(pos),
        }
    }
}

bitflags! {
    #[derive(Default)]
    pub struct FatFileAttributes: u8 {
        const READ_ONLY  = 0x01;
        const HIDDEN     = 0x02;
        const SYSTEM     = 0x04;
        const VOLUME_ID  = 0x08;
        const DIRECTORY  = 0x10;
        const ARCHIVE    = 0x20;
        const LFN        = Self::READ_ONLY.bits | Self::HIDDEN.bits
                         | Self::SYSTEM.bits | Self::VOLUME_ID.bits;
    }
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct FatDirFileEntryData {
    name: [u8; 11],
    attrs: FatFileAttributes,
    reserved_0: u8,
    create_time_0: u8,
    create_time_1: u16,
    create_date: u16,
    access_date: u16,
    first_cluster_hi: u16,
    modify_time: u16,
    modify_date: u16,
    first_cluster_lo: u16,
    size: u32,
}

#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
struct FatDirLfnEntryData {
    order: u8,
    name_0: [u16; 5],
    attrs: FatFileAttributes,
    entry_type: u8,
    checksum: u8,
    name_1: [u16; 6],
    reserved_0: u16,
    name_2: [u16; 2],
}

#[derive(Clone, Debug)]
enum FatDirEntryData {
    File(FatDirFileEntryData),
    Lfn(FatDirLfnEntryData),
}

#[derive(Clone)]
pub struct FatDirEntry<'a, 'b: 'a> {
    data: FatDirFileEntryData,
    lfn: Vec<u16>,
    fs: FatFileSystemRef<'a, 'b>,
}

pub struct DosDate {
    pub year: u16,
    pub month: u16,
    pub day: u16,
}

pub struct DosTime {
    pub hour: u16,
    pub min: u16,
    pub sec: u16,
}

pub struct DosDateTime {
    pub date: DosDate,
    pub time: DosTime,
}

impl DosDate {
    pub(crate) fn from_word(dos_date: u16) -> Self {
        let (year, month, day) = ((dos_date >> 9) + 1980, (dos_date >> 5) & 0xF, dos_date & 0x1F);
        DosDate { year, month, day }
    }
}

impl DosTime {
    pub(crate) fn from_word(dos_time: u16) -> Self {
        let (hour, min, sec) = (dos_time >> 11, (dos_time >> 5) & 0x3F, (dos_time & 0x1F) * 2);
        DosTime { hour, min, sec }
    }
}

impl DosDateTime {
    pub(crate) fn from_words(dos_date: u16, dos_time: u16) -> Self {
        DosDateTime {
            date: DosDate::from_word(dos_date),
            time: DosTime::from_word(dos_time),
        }
    }
}

#[cfg(feature = "chrono")]
impl From<DosDate> for Date<Local> {
    fn from(date: DosDate) -> Self {
        Local.ymd(date.year as i32, date.month as u32, date.day as u32)
    }
}

#[cfg(feature = "chrono")]
impl From<DosDateTime> for DateTime<Local> {
    fn from(date_time: DosDateTime) -> Self {
        Date::<Local>::from(date_time.date)
            .and_hms(date_time.time.hour as u32, date_time.time.min as u32, date_time.time.sec as u32)
    }
}

impl <'a, 'b> FatDirEntry<'a, 'b> {
    pub fn short_file_name(&self) -> String {
        let name_str = String::from_utf8_lossy(&self.data.name[0..8]);
        let ext_str = String::from_utf8_lossy(&self.data.name[8..11]);
        let name_trimmed = name_str.trim_right();
        let ext_trimmed = ext_str.trim_right();
        if ext_trimmed.is_empty() {
            name_trimmed.to_string()
        } else {
            format!("{}.{}", name_trimmed, ext_trimmed)
        }
    }

    pub fn file_name(&self) -> String {
        if self.lfn.len() > 0 {
            String::from_utf16_lossy(&self.lfn)
        } else {
            self.short_file_name()
        }
    }

    pub fn attributes(&self) -> FatFileAttributes {
        self.data.attrs
    }

    pub fn is_dir(&self) -> bool {
        self.data.attrs.contains(FatFileAttributes::DIRECTORY)
    }

    pub fn is_file(&self) -> bool {
        !self.is_dir()
    }

    pub(crate) fn first_cluster(&self) -> u32 {
        ((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32
    }

    pub fn to_file(&self) -> FatFile<'a, 'b> {
        if self.is_dir() {
            panic!("This is a directory");
        }
        FatFile::new(self.first_cluster(), Some(self.data.size), self.fs)
    }

    pub fn to_dir(&self) -> FatDir<'a, 'b> {
        if !self.is_dir() {
            panic!("This is a file");
        }
        let file = FatFile::new(self.first_cluster(), None, self.fs);
        FatDir::new(FatDirReader::File(file), self.fs)
    }

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

    pub fn created(&self) -> DosDateTime {
        DosDateTime::from_words(self.data.create_date, self.data.create_time_1)
    }

    pub fn accessed(&self) -> DosDate {
        DosDate::from_word(self.data.access_date)
    }

    pub fn modified(&self) -> DosDateTime {
        DosDateTime::from_words(self.data.modify_date, self.data.modify_time)
    }
}

impl <'a, 'b> fmt::Debug for FatDirEntry<'a, 'b> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.data.fmt(f)
    }
}

#[derive(Clone)]
pub struct FatDir<'a, 'b: 'a> {
    rdr: FatDirReader<'a, 'b>,
    fs: FatFileSystemRef<'a, 'b>,
}

impl <'a, 'b> FatDir<'a, 'b> {

    pub(crate) fn new(rdr: FatDirReader<'a, 'b>, fs: FatFileSystemRef<'a, 'b>) -> FatDir<'a, 'b> {
        FatDir { rdr, fs }
    }

    pub fn iter(&self) -> FatDirIter<'a, 'b> {
        FatDirIter {
            rdr: self.rdr.clone(),
            fs: self.fs.clone(),
            err: false,
        }
    }

    fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) {
        let mut path_split = path.trim_matches('/').splitn(2, "/");
        let comp = path_split.next().unwrap();
        let rest_opt = path_split.next();
        (comp, rest_opt)
    }

    fn find_entry(&mut self, name: &str) -> io::Result<FatDirEntry<'a, 'b>> {
        for r in self.iter() {
            let e = r?;
            if e.file_name().eq_ignore_ascii_case(name) {
                return Ok(e);
            }
        }
        Err(io::Error::new(ErrorKind::NotFound, "file not found"))
    }

    pub fn open_dir(&mut self, path: &str) -> io::Result<FatDir<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_dir(rest),
            None => Ok(e.to_dir())
        }
    }

    pub fn open_file(&mut self, path: &str) -> io::Result<FatFile<'a, 'b>> {
        let (name, rest_opt) = Self::split_path(path);
        let e = self.find_entry(name)?;
        match rest_opt {
            Some(rest) => e.to_dir().open_file(rest),
            None => Ok(e.to_file())
        }
    }
}

#[derive(Clone)]
pub struct FatDirIter<'a, 'b: 'a> {
    rdr: FatDirReader<'a, 'b>,
    fs: FatFileSystemRef<'a, 'b>,
    err: bool,
}

impl <'a, 'b> FatDirIter<'a, 'b> {
    fn read_dir_entry_data(&mut self) -> io::Result<FatDirEntryData> {
        let mut name = [0; 11];
        self.rdr.read(&mut name)?;
        let attrs = FatFileAttributes::from_bits(self.rdr.read_u8()?).expect("invalid attributes");
        if attrs == FatFileAttributes::LFN {
            let mut data = FatDirLfnEntryData {
                attrs, ..Default::default()
            };
            let mut cur = Cursor::new(&name);
            data.order = cur.read_u8()?;
            cur.read_u16_into::<LittleEndian>(&mut data.name_0)?;
            data.entry_type = self.rdr.read_u8()?;
            data.checksum = self.rdr.read_u8()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?;
            data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?;
            self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?;
            Ok(FatDirEntryData::Lfn(data))
        } else {
            let data = FatDirFileEntryData {
                name,
                attrs,
                reserved_0:       self.rdr.read_u8()?,
                create_time_0:    self.rdr.read_u8()?,
                create_time_1:    self.rdr.read_u16::<LittleEndian>()?,
                create_date:      self.rdr.read_u16::<LittleEndian>()?,
                access_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_hi: self.rdr.read_u16::<LittleEndian>()?,
                modify_time:      self.rdr.read_u16::<LittleEndian>()?,
                modify_date:      self.rdr.read_u16::<LittleEndian>()?,
                first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
                size:             self.rdr.read_u32::<LittleEndian>()?,
            };
            Ok(FatDirEntryData::File(data))
        }
    }
}

impl <'a, 'b> Iterator for FatDirIter<'a, 'b> {
    type Item = io::Result<FatDirEntry<'a, 'b>>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.err {
            return None;
        }
        let mut lfn_buf = Vec::<u16>::new();
        loop {
            let res = self.read_dir_entry_data();
            let data = match res {
                Ok(data) => data,
                Err(err) => {
                    self.err = true;
                    return Some(Err(err));
                },
            };
            match data {
                FatDirEntryData::File(data) => {
                    // Check if this is end of dif
                    if data.name[0] == 0 {
                        return None;
                    }
                    // Check if this is deleted or volume ID entry
                    if data.name[0] == 0xE5 || data.attrs.contains(FatFileAttributes::VOLUME_ID) {
                        lfn_buf.clear();
                        continue;
                    }
                    // Truncate 0 and 0xFFFF characters from LFN buffer
                    let mut lfn_len = lfn_buf.len();
                    loop {
                        if lfn_len == 0 {
                            break;
                        }
                        match lfn_buf[lfn_len-1] {
                            0xFFFF | 0 => lfn_len -= 1,
                            _ => break,
                        }
                    }
                    lfn_buf.truncate(lfn_len);
                    return Some(Ok(FatDirEntry {
                        data,
                        lfn: lfn_buf,
                        fs: self.fs,
                    }));
                },
                FatDirEntryData::Lfn(data) => {
                    // Check if this is deleted entry
                    if data.order == 0xE5 {
                        lfn_buf.clear();
                        continue;
                    }
                    const LFN_PART_LEN: usize = 13;
                    let index = (data.order & 0x1F) - 1;
                    let pos = LFN_PART_LEN * index as usize;
                    // resize LFN buffer to have enough space for entire name
                    if lfn_buf.len() < pos + LFN_PART_LEN {
                       lfn_buf.resize(pos + LFN_PART_LEN, 0);
                    }
                    // copy name parts into LFN buffer
                    lfn_buf[pos+0..pos+5].clone_from_slice(&data.name_0);
                    lfn_buf[pos+5..pos+11].clone_from_slice(&data.name_1);
                    lfn_buf[pos+11..pos+13].clone_from_slice(&data.name_2);
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Concurrent_computing
extern crate rand;

use std::io::timer::sleep;
use rand::random;

fn main() {
    let strings = ~[~"Enjoy", ~"Rosetta", ~"Code"];

    for s in strings.move_iter(){
        spawn(proc() {
            sleep(random::<u8>() as u64);
            println!("{:s}", s);
        });
    }
}
<commit_msg>Commented concurrent computing<commit_after>// Implements http://rosettacode.org/wiki/Concurrent_computing
extern crate rand;

use std::io::timer::sleep;
use rand::random;

fn main() {
    let strings = ~[~"Enjoy", ~"Rosetta", ~"Code"];

    for s in strings.move_iter(){
        spawn(proc() {
            // We use a random u8 (so an integer from 0 to 255)
            sleep(random::<u8>() as u64);
            println!("{}", s);
        });
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements traversal over the DOM tree. The traversal starts in sequential
//! mode, and optionally parallelizes as it discovers work.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{SendNode, TElement, TNode};
use parallel;
use parallel::{DispatchMode, WORK_UNIT_MAX};
use rayon;
use scoped_tls::ScopedTLS;
use std::borrow::Borrow;
use std::collections::VecDeque;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// Do a DOM traversal for top-down and (optionally) bottom-up processing,
/// generic over `D`.
///
/// We use an adaptive traversal strategy. We start out with simple sequential
/// processing, until we arrive at a wide enough level in the DOM that the
/// parallel traversal would parallelize it. If a thread pool is provided, we
/// then transfer control over to the parallel traversal.
pub fn traverse_dom<E, D>(
    traversal: &D,
    root: E,
    token: PreTraverseToken,
    pool: Option<&rayon::ThreadPool>
)
where
    E: TElement,
    D: DomTraversal<E>,
{
    debug_assert!(token.should_traverse());

    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Declare the main-thread context, as well as the worker-thread contexts,
    // which we may or may not instantiate. It's important to declare the worker-
    // thread contexts first, so that they get dropped second. This matters because:
    //   * ThreadLocalContexts borrow AtomicRefCells in TLS.
    //   * Dropping a ThreadLocalContext can run SequentialTasks.
    //   * Sequential tasks may call into functions like
    //     Servo_StyleSet_GetBaseComputedValuesForElement, which instantiate a
    //     ThreadLocalStyleContext on the main thread. If the main thread
    //     ThreadLocalStyleContext has not released its TLS borrow by that point,
    //     we'll panic on double-borrow.
    let mut maybe_tls: Option<ScopedTLS<ThreadLocalStyleContext<E>>> = None;
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    let mut discovered =
        VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
    let mut depth = root.depth();
    let mut nodes_remaining_at_current_depth = 1;
    discovered.push_back(unsafe { SendNode::new(root.as_node()) });
    while let Some(node) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
            children_to_process += 1;
            discovered.push_back(unsafe { SendNode::new(n) });
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             *node, children_to_process);

        nodes_remaining_at_current_depth -= 1;
        if nodes_remaining_at_current_depth == 0 {
            depth += 1;
            // If there is enough work to parallelize over, and the caller allows
            // parallelism, switch to the parallel driver. We do this only when
            // moving to the next level in the dom so that we can pass the same
            // depth for all the children.
            if pool.is_some() && discovered.len() > WORK_UNIT_MAX {
                let pool = pool.unwrap();
                maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool));
                let root_opaque = root.as_node().opaque();
                let drain = discovered.drain(..);
                pool.install(|| {
                    rayon::scope(|scope| {
                        parallel::traverse_nodes(
                            drain,
                            DispatchMode::TailCall,
                            /* recursion_ok = */ true,
                            root_opaque,
                            PerLevelTraversalData { current_dom_depth: depth },
                            scope,
                            pool,
                            traversal,
                            maybe_tls.as_ref().unwrap()
                        );
                    });
                });
                break;
            }
            nodes_remaining_at_current_depth = discovered.len();
        }
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        let mut aggregate =
            mem::replace(&mut context.thread_local.statistics, Default::default());
        let parallel = maybe_tls.is_some();
        if let Some(tls) = maybe_tls {
            let slots = unsafe { tls.unsafe_get() };
            aggregate = slots.iter().fold(aggregate, |acc, t| {
                match *t.borrow() {
                    None => acc,
                    Some(ref cx) => &cx.borrow().statistics + &acc,
                }
            });
        }
        aggregate.finish(traversal, parallel, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}
<commit_msg>Auto merge of #18366 - emilio:fix-statistics-crash, r=bholley<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements traversal over the DOM tree. The traversal starts in sequential
//! mode, and optionally parallelizes as it discovers work.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{SendNode, TElement, TNode};
use parallel;
use parallel::{DispatchMode, WORK_UNIT_MAX};
use rayon;
use scoped_tls::ScopedTLS;
use std::collections::VecDeque;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// Do a DOM traversal for top-down and (optionally) bottom-up processing,
/// generic over `D`.
///
/// We use an adaptive traversal strategy. We start out with simple sequential
/// processing, until we arrive at a wide enough level in the DOM that the
/// parallel traversal would parallelize it. If a thread pool is provided, we
/// then transfer control over to the parallel traversal.
pub fn traverse_dom<E, D>(
    traversal: &D,
    root: E,
    token: PreTraverseToken,
    pool: Option<&rayon::ThreadPool>
)
where
    E: TElement,
    D: DomTraversal<E>,
{
    debug_assert!(token.should_traverse());

    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Declare the main-thread context, as well as the worker-thread contexts,
    // which we may or may not instantiate. It's important to declare the worker-
    // thread contexts first, so that they get dropped second. This matters because:
    //   * ThreadLocalContexts borrow AtomicRefCells in TLS.
    //   * Dropping a ThreadLocalContext can run SequentialTasks.
    //   * Sequential tasks may call into functions like
    //     Servo_StyleSet_GetBaseComputedValuesForElement, which instantiate a
    //     ThreadLocalStyleContext on the main thread. If the main thread
    //     ThreadLocalStyleContext has not released its TLS borrow by that point,
    //     we'll panic on double-borrow.
    let mut maybe_tls: Option<ScopedTLS<ThreadLocalStyleContext<E>>> = None;
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    let mut discovered =
        VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
    let mut depth = root.depth();
    let mut nodes_remaining_at_current_depth = 1;
    discovered.push_back(unsafe { SendNode::new(root.as_node()) });
    while let Some(node) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
            children_to_process += 1;
            discovered.push_back(unsafe { SendNode::new(n) });
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             *node, children_to_process);

        nodes_remaining_at_current_depth -= 1;
        if nodes_remaining_at_current_depth == 0 {
            depth += 1;
            // If there is enough work to parallelize over, and the caller allows
            // parallelism, switch to the parallel driver. We do this only when
            // moving to the next level in the dom so that we can pass the same
            // depth for all the children.
            if pool.is_some() && discovered.len() > WORK_UNIT_MAX {
                let pool = pool.unwrap();
                maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool));
                let root_opaque = root.as_node().opaque();
                let drain = discovered.drain(..);
                pool.install(|| {
                    rayon::scope(|scope| {
                        parallel::traverse_nodes(
                            drain,
                            DispatchMode::TailCall,
                            /* recursion_ok = */ true,
                            root_opaque,
                            PerLevelTraversalData { current_dom_depth: depth },
                            scope,
                            pool,
                            traversal,
                            maybe_tls.as_ref().unwrap()
                        );
                    });
                });
                break;
            }
            nodes_remaining_at_current_depth = discovered.len();
        }
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        let mut aggregate =
            mem::replace(&mut context.thread_local.statistics, Default::default());
        let parallel = maybe_tls.is_some();
        if let Some(ref mut tls) = maybe_tls {
            let slots = unsafe { tls.unsafe_get() };
            aggregate = slots.iter().fold(aggregate, |acc, t| {
                match *t.borrow() {
                    None => acc,
                    Some(ref cx) => &cx.statistics + &acc,
                }
            });
        }
        aggregate.finish(traversal, parallel, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Marker types for formats.
//!
//! This module defines the types and traits used to mark a `Tendril`
//! with the format of data it contains.
//!
//! `Tendril` operations may become memory-unsafe if data invalid for
//! the format sneaks in. For that reason, these traits require
//! `unsafe impl`.

use std::{char, str, mem};
use std::slice::bytes;
use std::marker::{MarkerTrait, PhantomFn};
use std::default::Default;

use futf::{self, Codepoint, Meaning};

/// Implementation details.
///
/// You don't need these unless you are implementing
/// a new format.
pub mod imp {
    use std::default::Default;

    /// Describes how to fix up encodings when concatenating.
    ///
    /// We can drop characters on either side of the splice,
    /// and insert up to 4 bytes in the middle.
    pub struct Fixup {
        pub drop_left: u32,
        pub drop_right: u32,
        pub insert_len: u32,
        pub insert_bytes: [u8; 4],
    }

    impl Default for Fixup {
        #[inline(always)]
        fn default() -> Fixup {
            Fixup {
                drop_left: 0,
                drop_right: 0,
                insert_len: 0,
                insert_bytes: [0; 4],
            }
        }
    }
}

/// Trait for format marker types.
///
/// The type implementing this trait is usually not instantiated.
/// It's used with a phantom type parameter of `Tendril`.
pub unsafe trait Format: MarkerTrait {
    /// Check whether the buffer is valid for this format.
    fn validate(buf: &[u8]) -> bool;

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a prefix of a valid buffer.
    #[inline(always)]
    fn validate_prefix(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a suffix of a valid buffer.
    #[inline(always)]
    fn validate_suffix(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a contiguous subsequence
    /// of a valid buffer, but not necessarily a prefix or
    /// a suffix.
    #[inline(always)]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Compute any fixup needed when concatenating buffers.
    ///
    /// The default is to do nothing.
    ///
    /// The function is `unsafe` because it may assume the input
    /// buffers are already valid for the format. Also, no
    /// bounds-checking is performed on the return value!
    #[inline(always)]
    unsafe fn fixup(_lhs: &[u8], _rhs: &[u8]) -> imp::Fixup {
        Default::default()
    }
}

/// Indicates that one format is a subset of another.
///
/// The subset format can be converted to the superset format
/// for free.
pub unsafe trait SubsetOf<Super>: Format + PhantomFn<Super>
    where Super: Format,
{
    /// Validate the *other* direction of conversion; check if
    /// this buffer from the superset format conforms to the
    /// subset format.
    ///
    /// The default calls `Self::validate`, but some conversions
    /// may implement a check which is cheaper than validating
    /// from scratch.
    fn revalidate_subset(x: &[u8]) -> bool {
        Self::validate(x)
    }
}

/// Indicates a format which corresponds to a Rust slice type,
/// representing exactly the same invariants.
pub unsafe trait SliceFormat: Format {
    type Slice: ?Sized + Slice<Format = Self>;
}

/// Indicates a Rust slice type that has a corresponding format.
pub unsafe trait Slice {
    type Format: SliceFormat<Slice = Self>;

    /// Access the raw bytes of the slice.
    fn as_bytes(&self) -> &[u8];

    /// Convert a byte slice to this kind of slice.
    ///
    /// You may assume the buffer is *already validated*
    /// for `Format`.
    unsafe fn from_bytes(x: &[u8]) -> &Self;
}

/// Marker type for uninterpreted bytes.
///
/// Validation will never fail for this format.
#[derive(Copy, Clone, Default, Debug)]
pub struct Bytes;

unsafe impl Format for Bytes {
    #[inline(always)]
    fn validate(_: &[u8]) -> bool {
        true
    }
}

unsafe impl SliceFormat for Bytes {
    type Slice = [u8];
}

unsafe impl Slice for [u8] {
    type Format = Bytes;

    #[inline(always)]
    fn as_bytes(&self) -> &[u8] {
        self
    }

    #[inline(always)]
    unsafe fn from_bytes(x: &[u8]) -> &[u8] {
        x
    }
}

/// Marker type for ASCII text.
#[derive(Copy, Clone, Default, Debug)]
pub struct ASCII;

unsafe impl Format for ASCII {
    #[inline(always)]
    fn validate(buf: &[u8]) -> bool {
        buf.iter().all(|&n| n <= 127)
    }

    #[inline(always)]
    fn validate_prefix(_: &[u8]) -> bool {
        true
    }

    #[inline(always)]
    fn validate_suffix(_: &[u8]) -> bool {
        true
    }

    #[inline(always)]
    fn validate_subseq(_: &[u8]) -> bool {
        true
    }
}

unsafe impl SubsetOf<UTF8> for ASCII { }

/// Marker type for UTF-8 text.
#[derive(Copy, Clone, Default, Debug)]
pub struct UTF8;

unsafe impl Format for UTF8 {
    #[inline]
    fn validate(buf: &[u8]) -> bool {
        str::from_utf8(buf).is_ok()
    }

    #[inline]
    fn validate_prefix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, buf.len() - 1) {
            Some(Codepoint { meaning: Meaning::Whole(_), .. }) => true,
            _ => false,
        }
    }

    #[inline]
    fn validate_suffix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, 0) {
            Some(Codepoint { meaning: Meaning::Whole(_), .. }) => true,
            _ => false,
        }
    }

    #[inline]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate_prefix(buf)
            && <Self as Format>::validate_suffix(buf)
    }
}

unsafe impl SubsetOf<WTF8> for UTF8 { }

unsafe impl SliceFormat for UTF8 {
    type Slice = str;
}

unsafe impl Slice for str {
    type Format = UTF8;

    #[inline(always)]
    fn as_bytes(&self) -> &[u8] {
        self.as_bytes()
    }

    #[inline(always)]
    unsafe fn from_bytes(x: &[u8]) -> &str {
        str::from_utf8_unchecked(x)
    }
}

/// Marker type for WTF-8 text.
///
/// See the [WTF-8 spec](http://simonsapin.github.io/wtf-8/).
#[derive(Copy, Clone, Default, Debug)]
pub struct WTF8;

#[inline(always)]
fn wtf8_meaningful(m: Meaning) -> bool {
    match m {
        Meaning::Whole(_) | Meaning::LeadSurrogate(_)
            | Meaning::TrailSurrogate(_) => true,
        _ => false,
    }
}

unsafe impl Format for WTF8 {
    #[inline]
    fn validate(buf: &[u8]) -> bool {
        let mut i = 0;
        let mut prev_lead = false;
        while i < buf.len() {
            let codept = unwrap_or_return!(futf::classify(buf, i), false);
            if !wtf8_meaningful(codept.meaning) {
                return false;
            }
            i += codept.bytes.len();
            prev_lead = match codept.meaning {
                Meaning::TrailSurrogate(_) if prev_lead => return false,
                Meaning::LeadSurrogate(_) => true,
                _ => false,
            };
        }

        true
    }

    #[inline]
    fn validate_prefix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, buf.len() - 1) {
            Some(c) => wtf8_meaningful(c.meaning),
            _ => false,
        }
    }

    #[inline]
    fn validate_suffix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, 0) {
            Some(c) => wtf8_meaningful(c.meaning),
            _ => false,
        }
    }

    #[inline]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate_prefix(buf)
            && <Self as Format>::validate_suffix(buf)
    }

    #[inline]
    unsafe fn fixup(lhs: &[u8], rhs: &[u8]) -> imp::Fixup {
        if lhs.len() >= 3 && rhs.len() >= 3 {
            if let (Some(Codepoint { meaning: Meaning::LeadSurrogate(hi), .. }),
                    Some(Codepoint { meaning: Meaning::TrailSurrogate(lo), .. }))
                = (futf::classify(lhs, lhs.len() - 1), futf::classify(rhs, 0))
            {
                let n = 0x10000 + ((hi as u32) << 10) + (lo as u32);
                // FIXME: don't allocate for the char
                let s = format!("{}", char::from_u32(n).expect("WTF8: internal error"));
                debug_assert!(s.len() <= 4);

                let mut fixup = imp::Fixup {
                    drop_left: 3,
                    drop_right: 3,
                    insert_len: s.len() as u32,
                    insert_bytes: mem::uninitialized(),
                };
                bytes::copy_memory(&mut fixup.insert_bytes, s.as_bytes());
                return fixup;
            }
        }

        Default::default()
    }
}
<commit_msg>Fix confusing method definition<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Marker types for formats.
//!
//! This module defines the types and traits used to mark a `Tendril`
//! with the format of data it contains.
//!
//! `Tendril` operations may become memory-unsafe if data invalid for
//! the format sneaks in. For that reason, these traits require
//! `unsafe impl`.

use std::{char, str, mem};
use std::slice::bytes;
use std::marker::{MarkerTrait, PhantomFn};
use std::default::Default;

use futf::{self, Codepoint, Meaning};

/// Implementation details.
///
/// You don't need these unless you are implementing
/// a new format.
pub mod imp {
    use std::default::Default;

    /// Describes how to fix up encodings when concatenating.
    ///
    /// We can drop characters on either side of the splice,
    /// and insert up to 4 bytes in the middle.
    pub struct Fixup {
        pub drop_left: u32,
        pub drop_right: u32,
        pub insert_len: u32,
        pub insert_bytes: [u8; 4],
    }

    impl Default for Fixup {
        #[inline(always)]
        fn default() -> Fixup {
            Fixup {
                drop_left: 0,
                drop_right: 0,
                insert_len: 0,
                insert_bytes: [0; 4],
            }
        }
    }
}

/// Trait for format marker types.
///
/// The type implementing this trait is usually not instantiated.
/// It's used with a phantom type parameter of `Tendril`.
pub unsafe trait Format: MarkerTrait {
    /// Check whether the buffer is valid for this format.
    fn validate(buf: &[u8]) -> bool;

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a prefix of a valid buffer.
    #[inline(always)]
    fn validate_prefix(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a suffix of a valid buffer.
    #[inline(always)]
    fn validate_suffix(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Check whether the buffer is valid for this format.
    ///
    /// You may assume the buffer is a contiguous subsequence
    /// of a valid buffer, but not necessarily a prefix or
    /// a suffix.
    #[inline(always)]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate(buf)
    }

    /// Compute any fixup needed when concatenating buffers.
    ///
    /// The default is to do nothing.
    ///
    /// The function is `unsafe` because it may assume the input
    /// buffers are already valid for the format. Also, no
    /// bounds-checking is performed on the return value!
    #[inline(always)]
    unsafe fn fixup(_lhs: &[u8], _rhs: &[u8]) -> imp::Fixup {
        Default::default()
    }
}

/// Indicates that one format is a subset of another.
///
/// The subset format can be converted to the superset format
/// for free.
pub unsafe trait SubsetOf<Super>: Format + PhantomFn<Super>
    where Super: Format,
{
    /// Validate the *other* direction of conversion; check if
    /// this buffer from the superset format conforms to the
    /// subset format.
    ///
    /// The default calls `Self::validate`, but some conversions
    /// may implement a check which is cheaper than validating
    /// from scratch.
    fn revalidate_subset(x: &[u8]) -> bool {
        Self::validate(x)
    }
}

/// Indicates a format which corresponds to a Rust slice type,
/// representing exactly the same invariants.
pub unsafe trait SliceFormat: Format {
    type Slice: ?Sized + Slice<Format = Self>;
}

/// Indicates a Rust slice type that has a corresponding format.
pub unsafe trait Slice {
    type Format: SliceFormat<Slice = Self>;

    /// Access the raw bytes of the slice.
    fn as_bytes(&self) -> &[u8];

    /// Convert a byte slice to this kind of slice.
    ///
    /// You may assume the buffer is *already validated*
    /// for `Format`.
    unsafe fn from_bytes(x: &[u8]) -> &Self;
}

/// Marker type for uninterpreted bytes.
///
/// Validation will never fail for this format.
#[derive(Copy, Clone, Default, Debug)]
pub struct Bytes;

unsafe impl Format for Bytes {
    #[inline(always)]
    fn validate(_: &[u8]) -> bool {
        true
    }
}

unsafe impl SliceFormat for Bytes {
    type Slice = [u8];
}

unsafe impl Slice for [u8] {
    type Format = Bytes;

    #[inline(always)]
    fn as_bytes(&self) -> &[u8] {
        self
    }

    #[inline(always)]
    unsafe fn from_bytes(x: &[u8]) -> &[u8] {
        x
    }
}

/// Marker type for ASCII text.
#[derive(Copy, Clone, Default, Debug)]
pub struct ASCII;

unsafe impl Format for ASCII {
    #[inline(always)]
    fn validate(buf: &[u8]) -> bool {
        buf.iter().all(|&n| n <= 127)
    }

    #[inline(always)]
    fn validate_prefix(_: &[u8]) -> bool {
        true
    }

    #[inline(always)]
    fn validate_suffix(_: &[u8]) -> bool {
        true
    }

    #[inline(always)]
    fn validate_subseq(_: &[u8]) -> bool {
        true
    }
}

unsafe impl SubsetOf<UTF8> for ASCII { }

/// Marker type for UTF-8 text.
#[derive(Copy, Clone, Default, Debug)]
pub struct UTF8;

unsafe impl Format for UTF8 {
    #[inline]
    fn validate(buf: &[u8]) -> bool {
        str::from_utf8(buf).is_ok()
    }

    #[inline]
    fn validate_prefix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, buf.len() - 1) {
            Some(Codepoint { meaning: Meaning::Whole(_), .. }) => true,
            _ => false,
        }
    }

    #[inline]
    fn validate_suffix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, 0) {
            Some(Codepoint { meaning: Meaning::Whole(_), .. }) => true,
            _ => false,
        }
    }

    #[inline]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate_prefix(buf)
            && <Self as Format>::validate_suffix(buf)
    }
}

unsafe impl SubsetOf<WTF8> for UTF8 { }

unsafe impl SliceFormat for UTF8 {
    type Slice = str;
}

unsafe impl Slice for str {
    type Format = UTF8;

    #[inline(always)]
    fn as_bytes(&self) -> &[u8] {
        str::as_bytes(self)
    }

    #[inline(always)]
    unsafe fn from_bytes(x: &[u8]) -> &str {
        str::from_utf8_unchecked(x)
    }
}

/// Marker type for WTF-8 text.
///
/// See the [WTF-8 spec](http://simonsapin.github.io/wtf-8/).
#[derive(Copy, Clone, Default, Debug)]
pub struct WTF8;

#[inline(always)]
fn wtf8_meaningful(m: Meaning) -> bool {
    match m {
        Meaning::Whole(_) | Meaning::LeadSurrogate(_)
            | Meaning::TrailSurrogate(_) => true,
        _ => false,
    }
}

unsafe impl Format for WTF8 {
    #[inline]
    fn validate(buf: &[u8]) -> bool {
        let mut i = 0;
        let mut prev_lead = false;
        while i < buf.len() {
            let codept = unwrap_or_return!(futf::classify(buf, i), false);
            if !wtf8_meaningful(codept.meaning) {
                return false;
            }
            i += codept.bytes.len();
            prev_lead = match codept.meaning {
                Meaning::TrailSurrogate(_) if prev_lead => return false,
                Meaning::LeadSurrogate(_) => true,
                _ => false,
            };
        }

        true
    }

    #[inline]
    fn validate_prefix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, buf.len() - 1) {
            Some(c) => wtf8_meaningful(c.meaning),
            _ => false,
        }
    }

    #[inline]
    fn validate_suffix(buf: &[u8]) -> bool {
        if buf.len() == 0 {
            return true;
        }
        match futf::classify(buf, 0) {
            Some(c) => wtf8_meaningful(c.meaning),
            _ => false,
        }
    }

    #[inline]
    fn validate_subseq(buf: &[u8]) -> bool {
        <Self as Format>::validate_prefix(buf)
            && <Self as Format>::validate_suffix(buf)
    }

    #[inline]
    unsafe fn fixup(lhs: &[u8], rhs: &[u8]) -> imp::Fixup {
        if lhs.len() >= 3 && rhs.len() >= 3 {
            if let (Some(Codepoint { meaning: Meaning::LeadSurrogate(hi), .. }),
                    Some(Codepoint { meaning: Meaning::TrailSurrogate(lo), .. }))
                = (futf::classify(lhs, lhs.len() - 1), futf::classify(rhs, 0))
            {
                let n = 0x10000 + ((hi as u32) << 10) + (lo as u32);
                // FIXME: don't allocate for the char
                let s = format!("{}", char::from_u32(n).expect("WTF8: internal error"));
                debug_assert!(s.len() <= 4);

                let mut fixup = imp::Fixup {
                    drop_left: 3,
                    drop_right: 3,
                    insert_len: s.len() as u32,
                    insert_bytes: mem::uninitialized(),
                };
                bytes::copy_memory(&mut fixup.insert_bytes, s.as_bytes());
                return fixup;
            }
        }

        Default::default()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="font" sub_properties="font-style font-variant font-weight font-stretch
                                                font-size line-height font-family"
                    spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
    use properties::longhands::{font_style, font_variant, font_weight, font_stretch};
    use properties::longhands::{font_size, line_height, font_family};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut nb_normals = 0;
        let mut style = None;
        let mut variant = None;
        let mut weight = None;
        let mut stretch = None;
        let size;
        loop {
            // Special-case 'normal' because it is valid in each of
            // font-style, font-weight, font-variant and font-stretch.
            // Leaves the values to None, 'normal' is the initial value for each of them.
            if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
                nb_normals += 1;
                continue;
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| font_style::parse(context, input)) {
                    style = Some(value);
                    continue
                }
            }
            if weight.is_none() {
                if let Ok(value) = input.try(|input| font_weight::parse(context, input)) {
                    weight = Some(value);
                    continue
                }
            }
            if variant.is_none() {
                if let Ok(value) = input.try(|input| font_variant::parse(context, input)) {
                    variant = Some(value);
                    continue
                }
            }
            if stretch.is_none() {
                if let Ok(value) = input.try(|input| font_stretch::parse(context, input)) {
                    stretch = Some(value);
                    continue
                }
            }
            size = Some(try!(font_size::parse(context, input)));
            break
        }
        #[inline]
        fn count<T>(opt: &Option<T>) -> u8 {
            if opt.is_some() { 1 } else { 0 }
        }
        if size.is_none() || (count(&style) + count(&weight) + count(&variant) + count(&stretch) + nb_normals) > 4 {
            return Err(())
        }
        let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
            Some(try!(line_height::parse(context, input)))
        } else {
            None
        };
        let family = try!(input.parse_comma_separated(font_family::parse_one_family));
        Ok(Longhands {
            font_style: style,
            font_variant: variant,
            font_weight: weight,
            font_stretch: stretch,
            font_size: size,
            line_height: line_height,
            font_family: Some(font_family::SpecifiedValue(family))
        })
    }

    // This may be a bit off, unsure, possibly needs changes
    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let DeclaredValue::Value(ref style) = *self.font_style {
                try!(style.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref variant) = *self.font_variant {
                try!(variant.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref weight) = *self.font_weight {
                try!(weight.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref stretch) = *self.font_stretch {
                try!(stretch.to_css(dest));
                try!(write!(dest, " "));
            }

            try!(self.font_size.to_css(dest));
            if let DeclaredValue::Value(ref height) = *self.line_height {
                match *height {
                    line_height::SpecifiedValue::Normal => {},
                    _ => {
                        try!(write!(dest, "/"));
                        try!(height.to_css(dest));
                    }
                }
            }

            try!(write!(dest, " "));

            self.font_family.to_css(dest)
        }
    }
</%helpers:shorthand>
<commit_msg>Auto merge of #15305 - dbaron:reset-more-for-font, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="font" sub_properties="font-style font-variant font-weight font-stretch
                                                font-size line-height font-family
                                                ${'font-size-adjust' if product == 'gecko' else ''}
                                                ${'font-kerning' if product == 'gecko' else ''}
                                                ${'font-variant-caps' if product == 'gecko' else ''}
                                                ${'font-variant-position' if product == 'gecko' else ''}
                                                ${'font-language-override' if product == 'none' else ''}"
                    spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
    use properties::longhands::{font_style, font_variant, font_weight, font_stretch};
    use properties::longhands::{font_size, line_height, font_family};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut nb_normals = 0;
        let mut style = None;
        let mut variant = None;
        let mut weight = None;
        let mut stretch = None;
        let size;
        loop {
            // Special-case 'normal' because it is valid in each of
            // font-style, font-weight, font-variant and font-stretch.
            // Leaves the values to None, 'normal' is the initial value for each of them.
            if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
                nb_normals += 1;
                continue;
            }
            if style.is_none() {
                if let Ok(value) = input.try(|input| font_style::parse(context, input)) {
                    style = Some(value);
                    continue
                }
            }
            if weight.is_none() {
                if let Ok(value) = input.try(|input| font_weight::parse(context, input)) {
                    weight = Some(value);
                    continue
                }
            }
            if variant.is_none() {
                if let Ok(value) = input.try(|input| font_variant::parse(context, input)) {
                    variant = Some(value);
                    continue
                }
            }
            if stretch.is_none() {
                if let Ok(value) = input.try(|input| font_stretch::parse(context, input)) {
                    stretch = Some(value);
                    continue
                }
            }
            size = Some(try!(font_size::parse(context, input)));
            break
        }
        #[inline]
        fn count<T>(opt: &Option<T>) -> u8 {
            if opt.is_some() { 1 } else { 0 }
        }
        if size.is_none() || (count(&style) + count(&weight) + count(&variant) + count(&stretch) + nb_normals) > 4 {
            return Err(())
        }
        let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
            Some(try!(line_height::parse(context, input)))
        } else {
            None
        };
        let family = try!(input.parse_comma_separated(font_family::parse_one_family));
        Ok(Longhands {
            font_style: style,
            font_variant: variant,
            font_weight: weight,
            font_stretch: stretch,
            font_size: size,
            line_height: line_height,
            font_family: Some(font_family::SpecifiedValue(family)),
    % if product == "gecko":
            font_size_adjust: None,
            font_kerning: None,
            font_variant_caps: None,
            font_variant_position: None,
    % endif
    % if product == "none":
            font_language_override: None,
    % endif
        })
    }

    // This may be a bit off, unsure, possibly needs changes
    impl<'a> LonghandsToSerialize<'a>  {
        fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let DeclaredValue::Value(ref style) = *self.font_style {
                try!(style.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref variant) = *self.font_variant {
                try!(variant.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref weight) = *self.font_weight {
                try!(weight.to_css(dest));
                try!(write!(dest, " "));
            }

            if let DeclaredValue::Value(ref stretch) = *self.font_stretch {
                try!(stretch.to_css(dest));
                try!(write!(dest, " "));
            }

            try!(self.font_size.to_css(dest));
            if let DeclaredValue::Value(ref height) = *self.line_height {
                match *height {
                    line_height::SpecifiedValue::Normal => {},
                    _ => {
                        try!(write!(dest, "/"));
                        try!(height.to_css(dest));
                    }
                }
            }

            try!(write!(dest, " "));

            self.font_family.to_css(dest)
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>//! Provides the scene struct containing information needed to render a
//! volume from some camera position. Scenes are stored in JSON format, for example:
//!
//! ```json
//! {
//!     "volume": {
//!	    	"file": "csafe-heptane-302-volume.raw",
//!	    	"data_type": "u8",
//!	    	"dimensions": [302, 302, 302]
//!	    },
//!	    "transfer_function": "cool_warm",
//!	    "camera": {
//!		    "pos": [-0.5, 0.5, 1.5],
//!		    "target": [0.5, 0.5, 0.5],
//!		    "up": [0, 1, 0],
//!		    "fovy": 60,
//!	    },
//!	    "width": 512,
//!	    "height": 512,
//!	    "background": [0.1, 0.1, 0.1],
//!	    "n_samples": 4
//! }
//! ```
//!
//! The `transfer_function` element can be one of the default ones `jet`, `cool_warm` or
//! `gray_scale` or the name of a ParaView exported transfer function (any string ending in
//! .json). ParaView transfer function importing is still a TODO though.

use std::io::prelude::*;
use std::path::Path;
use std::fs::File;
use std::ffi::OsStr;

use serde_json::{self, Value};

use ddvol;
use camera::Camera;
use vec3::{Vec3f, Vec3i};
use vol::Volume;
use tfn::TransferFunction;
use raw;

pub type RenderParams = ddvol::RenderParams;

pub struct Scene {
    /// Image width
    pub width: usize,
    /// Image height
    pub height: usize,
    pub camera: Camera,
    pub volume: Volume,
    pub params: RenderParams,
}

impl Scene {
    pub fn load(file: &str) -> Scene {
        let mut f = match File::open(file) {
            Ok(f) => f,
            Err(e) => panic!("Failed to open scene file: {}", e),
        };
        let mut content = String::new();
        if let Err(e) = f.read_to_string(&mut content) {
            panic!("Failed to read scene file: {}", e);
        }
        let data: Value = match serde_json::from_str(&content[..]) {
            Ok(d) => d,
            Err(e) => panic!("JSON parsing error: {}", e),
        };
        assert!(data.is_object(), "Expected a root JSON object. See example scenes");
        let base_path = match Path::new(file).parent() {
            Some(p) => p,
            None => Path::new(file),
        };
        let img_width = data.find("width").expect("image width must be set")
            .as_u64().expect("image width must be an int") as usize;
        let img_height = data.find("height").expect("image height must be set")
            .as_u64().expect("image height must be an int") as usize;
        let mut volume = Scene::load_volume(data.find("volume").expect("A volume must be specified"), &base_path);
        let tfn = Scene::load_transfer_function(data.find("transfer_function")
                                                .expect("A transfer function must be specified"), &base_path);
        volume.set_transfer_function(tfn);

        let camera = Scene::load_camera(data.find("camera").expect("A camera must be specified"),
                                        img_width, img_height);
        let render_params = Scene::load_render_params(&data);
        Scene { width: img_width, height: img_height, camera: camera,
                volume: volume, params: render_params }
    }
    fn load_volume(e: &Value, base_path: &Path) -> Volume {
        let mut vol_file = Path::new(e.find("file").expect("A volume filename must be set")
                                 .as_string().expect("Volume filename must be a string")).to_owned();
        if !vol_file.is_absolute() {
            vol_file = base_path.join(vol_file);
        }
        assert_eq!(vol_file.extension(), Some(OsStr::new("raw")));
        println!("Loading volume {}", vol_file.display());
        let dimensions = Scene::load_vec3i(e.find("dimensions")
                                           .expect("Volume dims must be set for RAW volume"))
            .expect("Invalid dimensions specified");

        let dtype = e.find("data_type").expect("A data type must be specified for RAW volumes")
                     .as_string().expect("data type must be a string");
        if dtype == "u8" {
            raw::import::<u8>(vol_file.as_path(), dimensions)
        } else if dtype == "u16" {
            raw::import::<u16>(vol_file.as_path(), dimensions)
        } else if dtype == "f32" {
            raw::import::<f32>(vol_file.as_path(), dimensions)
        } else if dtype == "f64" {
            raw::import::<f64>(vol_file.as_path(), dimensions)
        } else {
            panic!("Unrecognized data type {}! Valid options are u8, u16, f32, f64", dtype);
        }
    }
    fn load_transfer_function(e: &Value, base_path: &Path) -> TransferFunction {
        let tfn_file = Path::new(e.as_string().expect("transfer_function filename/name must be a string"));
        // Load the ParaView transfer function file if it's one, otherwise
        // see if it's one of our defaults we can provide
        if tfn_file.extension() == Some(OsStr::new("json")) {
            let mut tfn_buf = tfn_file.to_owned();
            if !tfn_buf.is_absolute() {
                tfn_buf = base_path.join(tfn_buf);
            }
            panic!("TODO: ParaView transferfunction importing is not implemented");
        } else {
            let tfn_name = tfn_file.to_str().unwrap();
            if tfn_name == "grayscale" {
                TransferFunction::grayscale()
            } else if tfn_name == "jet" {
                TransferFunction::jet()
            } else if tfn_name == "cool_warm" {
                TransferFunction::cool_warm()
            } else {
                panic!("Scene error: {} is not a built in transfer function", tfn_name);
            }
        }
    }
    fn load_camera(e: &Value, width: usize, height: usize) -> Camera {
        let pos = Scene::load_vec3f(e.find("pos").expect("Camera view position must be set"))
            .expect("Invalid camera position");
        let target = Scene::load_vec3f(e.find("target").expect("Camera view target must be set"))
            .expect("Invalid camera target");
        let up = Scene::load_vec3f(e.find("up").expect("Camera up vector must be set"))
            .expect("Invalid camera up");
        let fovy = e.find("fovy").expect("Camera FOV Y must be set").as_f64()
            .expect("FOV Y must be a float") as f32;
        Camera::new(pos, target, up, fovy, width as u32, height as u32)
    }
    fn load_render_params(e: &Value) -> RenderParams {
        let background = Scene::load_vec3f(e.find("background").expect("Background color must be set"))
            .expect("Background color must be a vec3f");
        let n_samples = e.find("n_samples").expect("n_samples per pixel must be set")
            .as_i64().expect("n_samples must be an int") as i32;
        RenderParams { background: background, n_samples: n_samples }
    }
    fn load_vec3i(e: &Value) -> Option<Vec3i> {
        e.as_array().map(|x| {
            assert_eq!(x.len(), 3);
            Vec3i::new(x[0].as_i64().unwrap() as i32,
                       x[1].as_i64().unwrap() as i32,
                       x[2].as_i64().unwrap() as i32)
        })
    }
    fn load_vec3f(e: &Value) -> Option<Vec3f> {
        e.as_array().map(|x| {
            assert_eq!(x.len(), 3);
            Vec3f::new(x[0].as_f64().unwrap() as f32,
                       x[1].as_f64().unwrap() as f32,
                       x[2].as_f64().unwrap() as f32)
        })
    }
}

<commit_msg>Remove debug logging<commit_after>//! Provides the scene struct containing information needed to render a
//! volume from some camera position. Scenes are stored in JSON format, for example:
//!
//! ```json
//! {
//!     "volume": {
//!	    	"file": "csafe-heptane-302-volume.raw",
//!	    	"data_type": "u8",
//!	    	"dimensions": [302, 302, 302]
//!	    },
//!	    "transfer_function": "cool_warm",
//!	    "camera": {
//!		    "pos": [-0.5, 0.5, 1.5],
//!		    "target": [0.5, 0.5, 0.5],
//!		    "up": [0, 1, 0],
//!		    "fovy": 60,
//!	    },
//!	    "width": 512,
//!	    "height": 512,
//!	    "background": [0.1, 0.1, 0.1],
//!	    "n_samples": 4
//! }
//! ```
//!
//! The `transfer_function` element can be one of the default ones `jet`, `cool_warm` or
//! `gray_scale` or the name of a ParaView exported transfer function (any string ending in
//! .json). ParaView transfer function importing is still a TODO though.

use std::io::prelude::*;
use std::path::Path;
use std::fs::File;
use std::ffi::OsStr;

use serde_json::{self, Value};

use ddvol;
use camera::Camera;
use vec3::{Vec3f, Vec3i};
use vol::Volume;
use tfn::TransferFunction;
use raw;

pub type RenderParams = ddvol::RenderParams;

pub struct Scene {
    /// Image width
    pub width: usize,
    /// Image height
    pub height: usize,
    pub camera: Camera,
    pub volume: Volume,
    pub params: RenderParams,
}

impl Scene {
    pub fn load(file: &str) -> Scene {
        let mut f = match File::open(file) {
            Ok(f) => f,
            Err(e) => panic!("Failed to open scene file: {}", e),
        };
        let mut content = String::new();
        if let Err(e) = f.read_to_string(&mut content) {
            panic!("Failed to read scene file: {}", e);
        }
        let data: Value = match serde_json::from_str(&content[..]) {
            Ok(d) => d,
            Err(e) => panic!("JSON parsing error: {}", e),
        };
        assert!(data.is_object(), "Expected a root JSON object. See example scenes");
        let base_path = match Path::new(file).parent() {
            Some(p) => p,
            None => Path::new(file),
        };
        let img_width = data.find("width").expect("image width must be set")
            .as_u64().expect("image width must be an int") as usize;
        let img_height = data.find("height").expect("image height must be set")
            .as_u64().expect("image height must be an int") as usize;
        let mut volume = Scene::load_volume(data.find("volume").expect("A volume must be specified"), &base_path);
        let tfn = Scene::load_transfer_function(data.find("transfer_function")
                                                .expect("A transfer function must be specified"), &base_path);
        volume.set_transfer_function(tfn);

        let camera = Scene::load_camera(data.find("camera").expect("A camera must be specified"),
                                        img_width, img_height);
        let render_params = Scene::load_render_params(&data);
        Scene { width: img_width, height: img_height, camera: camera,
                volume: volume, params: render_params }
    }
    fn load_volume(e: &Value, base_path: &Path) -> Volume {
        let mut vol_file = Path::new(e.find("file").expect("A volume filename must be set")
                                 .as_string().expect("Volume filename must be a string")).to_owned();
        if !vol_file.is_absolute() {
            vol_file = base_path.join(vol_file);
        }
        assert_eq!(vol_file.extension(), Some(OsStr::new("raw")));
        let dimensions = Scene::load_vec3i(e.find("dimensions")
                                           .expect("Volume dims must be set for RAW volume"))
            .expect("Invalid dimensions specified");

        let dtype = e.find("data_type").expect("A data type must be specified for RAW volumes")
                     .as_string().expect("data type must be a string");
        if dtype == "u8" {
            raw::import::<u8>(vol_file.as_path(), dimensions)
        } else if dtype == "u16" {
            raw::import::<u16>(vol_file.as_path(), dimensions)
        } else if dtype == "f32" {
            raw::import::<f32>(vol_file.as_path(), dimensions)
        } else if dtype == "f64" {
            raw::import::<f64>(vol_file.as_path(), dimensions)
        } else {
            panic!("Unrecognized data type {}! Valid options are u8, u16, f32, f64", dtype);
        }
    }
    fn load_transfer_function(e: &Value, base_path: &Path) -> TransferFunction {
        let tfn_file = Path::new(e.as_string().expect("transfer_function filename/name must be a string"));
        // Load the ParaView transfer function file if it's one, otherwise
        // see if it's one of our defaults we can provide
        if tfn_file.extension() == Some(OsStr::new("json")) {
            let mut tfn_buf = tfn_file.to_owned();
            if !tfn_buf.is_absolute() {
                tfn_buf = base_path.join(tfn_buf);
            }
            panic!("TODO: ParaView transferfunction importing is not implemented");
        } else {
            let tfn_name = tfn_file.to_str().unwrap();
            if tfn_name == "grayscale" {
                TransferFunction::grayscale()
            } else if tfn_name == "jet" {
                TransferFunction::jet()
            } else if tfn_name == "cool_warm" {
                TransferFunction::cool_warm()
            } else {
                panic!("Scene error: {} is not a built in transfer function", tfn_name);
            }
        }
    }
    fn load_camera(e: &Value, width: usize, height: usize) -> Camera {
        let pos = Scene::load_vec3f(e.find("pos").expect("Camera view position must be set"))
            .expect("Invalid camera position");
        let target = Scene::load_vec3f(e.find("target").expect("Camera view target must be set"))
            .expect("Invalid camera target");
        let up = Scene::load_vec3f(e.find("up").expect("Camera up vector must be set"))
            .expect("Invalid camera up");
        let fovy = e.find("fovy").expect("Camera FOV Y must be set").as_f64()
            .expect("FOV Y must be a float") as f32;
        Camera::new(pos, target, up, fovy, width as u32, height as u32)
    }
    fn load_render_params(e: &Value) -> RenderParams {
        let background = Scene::load_vec3f(e.find("background").expect("Background color must be set"))
            .expect("Background color must be a vec3f");
        let n_samples = e.find("n_samples").expect("n_samples per pixel must be set")
            .as_i64().expect("n_samples must be an int") as i32;
        RenderParams { background: background, n_samples: n_samples }
    }
    fn load_vec3i(e: &Value) -> Option<Vec3i> {
        e.as_array().map(|x| {
            assert_eq!(x.len(), 3);
            Vec3i::new(x[0].as_i64().unwrap() as i32,
                       x[1].as_i64().unwrap() as i32,
                       x[2].as_i64().unwrap() as i32)
        })
    }
    fn load_vec3f(e: &Value) -> Option<Vec3f> {
        e.as_array().map(|x| {
            assert_eq!(x.len(), 3);
            Vec3f::new(x[0].as_f64().unwrap() as f32,
                       x[1].as_f64().unwrap() as f32,
                       x[2].as_f64().unwrap() as f32)
        })
    }
}

<|endoftext|>


<commit_before>//! Generic array are commonly used as a return value for hash digests, so
//! it's a good idea to allow to hexlify them easily. This module implements
//! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits.
//!
//! Example:
//!
//! ```rust
//! # #[macro_use]
//! # extern crate generic_array;
//! # extern crate typenum;
//! # fn main() {
//! let array = arr![u8; 10, 20, 30];
//! assert_eq!(format!("{:x}", array), "0a141e");
//! # }
//! ```
//!

use core::{fmt, str, ops::Add, cmp::min};

use typenum::*;

use crate::{ArrayLength, GenericArray};

static LOWER_CHARS: &'static [u8] = b"0123456789abcdef";
static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF";

impl<T: ArrayLength<u8>> fmt::LowerHex for GenericArray<u8, T>
where
    T: Add<T>,
    <T as Add<T>>::Output: ArrayLength<u8>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
        let max_hex = (max_digits >> 1) + (max_digits & 1);

        if T::USIZE < 1024 {
            // For small arrays use a stack allocated
            // buffer of 2x number of bytes
            let mut res = GenericArray::<u8, Sum<T, T>>::default();

            self.iter().take(max_hex).enumerate().for_each(|(i, c)| {
                res[i * 2] = LOWER_CHARS[(c >> 4) as usize];
                res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
            });

            f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
        } else {
            // For large array use chunks of up to 1024 bytes (2048 hex chars)
            let mut buf = [0u8; 2048];
            let mut digits_left = max_digits;

            for chunk in self[..max_hex].chunks(1024) {
                chunk.iter().enumerate().for_each(|(i, c)| {
                    buf[i * 2] = LOWER_CHARS[(c >> 4) as usize];
                    buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
                });

                let n = min(chunk.len() * 2, digits_left);
                f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
                digits_left -= n;
            }
        }
        Ok(())
    }
}

impl<T: ArrayLength<u8>> fmt::UpperHex for GenericArray<u8, T>
where
    T: Add<T>,
    <T as Add<T>>::Output: ArrayLength<u8>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
        let max_hex = (max_digits >> 1) + (max_digits & 1);

        if T::USIZE < 1024 {
            // For small arrays use a stack allocated
            // buffer of 2x number of bytes
            let mut res = GenericArray::<u8, Sum<T, T>>::default();

            self.iter().take(max_hex).enumerate().for_each(|(i, c)| {
                res[i * 2] = UPPER_CHARS[(c >> 4) as usize];
                res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
            });

            f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
        } else {
            // For large array use chunks of up to 1024 bytes (2048 hex chars)
            let mut buf = [0u8; 2048];
            let mut digits_left = max_digits;

            for chunk in self[..max_hex].chunks(1024) {
                chunk.iter().enumerate().for_each(|(i, c)| {
                    buf[i * 2] = UPPER_CHARS[(c >> 4) as usize];
                    buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
                });

                let n = min(chunk.len() * 2, digits_left);
                f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
                digits_left -= n;
            }
        }
        Ok(())
    }
}
<commit_msg>Remove default `static` lifetime<commit_after>//! Generic array are commonly used as a return value for hash digests, so
//! it's a good idea to allow to hexlify them easily. This module implements
//! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits.
//!
//! Example:
//!
//! ```rust
//! # #[macro_use]
//! # extern crate generic_array;
//! # extern crate typenum;
//! # fn main() {
//! let array = arr![u8; 10, 20, 30];
//! assert_eq!(format!("{:x}", array), "0a141e");
//! # }
//! ```
//!

use core::{cmp::min, fmt, ops::Add, str};

use typenum::*;

use crate::{ArrayLength, GenericArray};

static LOWER_CHARS: &[u8] = b"0123456789abcdef";
static UPPER_CHARS: &[u8] = b"0123456789ABCDEF";

impl<T: ArrayLength<u8>> fmt::LowerHex for GenericArray<u8, T>
where
    T: Add<T>,
    <T as Add<T>>::Output: ArrayLength<u8>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
        let max_hex = (max_digits >> 1) + (max_digits & 1);

        if T::USIZE < 1024 {
            // For small arrays use a stack allocated
            // buffer of 2x number of bytes
            let mut res = GenericArray::<u8, Sum<T, T>>::default();

            self.iter().take(max_hex).enumerate().for_each(|(i, c)| {
                res[i * 2] = LOWER_CHARS[(c >> 4) as usize];
                res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
            });

            f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
        } else {
            // For large array use chunks of up to 1024 bytes (2048 hex chars)
            let mut buf = [0u8; 2048];
            let mut digits_left = max_digits;

            for chunk in self[..max_hex].chunks(1024) {
                chunk.iter().enumerate().for_each(|(i, c)| {
                    buf[i * 2] = LOWER_CHARS[(c >> 4) as usize];
                    buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize];
                });

                let n = min(chunk.len() * 2, digits_left);
                f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
                digits_left -= n;
            }
        }
        Ok(())
    }
}

impl<T: ArrayLength<u8>> fmt::UpperHex for GenericArray<u8, T>
where
    T: Add<T>,
    <T as Add<T>>::Output: ArrayLength<u8>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let max_digits = f.precision().unwrap_or_else(|| self.len() * 2);
        let max_hex = (max_digits >> 1) + (max_digits & 1);

        if T::USIZE < 1024 {
            // For small arrays use a stack allocated
            // buffer of 2x number of bytes
            let mut res = GenericArray::<u8, Sum<T, T>>::default();

            self.iter().take(max_hex).enumerate().for_each(|(i, c)| {
                res[i * 2] = UPPER_CHARS[(c >> 4) as usize];
                res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
            });

            f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?;
        } else {
            // For large array use chunks of up to 1024 bytes (2048 hex chars)
            let mut buf = [0u8; 2048];
            let mut digits_left = max_digits;

            for chunk in self[..max_hex].chunks(1024) {
                chunk.iter().enumerate().for_each(|(i, c)| {
                    buf[i * 2] = UPPER_CHARS[(c >> 4) as usize];
                    buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize];
                });

                let n = min(chunk.len() * 2, digits_left);
                f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?;
                digits_left -= n;
            }
        }
        Ok(())
    }
}
<|endoftext|>