<commit_before>use core::cell::RefCell;
use core::cmp;
use std::io::prelude::*;
use std::io::{Error, ErrorKind, SeekFrom};
use std::io;
use std::str;
use byteorder::{LittleEndian, ReadBytesExt};

use file::FatFile;
use dir::{FatDirReader, FatDir};
use table::FatTable;

// FAT implementation based on:
//   http://wiki.osdev.org/FAT
//   https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FatType {
    Fat12, Fat16, Fat32, ExFat
}

pub trait ReadSeek: Read + Seek {}
impl<T> ReadSeek for T where T: Read + Seek {}

pub(crate) struct FatSharedState<'a> {
    pub(crate) rdr: &'a mut ReadSeek,
    pub(crate) fat_type: FatType,
    pub(crate) boot: FatBootRecord,
    pub(crate) first_data_sector: u32,
    pub(crate) root_dir_sectors: u32,
    pub(crate) table: FatTable,
}

impl <'a> FatSharedState<'a> {
    pub(crate) fn offset_from_sector(&self, sector: u32) -> u64 {
        (sector as u64) * self.boot.bpb.bytes_per_sector as u64
    }

    pub(crate) fn sector_from_cluster(&self, cluster: u32) -> u32 {
        ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector
    }

    pub(crate) fn get_cluster_size(&self) -> u32 {
        self.boot.bpb.sectors_per_cluster as u32 * self.boot.bpb.bytes_per_sector as u32
    }

    pub(crate) fn offset_from_cluster(&self, cluser: u32) -> u64 {
        self.offset_from_sector(self.sector_from_cluster(cluser))
    }
}

#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
pub(crate) struct FatBiosParameterBlock {
    bytes_per_sector: u16,
    sectors_per_cluster: u8,
    reserved_sector_count: u16,
    table_count: u8,
    root_entry_count: u16,
    total_sectors_16: u16,
    media_type: u8,
    table_size_16: u16,
    sectors_per_track: u16,
    head_side_count: u16,
    hidden_sector_count: u32,
    total_sectors_32: u32,

    // Extended BIOS Parameter Block
    table_size_32: u32,
    extended_flags: u16,
    fat_version: u16,
    root_cluster: u32,
    fat_info: u16,
    backup_bs_sector: u16,
    reserved_0: [u8; 12],
    drive_num: u8,
    reserved_1: u8,
    ext_sig: u8,
    volume_id: u32,
    volume_label: [u8; 11],
    fat_type_label: [u8; 8],
}

#[allow(dead_code)]
pub(crate) struct FatBootRecord {
    bootjmp: [u8; 3],
    oem_name: [u8; 8],
    bpb: FatBiosParameterBlock,
    boot_code: [u8; 448],
    boot_sig: [u8; 2],
}

impl Default for FatBootRecord {
    fn default() -> FatBootRecord {
        FatBootRecord {
            bootjmp: Default::default(),
            oem_name: Default::default(),
            bpb: Default::default(),
            boot_code: [0; 448],
            boot_sig: Default::default(),
        }
    }
}

pub(crate) type FatSharedStateCell<'a> = RefCell<FatSharedState<'a>>;
pub(crate) type FatSharedStateRef<'a, 'b: 'a> = &'a RefCell<FatSharedState<'b>>;

pub struct FatFileSystem<'a> {
    pub(crate) state: FatSharedStateCell<'a>,
}

impl <'a> FatFileSystem<'a> {

    pub fn new<T: ReadSeek>(mut rdr: &'a mut T) -> io::Result<FatFileSystem<'a>> {
        let boot = Self::read_boot_record(&mut *rdr)?;
        if boot.boot_sig != [0x55, 0xAA] {
            return Err(Error::new(ErrorKind::Other, "invBox::newalid signature"));
        }

        let total_sectors = if boot.bpb.total_sectors_16 == 0 { boot.bpb.total_sectors_32 } else { boot.bpb.total_sectors_16 as u32 };
        let table_size = if boot.bpb.table_size_16 == 0 { boot.bpb.table_size_32 } else { boot.bpb.table_size_16 as u32 };
        let root_dir_sectors = (((boot.bpb.root_entry_count * 32) + (boot.bpb.bytes_per_sector - 1)) / boot.bpb.bytes_per_sector) as u32;
        let first_data_sector = boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors;
        let data_sectors = total_sectors - (boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32);
        let total_clusters = data_sectors / boot.bpb.sectors_per_cluster as u32;
        let fat_type = Self::fat_type_from_clusters(total_clusters);

        let fat_offset = boot.bpb.reserved_sector_count * boot.bpb.bytes_per_sector;
        rdr.seek(SeekFrom::Start(fat_offset as u64))?;
        let table_size_bytes = table_size * boot.bpb.bytes_per_sector as u32;
        let table = FatTable::from_read(rdr, fat_type, table_size_bytes as usize)?;

        let state = FatSharedState {
            rdr,
            fat_type,
            boot,
            first_data_sector,
            root_dir_sectors,
            table,
        };

        Ok(FatFileSystem {
            state: RefCell::new(state),
        })
    }

    pub fn fat_type(&self) -> FatType {
        self.state.borrow().fat_type
    }

    pub fn volume_id(&self) -> u32 {
        self.state.borrow().boot.bpb.volume_id
    }

    pub fn volume_label(&self) -> String {
        str::from_utf8(&self.state.borrow().boot.bpb.volume_label).unwrap().trim_right().to_string()
    }

    pub fn root_dir<'b>(&'b self) -> FatDir<'b, 'a> {
        let root_rdr = {
            let state = self.state.borrow();
            match state.fat_type {
                FatType::Fat12 | FatType::Fat16 => FatDirReader::Root(FatSlice::from_sectors(
                   state.first_data_sector - state.root_dir_sectors, state.root_dir_sectors, &self.state)),
                _ => FatDirReader::File(FatFile::new(state.boot.bpb.root_cluster, None, &self.state)),
            }
        };
        FatDir::new(root_rdr, &self.state)
    }

    fn read_bpb(rdr: &mut Read) -> io::Result<FatBiosParameterBlock> {
        let mut bpb: FatBiosParameterBlock = Default::default();
        bpb.bytes_per_sector = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_cluster = rdr.read_u8()?;
        bpb.reserved_sector_count = rdr.read_u16::<LittleEndian>()?;
        bpb.table_count = rdr.read_u8()?;
        bpb.root_entry_count = rdr.read_u16::<LittleEndian>()? ;
        bpb.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.media_type = rdr.read_u8()?;
        bpb.table_size_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_track = rdr.read_u16::<LittleEndian>()?;
        bpb.head_side_count = rdr.read_u16::<LittleEndian>()?;
        bpb.hidden_sector_count = rdr.read_u32::<LittleEndian>()?; // hidden_sector_count
        bpb.total_sectors_32 = rdr.read_u32::<LittleEndian>()?;

        if bpb.table_size_16 == 0 {
            bpb.table_size_32 = rdr.read_u32::<LittleEndian>()?;
            bpb.extended_flags = rdr.read_u16::<LittleEndian>()?;
            bpb.fat_version = rdr.read_u16::<LittleEndian>()?;
            bpb.root_cluster = rdr.read_u32::<LittleEndian>()?;
            bpb.fat_info = rdr.read_u16::<LittleEndian>()?;
            bpb.backup_bs_sector = rdr.read_u16::<LittleEndian>()?;
            rdr.read(&mut bpb.reserved_0)?;
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fat_type_label)?;
            //bpb.boot_code = Vec::with_capacity(420);
            //rdr.read_exact(bpb.boot_code.as_mut_slice())?;
        } else {
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fat_type_label)?;
            //bpb.boot_code = Vec::with_capacity(448);
            //rdr.read_exact(bpb.boot_code.as_mut_slice())?;
        }
        Ok(bpb)
    }

    fn fat_type_from_clusters(total_clusters: u32) -> FatType {
        if total_clusters < 4085 {
            FatType::Fat12
        } else if total_clusters < 65525 {
            FatType::Fat16
        } else if total_clusters < 268435445 {
            FatType::Fat32
        } else {
            FatType::ExFat
        }
    }

    fn read_boot_record(rdr: &mut Read) -> io::Result<FatBootRecord> {
        let mut boot: FatBootRecord = Default::default();
        rdr.read(&mut boot.bootjmp)?;
        rdr.read(&mut boot.oem_name)?;
        boot.bpb = Self::read_bpb(rdr)?;

        if boot.bpb.table_size_16 == 0 {
            rdr.read_exact(&mut boot.boot_code[0..420])?;
        } else {
            rdr.read_exact(&mut boot.boot_code[0..448])?;
        }
        rdr.read(&mut boot.boot_sig)?;
        Ok(boot)
    }
}

pub(crate) struct FatSlice<'a, 'b: 'a> {
    begin: u64,
    size: u64,
    offset: u64,
    state: FatSharedStateRef<'a, 'b>,
}

impl <'a, 'b> FatSlice<'a, 'b> {
    pub(crate) fn new(begin: u64, size: u64, state: FatSharedStateRef<'a, 'b>) -> Self {
        FatSlice { begin, size, state, offset: 0 }
    }

    pub(crate) fn from_sectors(first_sector: u32, sectors_count: u32, state: FatSharedStateRef<'a, 'b>) -> Self {
        let bytes_per_sector = state.borrow().boot.bpb.bytes_per_sector as u64;
        Self::new(first_sector as u64 * bytes_per_sector, sectors_count as u64 * bytes_per_sector, state)
    }
}

impl <'a, 'b> Read for FatSlice<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let offset = self.begin + self.offset;
        let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
        let mut state = self.state.borrow_mut();
        state.rdr.seek(SeekFrom::Start(offset))?;
        let size = state.rdr.read(&mut buf[..read_size])?;
        self.offset += size as u64;
        Ok(size)
    }
}

impl <'a, 'b> Seek for FatSlice<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        let new_offset = match pos {
            SeekFrom::Current(x) => self.offset as i64 + x,
            SeekFrom::Start(x) => x as i64,
            SeekFrom::End(x) => self.size as i64 + x,
        };
        if new_offset < 0 || new_offset as u64 > self.size {
            Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"))
        } else {
            self.offset = new_offset as u64;
            Ok(self.offset)
        }
    }
}
<commit_msg>Rename some fields in internal bsp struct.<commit_after>use core::cell::RefCell;
use core::cmp;
use std::io::prelude::*;
use std::io::{Error, ErrorKind, SeekFrom};
use std::io;
use std::str;
use byteorder::{LittleEndian, ReadBytesExt};

use file::FatFile;
use dir::{FatDirReader, FatDir};
use table::FatTable;

// FAT implementation based on:
//   http://wiki.osdev.org/FAT
//   https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FatType {
    Fat12, Fat16, Fat32, ExFat
}

pub trait ReadSeek: Read + Seek {}
impl<T> ReadSeek for T where T: Read + Seek {}

pub(crate) struct FatSharedState<'a> {
    pub(crate) rdr: &'a mut ReadSeek,
    pub(crate) fat_type: FatType,
    pub(crate) boot: FatBootRecord,
    pub(crate) first_data_sector: u32,
    pub(crate) root_dir_sectors: u32,
    pub(crate) table: FatTable,
}

impl <'a> FatSharedState<'a> {
    pub(crate) fn offset_from_sector(&self, sector: u32) -> u64 {
        (sector as u64) * self.boot.bpb.bytes_per_sector as u64
    }

    pub(crate) fn sector_from_cluster(&self, cluster: u32) -> u32 {
        ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector
    }

    pub(crate) fn get_cluster_size(&self) -> u32 {
        self.boot.bpb.sectors_per_cluster as u32 * self.boot.bpb.bytes_per_sector as u32
    }

    pub(crate) fn offset_from_cluster(&self, cluser: u32) -> u64 {
        self.offset_from_sector(self.sector_from_cluster(cluser))
    }
}

#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
pub(crate) struct FatBiosParameterBlock {
    bytes_per_sector: u16,
    sectors_per_cluster: u8,
    reserved_sectors: u16,
    fats: u8,
    root_entries: u16,
    total_sectors_16: u16,
    media: u8,
    sectors_per_fat_16: u16,
    sectors_per_track: u16,
    heads: u16,
    hidden_sectors: u32,
    total_sectors_32: u32,

    // Extended BIOS Parameter Block
    sectors_per_fat_32: u32,
    extended_flags: u16,
    fs_version: u16,
    root_dir_first_cluster: u32,
    fs_info_sector: u16,
    backup_boot_sector: u16,
    reserved_0: [u8; 12],
    drive_num: u8,
    reserved_1: u8,
    ext_sig: u8,
    volume_id: u32,
    volume_label: [u8; 11],
    fs_type_label: [u8; 8],
}

#[allow(dead_code)]
pub(crate) struct FatBootRecord {
    bootjmp: [u8; 3],
    oem_name: [u8; 8],
    bpb: FatBiosParameterBlock,
    boot_code: [u8; 448],
    boot_sig: [u8; 2],
}

impl Default for FatBootRecord {
    fn default() -> FatBootRecord {
        FatBootRecord {
            bootjmp: Default::default(),
            oem_name: Default::default(),
            bpb: Default::default(),
            boot_code: [0; 448],
            boot_sig: Default::default(),
        }
    }
}

pub(crate) type FatSharedStateCell<'a> = RefCell<FatSharedState<'a>>;
pub(crate) type FatSharedStateRef<'a, 'b: 'a> = &'a RefCell<FatSharedState<'b>>;

pub struct FatFileSystem<'a> {
    pub(crate) state: FatSharedStateCell<'a>,
}

impl <'a> FatFileSystem<'a> {

    pub fn new<T: ReadSeek>(mut rdr: &'a mut T) -> io::Result<FatFileSystem<'a>> {
        let boot = Self::read_boot_record(&mut *rdr)?;
        if boot.boot_sig != [0x55, 0xAA] {
            return Err(Error::new(ErrorKind::Other, "invBox::newalid signature"));
        }

        let total_sectors = if boot.bpb.total_sectors_16 == 0 { boot.bpb.total_sectors_32 } else { boot.bpb.total_sectors_16 as u32 };
        let sectors_per_fat = if boot.bpb.sectors_per_fat_16 == 0 { boot.bpb.sectors_per_fat_32 } else { boot.bpb.sectors_per_fat_16 as u32 };
        let root_dir_sectors = (((boot.bpb.root_entries * 32) + (boot.bpb.bytes_per_sector - 1)) / boot.bpb.bytes_per_sector) as u32;
        let first_data_sector = boot.bpb.reserved_sectors as u32 + (boot.bpb.fats as u32 * sectors_per_fat) + root_dir_sectors;
        let data_sectors = total_sectors - (boot.bpb.reserved_sectors as u32 + (boot.bpb.fats as u32 * sectors_per_fat) + root_dir_sectors as u32);
        let total_clusters = data_sectors / boot.bpb.sectors_per_cluster as u32;
        let fat_type = Self::fat_type_from_clusters(total_clusters);

        let fat_offset = boot.bpb.reserved_sectors * boot.bpb.bytes_per_sector;
        rdr.seek(SeekFrom::Start(fat_offset as u64))?;
        let fat_size = sectors_per_fat * boot.bpb.bytes_per_sector as u32;
        let table = FatTable::from_read(rdr, fat_type, fat_size as usize)?;

        let state = FatSharedState {
            rdr,
            fat_type,
            boot,
            first_data_sector,
            root_dir_sectors,
            table,
        };

        Ok(FatFileSystem {
            state: RefCell::new(state),
        })
    }

    pub fn fat_type(&self) -> FatType {
        self.state.borrow().fat_type
    }

    pub fn volume_id(&self) -> u32 {
        self.state.borrow().boot.bpb.volume_id
    }

    pub fn volume_label(&self) -> String {
        str::from_utf8(&self.state.borrow().boot.bpb.volume_label).unwrap().trim_right().to_string()
    }

    pub fn root_dir<'b>(&'b self) -> FatDir<'b, 'a> {
        let root_rdr = {
            let state = self.state.borrow();
            match state.fat_type {
                FatType::Fat12 | FatType::Fat16 => FatDirReader::Root(FatSlice::from_sectors(
                   state.first_data_sector - state.root_dir_sectors, state.root_dir_sectors, &self.state)),
                _ => FatDirReader::File(FatFile::new(state.boot.bpb.root_dir_first_cluster, None, &self.state)),
            }
        };
        FatDir::new(root_rdr, &self.state)
    }

    fn read_bpb(rdr: &mut Read) -> io::Result<FatBiosParameterBlock> {
        let mut bpb: FatBiosParameterBlock = Default::default();
        bpb.bytes_per_sector = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_cluster = rdr.read_u8()?;
        bpb.reserved_sectors = rdr.read_u16::<LittleEndian>()?;
        bpb.fats = rdr.read_u8()?;
        bpb.root_entries = rdr.read_u16::<LittleEndian>()? ;
        bpb.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.media = rdr.read_u8()?;
        bpb.sectors_per_fat_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_track = rdr.read_u16::<LittleEndian>()?;
        bpb.heads = rdr.read_u16::<LittleEndian>()?;
        bpb.hidden_sectors = rdr.read_u32::<LittleEndian>()?; // hidden_sector_count
        bpb.total_sectors_32 = rdr.read_u32::<LittleEndian>()?;

        if bpb.sectors_per_fat_16 == 0 {
            bpb.sectors_per_fat_32 = rdr.read_u32::<LittleEndian>()?;
            bpb.extended_flags = rdr.read_u16::<LittleEndian>()?;
            bpb.fs_version = rdr.read_u16::<LittleEndian>()?;
            bpb.root_dir_first_cluster = rdr.read_u32::<LittleEndian>()?;
            bpb.fs_info_sector = rdr.read_u16::<LittleEndian>()?;
            bpb.backup_boot_sector = rdr.read_u16::<LittleEndian>()?;
            rdr.read(&mut bpb.reserved_0)?;
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fs_type_label)?;
        } else {
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fs_type_label)?;
        }
        Ok(bpb)
    }

    fn fat_type_from_clusters(total_clusters: u32) -> FatType {
        if total_clusters < 4085 {
            FatType::Fat12
        } else if total_clusters < 65525 {
            FatType::Fat16
        } else if total_clusters < 268435445 {
            FatType::Fat32
        } else {
            FatType::ExFat
        }
    }

    fn read_boot_record(rdr: &mut Read) -> io::Result<FatBootRecord> {
        let mut boot: FatBootRecord = Default::default();
        rdr.read(&mut boot.bootjmp)?;
        rdr.read(&mut boot.oem_name)?;
        boot.bpb = Self::read_bpb(rdr)?;

        if boot.bpb.sectors_per_fat_16 == 0 {
            rdr.read_exact(&mut boot.boot_code[0..420])?;
        } else {
            rdr.read_exact(&mut boot.boot_code[0..448])?;
        }
        rdr.read(&mut boot.boot_sig)?;
        Ok(boot)
    }
}

pub(crate) struct FatSlice<'a, 'b: 'a> {
    begin: u64,
    size: u64,
    offset: u64,
    state: FatSharedStateRef<'a, 'b>,
}

impl <'a, 'b> FatSlice<'a, 'b> {
    pub(crate) fn new(begin: u64, size: u64, state: FatSharedStateRef<'a, 'b>) -> Self {
        FatSlice { begin, size, state, offset: 0 }
    }

    pub(crate) fn from_sectors(first_sector: u32, sectors_count: u32, state: FatSharedStateRef<'a, 'b>) -> Self {
        let bytes_per_sector = state.borrow().boot.bpb.bytes_per_sector as u64;
        Self::new(first_sector as u64 * bytes_per_sector, sectors_count as u64 * bytes_per_sector, state)
    }
}

impl <'a, 'b> Read for FatSlice<'a, 'b> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let offset = self.begin + self.offset;
        let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
        let mut state = self.state.borrow_mut();
        state.rdr.seek(SeekFrom::Start(offset))?;
        let size = state.rdr.read(&mut buf[..read_size])?;
        self.offset += size as u64;
        Ok(size)
    }
}

impl <'a, 'b> Seek for FatSlice<'a, 'b> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        let new_offset = match pos {
            SeekFrom::Current(x) => self.offset as i64 + x,
            SeekFrom::Start(x) => x as i64,
            SeekFrom::End(x) => self.size as i64 + x,
        };
        if new_offset < 0 || new_offset as u64 > self.size {
            Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"))
        } else {
            self.offset = new_offset as u64;
            Ok(self.offset)
        }
    }
}
<|endoftext|>


<commit_before>use nickel::{Request, Response, MiddlewareResult};
use hyper::client::Client;
use common;
use nickel::status::StatusCode;
use hyper::header::Location;
use mustache::MapBuilder;
use mustache::Data;
use json::JsonValue;

pub fn id_handler<'a, D>(request: &mut Request<D>,
                         mut response: Response<'a, D>)
                         -> MiddlewareResult<'a, D> {
    let client = Client::new();
    let id_query = request.param("id").expect("Missing id");
    let url = &format!("https://api.tfl.gov.uk/StopPoint/{}", id_query);
    let obj = match common::json_for_request(client.get(url)) {
        Ok(val) => val,
        Err(val) => {
            response.set(StatusCode::BadGateway);
            return response.send(val);
        }
    };

    for line_group in obj["lineGroup"].members() {
        if line_group["naptanIdReference"] == JsonValue::Null {
            continue;
        }
        if line_group["naptanIdReference"].as_str().unwrap_or("") == id_query {
            response.set(Location(format!("/arrivals/{}", line_group["naptanIdReference"])))
                .set(StatusCode::MovedPermanently);
            return response.send("");
        }
    }

    let data = MapBuilder::new()
        .insert_vec("stops", |vecbuilder| {
            let mut vecb = vecbuilder;
            for naptan_id in obj["lineGroup"]
                .members()
                .into_iter()
                .map(|x| x["naptanIdReference"].as_str().unwrap_or("")) {
                if naptan_id == "" {
                    continue;
                }
                let stopobj =
            match common::json_for_request(
                client.get(&format!("https://api.tfl.gov.uk/StopPoint/{}/Arrivals",
                              naptan_id))) {
                Ok(val) => val,
                Err(_) => continue
            };
                let first_arrival = stopobj.members().nth(0);
                if let Some(val) = first_arrival {
                    vecb = vecb.push_map(|mapbuilder| {
                        let platform_name = val["platformName"].as_str().unwrap();
                        let stop_number = if platform_name == "null" {
                            "".to_string()
                        } else {
                            format!(" (Stop {})", platform_name)
                        };
                        mapbuilder.insert_str("id", naptan_id)
                            .insert_str("stopName", val["stationName"].as_str().unwrap())
                            .insert_str("stopNumber", stop_number)
                    })
                }
            }
            vecb
        })
        .insert_str("query", obj["commonName"].as_str().unwrap())
        .build();
    if let Data::Map(ref hash) = data {
        if let Data::VecVal(ref stops) = hash["stops"] {
            if stops.len() == 1 {
                if let Data::Map(ref stop) = stops[0] {
                    if let Data::StrVal(ref id) = stop["id"] {
                        response.set(Location(format!("/id/{}", id)))
                            .set(StatusCode::MovedPermanently);
                        return response.send("");
                    }
                }
            }
        }
    }
    common::render_to_response(response, "resources/templates/multiple-id.mustache", &data)
}
<commit_msg>Now id only matches on naptanIdReference, don't need to skip the nulls<commit_after>use nickel::{Request, Response, MiddlewareResult};
use hyper::client::Client;
use common;
use nickel::status::StatusCode;
use hyper::header::Location;
use mustache::MapBuilder;
use mustache::Data;
use json::JsonValue;

pub fn id_handler<'a, D>(request: &mut Request<D>,
                         mut response: Response<'a, D>)
                         -> MiddlewareResult<'a, D> {
    let client = Client::new();
    let id_query = request.param("id").expect("Missing id");
    let url = &format!("https://api.tfl.gov.uk/StopPoint/{}", id_query);
    let obj = match common::json_for_request(client.get(url)) {
        Ok(val) => val,
        Err(val) => {
            response.set(StatusCode::BadGateway);
            return response.send(val);
        }
    };

    for line_group in obj["lineGroup"].members() {
        if line_group["naptanIdReference"].as_str().unwrap_or("") == id_query {
            response.set(Location(format!("/arrivals/{}", line_group["naptanIdReference"])))
                .set(StatusCode::MovedPermanently);
            return response.send("");
        }
    }

    let data = MapBuilder::new()
        .insert_vec("stops", |vecbuilder| {
            let mut vecb = vecbuilder;
            for naptan_id in obj["lineGroup"]
                .members()
                .into_iter()
                .map(|x| x["naptanIdReference"].as_str().unwrap_or("")) {
                if naptan_id == "" {
                    continue;
                }
                let stopobj =
            match common::json_for_request(
                client.get(&format!("https://api.tfl.gov.uk/StopPoint/{}/Arrivals",
                              naptan_id))) {
                Ok(val) => val,
                Err(_) => continue
            };
                let first_arrival = stopobj.members().nth(0);
                if let Some(val) = first_arrival {
                    vecb = vecb.push_map(|mapbuilder| {
                        let platform_name = val["platformName"].as_str().unwrap();
                        let stop_number = if platform_name == "null" {
                            "".to_string()
                        } else {
                            format!(" (Stop {})", platform_name)
                        };
                        mapbuilder.insert_str("id", naptan_id)
                            .insert_str("stopName", val["stationName"].as_str().unwrap())
                            .insert_str("stopNumber", stop_number)
                    })
                }
            }
            vecb
        })
        .insert_str("query", obj["commonName"].as_str().unwrap())
        .build();
    if let Data::Map(ref hash) = data {
        if let Data::VecVal(ref stops) = hash["stops"] {
            if stops.len() == 1 {
                if let Data::Map(ref stop) = stops[0] {
                    if let Data::StrVal(ref id) = stop["id"] {
                        response.set(Location(format!("/id/{}", id)))
                            .set(StatusCode::MovedPermanently);
                        return response.send("");
                    }
                }
            }
        }
    }
    common::render_to_response(response, "resources/templates/multiple-id.mustache", &data)
}
<|endoftext|>


<commit_before>//! # generator run time support
//!
//! generator run time context management
//!
use std::any::Any;
use std::mem::MaybeUninit;
use std::ptr;

use crate::reg_context::RegContext;

thread_local!(
    /// each thread has it's own generator context stack
    static ROOT_CONTEXT: Box<Context> = {
        let mut root = Box::new(Context::new());
        let p = &mut *root as *mut _;
        root.parent = p; // init top to current
        root
    }
);

// fast access pointer, this is will be init only once
// when ROOT_CONTEXT get initialized. but in debug mode it
// will be zero in generator context since the stack changed
// to a different place, be careful about that.
#[cfg(nightly)]
#[thread_local]
#[no_mangle]
static mut ROOT_CONTEXT_P: *mut Context = ptr::null_mut();

/// yield panic error types
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Error {
    /// Cancel panic
    Cancel,
    /// Type mismatch panic
    TypeErr,
    /// Stack overflow panic
    StackErr,
    /// Wrong Context panic
    ContextErr,
}

/// generator context
#[repr(C)]
pub struct Context {
    /// generator regs context
    pub regs: RegContext,
    /// child context
    child: *mut Context,
    /// parent context
    pub parent: *mut Context,
    /// passed in para for send
    pub para: MaybeUninit<*mut dyn Any>,
    /// this is just a buffer for the return value
    pub ret: MaybeUninit<*mut dyn Any>,
    /// track generator ref, yield will -1, send will +1
    pub _ref: usize,
    /// context local storage
    pub local_data: *mut u8,
    /// propagate panic
    pub err: Option<Box<dyn Any + Send>>,
}

impl Context {
    /// return a default generator context
    pub fn new() -> Context {
        Context {
            regs: RegContext::empty(),
            para: MaybeUninit::zeroed(),
            ret: MaybeUninit::zeroed(),
            _ref: 1, // none zero means it's not running
            err: None,
            child: ptr::null_mut(),
            parent: ptr::null_mut(),
            local_data: ptr::null_mut(),
        }
    }

    /// judge it's generator context
    #[inline]
    pub fn is_generator(&self) -> bool {
        self.parent != self as *const _ as *mut _
    }

    /// get current generator send para
    #[inline]
    pub fn get_para(&mut self) -> Option
    where
        A: Any,
    {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            assert!(!para_ptr.is_null());
            &mut *para_ptr
        };
        match para.downcast_mut::<Option>() {
            Some(v) => v.take(),
            None => type_error::("get yield type mismatch error detected"),
        }
    }

    /// get coroutine send para
    #[inline]
    pub fn co_get_para(&mut self) -> Option {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            debug_assert!(!para_ptr.is_null());
            &mut *(para_ptr as *mut Option)
        };
        para.take()
    }

    /// set current generator send para
    // #[inline]
    // pub fn set_para(&self, data: A)
    // where
    //     A: Any,
    // {
    //     let para = unsafe { &mut *self.para };
    //     match para.downcast_mut::<Option>() {
    //         Some(v) => *v = Some(data),
    //         None => type_error::("set yield type mismatch error detected"),
    //     }
    // }

    /// set coroutine send para
    /// without check the data type for coroutine performance reason
    #[inline]
    pub fn co_set_para(&mut self, data: A) {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            debug_assert!(!para_ptr.is_null());
            &mut *(para_ptr as *mut Option)
        };
        *para = Some(data);
    }

    /// set current generator return value
    #[inline]
    pub fn set_ret<T>(&mut self, v: T)
    where
        T: Any,
    {
        let ret = unsafe {
            let ret_ptr = *self.ret.as_mut_ptr();
            assert!(!ret_ptr.is_null());
            &mut *ret_ptr
        };
        match ret.downcast_mut::<Option<T>>() {
            Some(r) => *r = Some(v),
            None => type_error::<T>("yield type mismatch error detected"),
        }
    }

    /// set coroutine return value
    /// without check the data type for coroutine performance reason
    #[inline]
    pub fn co_set_ret<T>(&mut self, v: T) {
        let ret = unsafe {
            let ret_ptr = *self.ret.as_mut_ptr();
            debug_assert!(!ret_ptr.is_null());
            &mut *(ret_ptr as *mut Option<T>)
        };
        *ret = Some(v);
    }
}

/// Coroutine managing environment
pub struct ContextStack {
    root: *mut Context,
}

#[cfg(nightly)]
#[inline(never)]
unsafe fn init_root_p() {
    ROOT_CONTEXT_P = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
}

impl ContextStack {
    #[cfg(nightly)]
    #[inline]
    pub fn current() -> ContextStack {
        unsafe {
            if ROOT_CONTEXT_P.is_null() {
                init_root_p();
            }
            ContextStack {
                root: ROOT_CONTEXT_P,
            }
        }
    }

    #[cfg(not(nightly))]
    #[inline]
    pub fn current() -> ContextStack {
        let root = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
        ContextStack { root }
    }

    /// get the top context
    #[inline]
    pub fn top(&self) -> &'static mut Context {
        let root = unsafe { &mut *self.root };
        unsafe { &mut *root.parent }
    }

    /// get the coroutine context
    #[inline]
    pub fn co_ctx(&self) -> Option<&'static mut Context> {
        let root = unsafe { &mut *self.root };

        // search from top
        let mut ctx = unsafe { &mut *root.parent };
        while ctx as *const _ != root as *const _ {
            if !ctx.local_data.is_null() {
                return Some(ctx);
            }
            ctx = unsafe { &mut *ctx.parent };
        }
        // not find any coroutine
        None
    }

    /// push the context to the thread context list
    #[inline]
    pub fn push_context(&self, ctx: *mut Context) {
        let root = unsafe { &mut *self.root };
        let ctx = unsafe { &mut *ctx };
        let top = unsafe { &mut *root.parent };
        let new_top = ctx.parent;

        // link top and new ctx
        top.child = ctx;
        ctx.parent = top;

        // save the new top
        root.parent = new_top;
    }

    /// pop the context from the thread context list and return it's parent context
    #[inline]
    pub fn pop_context(&self, ctx: *mut Context) -> &'static mut Context {
        let root = unsafe { &mut *self.root };
        let ctx = unsafe { &mut *ctx };
        let parent = unsafe { &mut *ctx.parent };

        // save the old top in ctx's parent
        ctx.parent = root.parent;
        // unlink ctx and it's parent
        parent.child = ptr::null_mut();

        // save the new top
        root.parent = parent;

        parent
    }
}

#[inline]
fn type_error(msg: &str) -> ! {
    #[cfg(nightly)]
    #[allow(unused_unsafe)]
    {
        use std::intrinsics::type_name;
        let t = unsafe { type_name::() };
        error!("{}, expected type: {}", msg, t);
    }

    #[cfg(not(nightly))]
    {
        error!("{}", msg);
    }
    panic!(Error::TypeErr)
}

/// check the current context if it's generator
#[inline]
pub fn is_generator() -> bool {
    let env = ContextStack::current();
    let root = unsafe { &mut *env.root };
    !root.child.is_null()
}

/// get the current context local data
/// only coroutine support local data
#[inline]
pub fn get_local_data() -> *mut u8 {
    let env = ContextStack::current();
    let root = unsafe { &mut *env.root };

    // search from top
    let mut ctx = unsafe { &mut *root.parent };
    while ctx as *const _ != root as *const _ {
        if !ctx.local_data.is_null() {
            return ctx.local_data;
        }
        ctx = unsafe { &mut *ctx.parent };
    }

    ptr::null_mut()
}

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

    #[test]
    fn test_is_context() {
        // this is the root context
        assert!(!is_generator());
    }
}
<commit_msg>:pencil: fix aarch64 release optimization issue<commit_after>//! # generator run time support
//!
//! generator run time context management
//!
use std::any::Any;
use std::mem::MaybeUninit;
use std::ptr;

use crate::reg_context::RegContext;

thread_local!(
    /// each thread has it's own generator context stack
    static ROOT_CONTEXT: Box<Context> = {
        let mut root = Box::new(Context::new());
        let p = &mut *root as *mut _;
        root.parent = p; // init top to current
        root
    }
);

// fast access pointer, this is will be init only once
// when ROOT_CONTEXT get initialized. but in debug mode it
// will be zero in generator context since the stack changed
// to a different place, be careful about that.
#[cfg(nightly)]
#[thread_local]
#[no_mangle]
static mut ROOT_CONTEXT_P: *mut Context = ptr::null_mut();

/// yield panic error types
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Error {
    /// Cancel panic
    Cancel,
    /// Type mismatch panic
    TypeErr,
    /// Stack overflow panic
    StackErr,
    /// Wrong Context panic
    ContextErr,
}

/// generator context
#[repr(C)]
pub struct Context {
    /// generator regs context
    pub regs: RegContext,
    /// child context
    child: *mut Context,
    /// parent context
    pub parent: *mut Context,
    /// passed in para for send
    pub para: MaybeUninit<*mut dyn Any>,
    /// this is just a buffer for the return value
    pub ret: MaybeUninit<*mut dyn Any>,
    /// track generator ref, yield will -1, send will +1
    pub _ref: usize,
    /// context local storage
    pub local_data: *mut u8,
    /// propagate panic
    pub err: Option<Box<dyn Any + Send>>,
}

impl Context {
    /// return a default generator context
    pub fn new() -> Context {
        Context {
            regs: RegContext::empty(),
            para: MaybeUninit::zeroed(),
            ret: MaybeUninit::zeroed(),
            _ref: 1, // none zero means it's not running
            err: None,
            child: ptr::null_mut(),
            parent: ptr::null_mut(),
            local_data: ptr::null_mut(),
        }
    }

    /// judge it's generator context
    #[inline]
    pub fn is_generator(&self) -> bool {
        self.parent != self as *const _ as *mut _
    }

    /// get current generator send para
    #[inline]
    pub fn get_para(&mut self) -> Option
    where
        A: Any,
    {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            assert!(!para_ptr.is_null());
            &mut *para_ptr
        };
        match para.downcast_mut::<Option>() {
            Some(v) => v.take(),
            None => type_error::("get yield type mismatch error detected"),
        }
    }

    /// get coroutine send para
    #[inline]
    pub fn co_get_para(&mut self) -> Option {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            debug_assert!(!para_ptr.is_null());
            &mut *(para_ptr as *mut Option)
        };
        para.take()
    }

    /// set current generator send para
    // #[inline]
    // pub fn set_para(&self, data: A)
    // where
    //     A: Any,
    // {
    //     let para = unsafe { &mut *self.para };
    //     match para.downcast_mut::<Option>() {
    //         Some(v) => *v = Some(data),
    //         None => type_error::("set yield type mismatch error detected"),
    //     }
    // }

    /// set coroutine send para
    /// without check the data type for coroutine performance reason
    #[inline]
    pub fn co_set_para(&mut self, data: A) {
        let para = unsafe {
            let para_ptr = *self.para.as_mut_ptr();
            debug_assert!(!para_ptr.is_null());
            &mut *(para_ptr as *mut Option)
        };
        *para = Some(data);
    }

    /// set current generator return value
    #[inline]
    pub fn set_ret<T>(&mut self, v: T)
    where
        T: Any,
    {
        let ret = unsafe {
            let ret_ptr = *self.ret.as_mut_ptr();
            assert!(!ret_ptr.is_null());
            &mut *ret_ptr
        };
        match ret.downcast_mut::<Option<T>>() {
            Some(r) => *r = Some(v),
            None => type_error::<T>("yield type mismatch error detected"),
        }
    }

    /// set coroutine return value
    /// without check the data type for coroutine performance reason
    #[inline]
    pub fn co_set_ret<T>(&mut self, v: T) {
        let ret = unsafe {
            let ret_ptr = *self.ret.as_mut_ptr();
            debug_assert!(!ret_ptr.is_null());
            &mut *(ret_ptr as *mut Option<T>)
        };
        *ret = Some(v);
    }
}

/// Coroutine managing environment
pub struct ContextStack {
    root: *mut Context,
}

#[cfg(nightly)]
#[inline(never)]
unsafe fn init_root_p() {
    ROOT_CONTEXT_P = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
}

impl ContextStack {
    #[cfg(nightly)]
    #[inline(never)]
    pub fn current() -> ContextStack {
        unsafe {
            if ROOT_CONTEXT_P.is_null() {
                init_root_p();
            }
            ContextStack {
                root: ROOT_CONTEXT_P,
            }
        }
    }

    #[cfg(not(nightly))]
    #[inline(never)]
    pub fn current() -> ContextStack {
        let root = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
        ContextStack { root }
    }

    /// get the top context
    #[inline]
    pub fn top(&self) -> &'static mut Context {
        let root = unsafe { &mut *self.root };
        unsafe { &mut *root.parent }
    }

    /// get the coroutine context
    #[inline]
    pub fn co_ctx(&self) -> Option<&'static mut Context> {
        let root = unsafe { &mut *self.root };

        // search from top
        let mut ctx = unsafe { &mut *root.parent };
        while ctx as *const _ != root as *const _ {
            if !ctx.local_data.is_null() {
                return Some(ctx);
            }
            ctx = unsafe { &mut *ctx.parent };
        }
        // not find any coroutine
        None
    }

    /// push the context to the thread context list
    #[inline]
    pub fn push_context(&self, ctx: *mut Context) {
        let root = unsafe { &mut *self.root };
        let ctx = unsafe { &mut *ctx };
        let top = unsafe { &mut *root.parent };
        let new_top = ctx.parent;

        // link top and new ctx
        top.child = ctx;
        ctx.parent = top;

        // save the new top
        root.parent = new_top;
    }

    /// pop the context from the thread context list and return it's parent context
    #[inline]
    pub fn pop_context(&self, ctx: *mut Context) -> &'static mut Context {
        let root = unsafe { &mut *self.root };
        let ctx = unsafe { &mut *ctx };
        let parent = unsafe { &mut *ctx.parent };

        // save the old top in ctx's parent
        ctx.parent = root.parent;
        // unlink ctx and it's parent
        parent.child = ptr::null_mut();

        // save the new top
        root.parent = parent;

        parent
    }
}

#[inline]
fn type_error(msg: &str) -> ! {
    #[cfg(nightly)]
    #[allow(unused_unsafe)]
    {
        use std::intrinsics::type_name;
        let t = unsafe { type_name::() };
        error!("{}, expected type: {}", msg, t);
    }

    #[cfg(not(nightly))]
    {
        error!("{}", msg);
    }
    panic!(Error::TypeErr)
}

/// check the current context if it's generator
#[inline]
pub fn is_generator() -> bool {
    let env = ContextStack::current();
    let root = unsafe { &mut *env.root };
    !root.child.is_null()
}

/// get the current context local data
/// only coroutine support local data
#[inline]
pub fn get_local_data() -> *mut u8 {
    let env = ContextStack::current();
    let root = unsafe { &mut *env.root };

    // search from top
    let mut ctx = unsafe { &mut *root.parent };
    while ctx as *const _ != root as *const _ {
        if !ctx.local_data.is_null() {
            return ctx.local_data;
        }
        ctx = unsafe { &mut *ctx.parent };
    }

    ptr::null_mut()
}

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

    #[test]
    fn test_is_context() {
        // this is the root context
        assert!(!is_generator());
    }
}
<|endoftext|>


<commit_before>use std::usize;

// Prefer this for marking, instead of Option<usize> (as it requires additional byte of memory)
const MARKER: usize = usize::MAX;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SuffixType {
    Small,
    Large,
    LeftMostSmall,
}

// Generates a suffix array and sorts them using the "induced sorting" method
// (Thanks to the python implementation in http://zork.net/~st/jottings/sais.html)
pub fn suffix_array(input: Vec<u8>) -> Vec<usize> {
    let mut type_map = vec![SuffixType::Small; input.len() + 1];
    let mut bucket_sizes = [0; 256];
    let mut bucket_heads = vec![0; 256];
    let mut bucket_tails = vec![0; 256];

    type_map[input.len()] = SuffixType::LeftMostSmall;      // assume that this is a null byte
    type_map[input.len() - 1] = SuffixType::Large;          // should be L-type
    bucket_sizes[input[input.len() - 1] as usize] = 1;      // don't forget the last value!

    // group the bytes into S-type or L-type (also mark LMS types)
    for i in (0..input.len() - 1).rev() {
        bucket_sizes[input[i] as usize] += 1;

        if input[i] > input[i + 1] ||
           (input[i] == input[i + 1] && type_map[i + 1] == SuffixType::Large) {
            if type_map[i + 1] == SuffixType::Small {
                type_map[i + 1] = SuffixType::LeftMostSmall;
            }

            type_map[i] = SuffixType::Large;
        }
    }

    let mut idx = 1;
    // fill the bucket heads and tails
    for (i, size) in bucket_sizes.iter().enumerate() {
        bucket_heads[i] = idx;
        idx += *size;
        bucket_tails[i] = idx - 1;
    }

    let mut approx_sa = {       // build the first (approximate) SA
        let mut vec = vec![MARKER; input.len() + 1];
        let mut bucket_tails = bucket_tails.clone();
        for (i, byte) in input.iter().enumerate() {
            if type_map[i] != SuffixType::LeftMostSmall {
                continue        // ignore the L and S types (for now)
            }

            let bucket_idx = *byte as usize;
            vec[bucket_tails[bucket_idx]] = i;
            bucket_tails[bucket_idx] -= 1;
        }

        vec[0] = input.len();       // null byte
        vec
    };

    fn induced_sort_large(input: &[u8], approx_sa: &mut [usize],
                          mut bucket_heads: Vec<usize>, type_map: &[SuffixType]) {
        for i in 0..approx_sa.len() {
            if approx_sa[i] == MARKER || approx_sa[i] == 0 {
                continue
            }

            let j = approx_sa[i] - 1;
            if type_map[j] != SuffixType::Large {
                continue    // only the L-types
            }

            let bucket_idx = input[j] as usize;
            approx_sa[bucket_heads[bucket_idx]] = j;
            bucket_heads[bucket_idx] += 1;
        }
    }

    fn induced_sort_small(input: &[u8], approx_sa: &mut [usize],
                          mut bucket_tails: Vec<usize>, type_map: &[SuffixType]) {
        for i in (0..approx_sa.len()).rev() {
            if approx_sa[i] == MARKER || approx_sa[i] == 0 {
                continue
            }

            let j = approx_sa[i] - 1;
            if type_map[j] == SuffixType::Large {
                continue    // only the S-types (and LMS-types as per our grouping)
            }

            let bucket_idx = input[j] as usize;
            approx_sa[bucket_tails[bucket_idx]] = j;
            bucket_tails[bucket_idx] -= 1;
        }
    }

    induced_sort_large(&input, &mut approx_sa, bucket_heads.clone(), &type_map);
    induced_sort_small(&input, &mut approx_sa, bucket_tails.clone(), &type_map);

    fn is_equal_lms(input: &[u8], type_map: &[SuffixType], j: usize, k: usize) -> bool {
        if j == input.len() || k == input.len() {
            return false    // null byte
        }

        for i in 0..(input.len() + 1) {
            let first_lms = type_map[i + j] == SuffixType::LeftMostSmall;
            let second_lms = type_map[i + k] == SuffixType::LeftMostSmall;
            if first_lms && second_lms && i > 0 {
                return true
            } else if (first_lms != second_lms) || (input[i + j] != input[i + k]) {
                return false
            }
        }

        false
    }

    let mut byte = 0;
    let lms_bytes = {
        let mut approx_sa = approx_sa;
        let mut last_idx = approx_sa[0];
        let mut lms_bytes = vec![input.len(); input.len() + 1];
        lms_bytes[last_idx] = 0;

        for count in approx_sa.drain(1..) {
            let idx = if count == MARKER { input.len() } else { count };
            if type_map[idx] != SuffixType::LeftMostSmall {
                continue
            }

            if !is_equal_lms(&input, &type_map, last_idx, idx) {
                byte += 1;
            }

            last_idx = idx;
            lms_bytes[idx] = byte;
        }

        lms_bytes
    };

    let summary_index = lms_bytes.iter().enumerate().filter_map(|(i, b)| {
        if *b == input.len() { None } else { Some(i) }
    }).collect::<Vec<_>>();

    let mut final_sa = {
        let mut bucket_tails = bucket_tails.clone();
        let summary_sa = if byte == summary_index.len() - 1 {
            let mut sum_sa = vec![0; summary_index.len() + 1];
            sum_sa[0] = summary_index.len();
            for i in 0..summary_index.len() {
                let idx = lms_bytes[summary_index[i]] as usize;
                sum_sa[idx + 1] = i;
            }

            sum_sa
        } else {
            suffix_array(summary_index.iter().map(|i| lms_bytes[*i] as u8).collect())
        };

        let mut suffix_idx = vec![MARKER; input.len() + 1];
        for i in (2..summary_sa.len()).rev() {
            let idx = summary_index[summary_sa[i]];
            let bucket_idx = input[idx] as usize;
            suffix_idx[bucket_tails[bucket_idx]] = idx;
            bucket_tails[bucket_idx] -= 1;
        }

        suffix_idx[0] = input.len();
        suffix_idx
    };

    induced_sort_large(&input, &mut final_sa, bucket_heads, &type_map);
    induced_sort_small(&input, &mut final_sa, bucket_tails, &type_map);

    final_sa
}
<commit_msg>Fix the buggy recursion (always prefer usize), and some comments<commit_after>use std::collections::HashMap;
use std::usize;

// Prefer this for marking, instead of Option<usize> (as it requires additional byte of memory)
const MARKER: usize = usize::MAX;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SuffixType {
    Small,
    Large,
    LeftMostSmall,
}

// Generates a suffix array and sorts them using the "induced sorting" method
// (Thanks to the python implementation in http://zork.net/~st/jottings/sais.html)
pub fn suffix_array(input: Vec<usize>) -> Vec<usize> {
    let mut type_map = vec![SuffixType::Small; input.len() + 1];
    let mut bucket_sizes = HashMap::new();      // byte frequency

    type_map[input.len()] = SuffixType::LeftMostSmall;      // null byte
    type_map[input.len() - 1] = SuffixType::Large;          // should be L-type
    bucket_sizes.insert(input[input.len() - 1], 1);

    // group the bytes into S-type or L-type (also mark LMS types)
    for i in (0..input.len() - 1).rev() {
        let mut c = bucket_sizes.entry(input[i]).or_insert(0);
        *c += 1;

        if input[i] > input[i + 1] ||
           (input[i] == input[i + 1] && type_map[i + 1] == SuffixType::Large) {
            if type_map[i + 1] == SuffixType::Small {
                type_map[i + 1] = SuffixType::LeftMostSmall;
            }

            type_map[i] = SuffixType::Large;
        }
    }

    let mut idx = 1;
    let mut bytes = bucket_sizes.keys().map(|i| *i).collect::<Vec<_>>();
    bytes.sort();

    let max_byte = bytes[bytes.len() - 1];
    let mut bucket_heads = vec![0; max_byte + 1];
    let mut bucket_tails = vec![0; max_byte + 1];

    // fill the bucket heads and tails (heads for L-types and tails for S-types)
    let mut j = 0;
    for i in 0..(max_byte + 1) {
        bucket_heads[i] = idx;
        if i == bytes[j] {
            idx += bucket_sizes.remove(&bytes[j]).unwrap();
            j += 1;
        }

        bucket_tails[i] = idx - 1;
    }

    let mut approx_sa = {       // build the first (approximate) SA
        let mut vec = vec![MARKER; input.len() + 1];
        let mut bucket_tails = bucket_tails.clone();
        for (i, byte) in input.iter().enumerate() {
            if type_map[i] != SuffixType::LeftMostSmall {
                continue        // ignore the L and S types (for now)
            }

            let bucket_idx = *byte;
            vec[bucket_tails[bucket_idx]] = i;
            bucket_tails[bucket_idx] -= 1;
        }

        vec[0] = input.len();       // null byte
        vec
    };

    fn induced_sort_large(input: &[usize], approx_sa: &mut [usize],
                          mut bucket_heads: Vec<usize>, type_map: &[SuffixType]) {
        for i in 0..approx_sa.len() {
            if approx_sa[i] == MARKER || approx_sa[i] == 0 {
                continue
            }

            let j = approx_sa[i] - 1;
            if type_map[j] != SuffixType::Large {
                continue    // only the L-types
            }

            let bucket_idx = input[j];
            approx_sa[bucket_heads[bucket_idx]] = j;
            bucket_heads[bucket_idx] += 1;
        }
    }

    fn induced_sort_small(input: &[usize], approx_sa: &mut [usize],
                          mut bucket_tails: Vec<usize>, type_map: &[SuffixType]) {
        for i in (0..approx_sa.len()).rev() {
            if approx_sa[i] == MARKER || approx_sa[i] == 0 {
                continue
            }

            let j = approx_sa[i] - 1;
            if type_map[j] == SuffixType::Large {
                continue    // only the S-types (and LMS-types as per our grouping)
            }

            let bucket_idx = input[j];
            approx_sa[bucket_tails[bucket_idx]] = j;
            bucket_tails[bucket_idx] -= 1;
        }
    }

    induced_sort_large(&input, &mut approx_sa, bucket_heads.clone(), &type_map);
    induced_sort_small(&input, &mut approx_sa, bucket_tails.clone(), &type_map);

    // Check whether the string between two LMS bytes have the same lengths and same contents
    fn is_equal_lms(input: &[usize], type_map: &[SuffixType], j: usize, k: usize) -> bool {
        if j == input.len() || k == input.len() {
            return false    // null byte
        }

        for i in 0..(input.len() + 1) {
            let first_lms = type_map[i + j] == SuffixType::LeftMostSmall;
            let second_lms = type_map[i + k] == SuffixType::LeftMostSmall;
            if first_lms && second_lms && i > 0 {
                return true
            } else if (first_lms != second_lms) || (input[i + j] != input[i + k]) {
                return false
            }
        }

        false
    }

    let mut byte = 0;
    let lms_bytes = {
        let mut approx_sa = approx_sa;      // we no longer need this
        let mut last_idx = approx_sa[0];
        let mut lms_bytes = vec![input.len(); input.len() + 1];
        lms_bytes[last_idx] = 0;

        for count in approx_sa.drain(1..) {
            let idx = if count == MARKER { input.len() } else { count };
            if type_map[idx] != SuffixType::LeftMostSmall {
                continue
            }

            if !is_equal_lms(&input, &type_map, last_idx, idx) {
                byte += 1;
            }

            last_idx = idx;
            lms_bytes[idx] = byte;
        }

        lms_bytes
    };

    // filter the modified bytes
    let summary_index = lms_bytes.iter().enumerate().filter_map(|(i, b)| {
        if *b == input.len() { None } else { Some(i) }
    }).collect::<Vec<_>>();

    let mut final_sa = {        // build the summary SA (using the usable bytes)
        let mut bucket_tails = bucket_tails.clone();
        let summary_sa = if byte == summary_index.len() - 1 {
            let mut sum_sa = vec![0; summary_index.len() + 1];
            sum_sa[0] = summary_index.len();
            for i in 0..summary_index.len() {
                let idx = lms_bytes[summary_index[i]];
                sum_sa[idx + 1] = i;
            }

            sum_sa
        } else {
            suffix_array(summary_index.iter().map(|i| lms_bytes[*i]).collect::<Vec<_>>())
        };

        let mut suffix_idx = vec![MARKER; input.len() + 1];
        for i in (2..summary_sa.len()).rev() {
            let idx = summary_index[summary_sa[i]];
            let bucket_idx = input[idx];
            suffix_idx[bucket_tails[bucket_idx]] = idx;
            bucket_tails[bucket_idx] -= 1;
        }

        suffix_idx[0] = input.len();
        suffix_idx
    };

    induced_sort_large(&input, &mut final_sa, bucket_heads, &type_map);
    induced_sort_small(&input, &mut final_sa, bucket_tails, &type_map);

    final_sa
}
<|endoftext|>


<commit_before>
use piston_window::*;
use common::{ParamType, MoveDestination, GameEndState};
use chrono::Duration;

struct Block<'a> {
    name: &'a str,
    num: u32,
    old_num: u32,
    hotkey: char,
    selected: bool,
    min_val: u32,
    max_val: u32,
    param_type: ParamType,
}

impl<'a> Block<'a> {
    pub fn new(name: &'a str,
               num: u32,
               hotkey: char,
               min_val: u32,
               max_val: u32,
               param_type: ParamType) -> Block<'a>
    {
        Block {
            name: name,
            num: num,
            old_num: num,
            hotkey: hotkey,
            selected: false,
            min_val: min_val,
            max_val: max_val,
            param_type: param_type,
        }
    }

    pub fn draw(&self,
                context: Context,
                graphics: &mut G2d,
                rect: &mut [u32; 4],
                glyps: &mut Glyphs)
    {
        let margin = 10;
        let text_height = 20;
        let block_height = 30;
        let text_padding = 7;
        let color = if self.selected {
            [0.0, 1.0, 0.0, 1.0]
        } else {
            [1.0, 1.0, 1.0, 1.0]
        };
        rect[1] += 20;
        rectangle(color,
                  [
                    (rect[0] + margin) as f64,
                    (rect[1]) as f64,
                    (rect[2] - 2*margin) as f64,
                    block_height as f64
                  ],
                  context.transform,
                  graphics);
        rect[1] += block_height;
        let transform = context.transform.trans((rect[0] + margin + text_padding) as f64,
                                                (rect[1] - text_padding) as f64);
        text([0.0, 0.0, 0.0, 1.0],
             text_height,
             &*format!("{}: {}", self.name, self.num),
             glyps,
             transform,
             graphics);
        rect[1] += margin + text_height/2;
        let transform = context.transform.trans((rect[0] + margin) as f64,
                                                (rect[1]) as f64);
        let s = if self.selected {
            format!("Use arrows, press '{}' to apply changes", self.hotkey)
        } else {
            format!("Press '{}' to change", self.hotkey)
        };
        text([1.0, 1.0, 1.0, 1.0],
             text_height,
             &*s,
             glyps,
             transform,
             graphics);
    }

    pub fn inc_safe(&mut self) {
        if self.num < self.max_val {
            self.num += 1;
        }
    }

    pub fn dec_safe(&mut self) {
        if self.num > self.min_val {
            self.num -= 1;
        }
    }

    pub fn apply_changes(&mut self) {
        self.old_num = self.num;
    }

    pub fn discard_changes(&mut self) {
        self.num = self.old_num;
    }
}

pub struct UI<'a> {
    blocks: Vec<Block<'a>>,
    selected_block: i32,
}

impl<'a> UI<'a> {
    pub fn new(height: u32, width: u32, mines: u32) -> UI<'a> {
        UI {
            blocks: vec![Block::new("Field width", width, 'W', 5, 50, ParamType::Width),
                         Block::new("Field height", height, 'H', 5, 50, ParamType::Height),
                         Block::new("Mines", mines, 'M', 1, 2500, ParamType::Mines),
            ],
            selected_block: -1,
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            mut rect: [u32; 4],
            glyps: &mut Glyphs,
            mines_total: u32,
            mines_marked: u32,
            duration : Duration)
    {
        for b in self.blocks.iter() {
            b.draw(context, graphics, &mut rect, glyps);
        }

        let transform = context.transform.trans((rect[0]+10) as f64,
                                                 (rect[1]+27) as f64);
        text([1.0, 1.0, 1.0, 1.0],
             20,
             &*format!("{} marked {} remaining", mines_marked, mines_total as i32 - mines_marked as i32),
             glyps,
             transform,
             graphics);

        let transform = context.transform.trans((rect[0]+10) as f64,
                                                 (rect[1]+27*2) as f64);
        let total_seconds = duration.num_seconds();
        let mins = total_seconds / 60;
        let rem_seconds = total_seconds - mins*60;

        text([1.0, 1.0, 1.0, 1.0],
             20,
             &*format!("{}:{}", mins, rem_seconds),
             glyps,
             transform,
             graphics);
    }

    pub fn proc_key(&mut self, block: ParamType) -> Option<u32> {
        if self.selected_block >= 0 {
            let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
            if selected.param_type == block {
                selected.selected = false;
                selected.apply_changes();
                self.selected_block = -1;
                return Some(selected.num);
            }
        }
        for i in 0..self.blocks.len() {
            let item = self.blocks.get_mut(i).unwrap();
            let b = item.param_type == block;
            item.selected = b;
            if b {
                self.selected_block = i as i32;
            } else {
                item.discard_changes();
            }
        }
        None
    }

    pub fn change_selected(&mut self, dest: MoveDestination) {
        assert!(self.selected_block >= 0);
        let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
        match dest {
            MoveDestination::Up | MoveDestination::Right => selected.inc_safe(),
            MoveDestination::Down | MoveDestination::Left => selected.dec_safe()
        }
    }
}

pub struct EndMessage<'a> {
    visible: bool,
    win: bool,
    message: &'a str
}

static EM_TEXT_BIG      : u32 = 40;
static EM_TEXT_SMALL    : u32 = 20;
static EM_TEXT_PADDING  : u32 = 5;
static EM_BORDER_WIDTH  : u32 = 3;
static EM_BORDER_WIDTH_2: u32 = 6;

static RETRY_MSG: &'static str = "Press 'R' to play again";

impl<'a> EndMessage<'a> {
    pub fn new() -> EndMessage<'a> {
        EndMessage {
            visible: false,
            win: false,
            message: "Ready",
        }
    }

    pub fn show( &mut self, end_state: GameEndState ) {
        self.win = match end_state {
            GameEndState::Win => true,
            _                 => false };
        self.visible = true;
        self.message = if self.win {
                "You WIN :)"
            } else {
                "Game over :("
            };
    }

    pub fn hide( &mut self ) {
        self.visible = false;
    }

    /// Message Box's size. (width,height).
    pub fn size() -> (u32,u32) {
        (
            350,
            (EM_TEXT_BIG + EM_TEXT_SMALL + (EM_TEXT_PADDING*4) + (EM_BORDER_WIDTH*2))
        )
    }

    pub fn draw(&self,
        context: Context,
        graphics: &mut G2d,
        rect: [u32; 4],
        glyps: &mut Glyphs)
    {
        if !self.visible
        {
            return;
        }

        let border_color = if self.win {
            [0.0, 0.0, 1.0, 1.0]    // Win : Blue
        } else {
            [1.0, 1.0, 0.0, 1.0]    // Lose: yellow
        };

        // draw border
        rectangle(border_color,
            [
                (rect[0]) as f64,
                (rect[1]) as f64,
                (rect[2]) as f64,
                (rect[3]) as f64
            ],
            context.transform,
            graphics);

        // draw background
        rectangle( [1.0, 1.0, 1.0, 1.0],
            [
                (rect[0] +EM_BORDER_WIDTH) as f64,
                (rect[1] +EM_BORDER_WIDTH) as f64,
                (rect[2] -EM_BORDER_WIDTH_2) as f64,
                (rect[3] -EM_BORDER_WIDTH_2) as f64
            ],
            context.transform,
            graphics);

        // Draw game result message
        let trans_msg = context.transform.trans(
            (rect[0] + EM_BORDER_WIDTH + EM_TEXT_PADDING) as f64,
            (rect[1] + EM_BORDER_WIDTH + EM_TEXT_PADDING + EM_TEXT_BIG) as f64);

        text([0.0, 0.0, 0.0, 1.0],
             EM_TEXT_BIG,
             &*self.message,
             glyps,
             trans_msg,
             graphics);

        // Draw 'play again' message
        let trans_retry = context.transform.trans(
            (rect[0] + EM_BORDER_WIDTH + EM_TEXT_PADDING) as f64,
            (rect[1] + EM_BORDER_WIDTH + EM_TEXT_PADDING*2 + EM_TEXT_BIG + EM_TEXT_SMALL) as f64);
        text([0.0, 0.0, 0.0, 1.0],
             EM_TEXT_SMALL,
             &*RETRY_MSG,
             glyps,
             trans_retry,
             graphics);
    }
}
<commit_msg>imp(timer): Second hand now always displays two digits<commit_after>
use piston_window::*;
use common::{ParamType, MoveDestination, GameEndState};
use chrono::Duration;

struct Block<'a> {
    name: &'a str,
    num: u32,
    old_num: u32,
    hotkey: char,
    selected: bool,
    min_val: u32,
    max_val: u32,
    param_type: ParamType,
}

impl<'a> Block<'a> {
    pub fn new(name: &'a str,
               num: u32,
               hotkey: char,
               min_val: u32,
               max_val: u32,
               param_type: ParamType) -> Block<'a>
    {
        Block {
            name: name,
            num: num,
            old_num: num,
            hotkey: hotkey,
            selected: false,
            min_val: min_val,
            max_val: max_val,
            param_type: param_type,
        }
    }

    pub fn draw(&self,
                context: Context,
                graphics: &mut G2d,
                rect: &mut [u32; 4],
                glyps: &mut Glyphs)
    {
        let margin = 10;
        let text_height = 20;
        let block_height = 30;
        let text_padding = 7;
        let color = if self.selected {
            [0.0, 1.0, 0.0, 1.0]
        } else {
            [1.0, 1.0, 1.0, 1.0]
        };
        rect[1] += 20;
        rectangle(color,
                  [
                    (rect[0] + margin) as f64,
                    (rect[1]) as f64,
                    (rect[2] - 2*margin) as f64,
                    block_height as f64
                  ],
                  context.transform,
                  graphics);
        rect[1] += block_height;
        let transform = context.transform.trans((rect[0] + margin + text_padding) as f64,
                                                (rect[1] - text_padding) as f64);
        text([0.0, 0.0, 0.0, 1.0],
             text_height,
             &*format!("{}: {}", self.name, self.num),
             glyps,
             transform,
             graphics);
        rect[1] += margin + text_height/2;
        let transform = context.transform.trans((rect[0] + margin) as f64,
                                                (rect[1]) as f64);
        let s = if self.selected {
            format!("Use arrows, press '{}' to apply changes", self.hotkey)
        } else {
            format!("Press '{}' to change", self.hotkey)
        };
        text([1.0, 1.0, 1.0, 1.0],
             text_height,
             &*s,
             glyps,
             transform,
             graphics);
    }

    pub fn inc_safe(&mut self) {
        if self.num < self.max_val {
            self.num += 1;
        }
    }

    pub fn dec_safe(&mut self) {
        if self.num > self.min_val {
            self.num -= 1;
        }
    }

    pub fn apply_changes(&mut self) {
        self.old_num = self.num;
    }

    pub fn discard_changes(&mut self) {
        self.num = self.old_num;
    }
}

pub struct UI<'a> {
    blocks: Vec<Block<'a>>,
    selected_block: i32,
}

impl<'a> UI<'a> {
    pub fn new(height: u32, width: u32, mines: u32) -> UI<'a> {
        UI {
            blocks: vec![Block::new("Field width", width, 'W', 5, 50, ParamType::Width),
                         Block::new("Field height", height, 'H', 5, 50, ParamType::Height),
                         Block::new("Mines", mines, 'M', 1, 2500, ParamType::Mines),
            ],
            selected_block: -1,
        }
    }

    pub fn draw(&mut self,
            context: Context,
            graphics: &mut G2d,
            mut rect: [u32; 4],
            glyps: &mut Glyphs,
            mines_total: u32,
            mines_marked: u32,
            duration : Duration)
    {
        for b in self.blocks.iter() {
            b.draw(context, graphics, &mut rect, glyps);
        }

        let transform = context.transform.trans((rect[0]+10) as f64,
                                                 (rect[1]+27) as f64);
        text([1.0, 1.0, 1.0, 1.0],
             20,
             &*format!("{} marked {} remaining", mines_marked, mines_total as i32 - mines_marked as i32),
             glyps,
             transform,
             graphics);

        let transform = context.transform.trans((rect[0]+10) as f64,
                                                 (rect[1]+27*2) as f64);
        let total_seconds = duration.num_seconds();
        let mins = total_seconds / 60;
        let rem_seconds = total_seconds - mins*60;

        text([1.0, 1.0, 1.0, 1.0],
             20,
             &*format!("{}:{:02}", mins, rem_seconds),
             glyps,
             transform,
             graphics);
    }

    pub fn proc_key(&mut self, block: ParamType) -> Option<u32> {
        if self.selected_block >= 0 {
            let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
            if selected.param_type == block {
                selected.selected = false;
                selected.apply_changes();
                self.selected_block = -1;
                return Some(selected.num);
            }
        }
        for i in 0..self.blocks.len() {
            let item = self.blocks.get_mut(i).unwrap();
            let b = item.param_type == block;
            item.selected = b;
            if b {
                self.selected_block = i as i32;
            } else {
                item.discard_changes();
            }
        }
        None
    }

    pub fn change_selected(&mut self, dest: MoveDestination) {
        assert!(self.selected_block >= 0);
        let selected = self.blocks.get_mut(self.selected_block as usize).unwrap();
        match dest {
            MoveDestination::Up | MoveDestination::Right => selected.inc_safe(),
            MoveDestination::Down | MoveDestination::Left => selected.dec_safe()
        }
    }
}

pub struct EndMessage<'a> {
    visible: bool,
    win: bool,
    message: &'a str
}

static EM_TEXT_BIG      : u32 = 40;
static EM_TEXT_SMALL    : u32 = 20;
static EM_TEXT_PADDING  : u32 = 5;
static EM_BORDER_WIDTH  : u32 = 3;
static EM_BORDER_WIDTH_2: u32 = 6;

static RETRY_MSG: &'static str = "Press 'R' to play again";

impl<'a> EndMessage<'a> {
    pub fn new() -> EndMessage<'a> {
        EndMessage {
            visible: false,
            win: false,
            message: "Ready",
        }
    }

    pub fn show( &mut self, end_state: GameEndState ) {
        self.win = match end_state {
            GameEndState::Win => true,
            _                 => false };
        self.visible = true;
        self.message = if self.win {
                "You WIN :)"
            } else {
                "Game over :("
            };
    }

    pub fn hide( &mut self ) {
        self.visible = false;
    }

    /// Message Box's size. (width,height).
    pub fn size() -> (u32,u32) {
        (
            350,
            (EM_TEXT_BIG + EM_TEXT_SMALL + (EM_TEXT_PADDING*4) + (EM_BORDER_WIDTH*2))
        )
    }

    pub fn draw(&self,
        context: Context,
        graphics: &mut G2d,
        rect: [u32; 4],
        glyps: &mut Glyphs)
    {
        if !self.visible
        {
            return;
        }

        let border_color = if self.win {
            [0.0, 0.0, 1.0, 1.0]    // Win : Blue
        } else {
            [1.0, 1.0, 0.0, 1.0]    // Lose: yellow
        };

        // draw border
        rectangle(border_color,
            [
                (rect[0]) as f64,
                (rect[1]) as f64,
                (rect[2]) as f64,
                (rect[3]) as f64
            ],
            context.transform,
            graphics);

        // draw background
        rectangle( [1.0, 1.0, 1.0, 1.0],
            [
                (rect[0] +EM_BORDER_WIDTH) as f64,
                (rect[1] +EM_BORDER_WIDTH) as f64,
                (rect[2] -EM_BORDER_WIDTH_2) as f64,
                (rect[3] -EM_BORDER_WIDTH_2) as f64
            ],
            context.transform,
            graphics);

        // Draw game result message
        let trans_msg = context.transform.trans(
            (rect[0] + EM_BORDER_WIDTH + EM_TEXT_PADDING) as f64,
            (rect[1] + EM_BORDER_WIDTH + EM_TEXT_PADDING + EM_TEXT_BIG) as f64);

        text([0.0, 0.0, 0.0, 1.0],
             EM_TEXT_BIG,
             &*self.message,
             glyps,
             trans_msg,
             graphics);

        // Draw 'play again' message
        let trans_retry = context.transform.trans(
            (rect[0] + EM_BORDER_WIDTH + EM_TEXT_PADDING) as f64,
            (rect[1] + EM_BORDER_WIDTH + EM_TEXT_PADDING*2 + EM_TEXT_BIG + EM_TEXT_SMALL) as f64);
        text([0.0, 0.0, 0.0, 1.0],
             EM_TEXT_SMALL,
             &*RETRY_MSG,
             glyps,
             trans_retry,
             graphics);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
#[macro_use] extern crate quote;

use syn::*;
use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};

#[proc_macro_attribute]
pub fn entrypoint(_args: TokenStream, input: TokenStream) -> TokenStream {
    // TODO: support #[entrypoint(apply=run, default=init)] when attached to `impl`
    // let args_path = parse_path(&args.to_string()).ok();
    let item = parse_item(&input.to_string())
        .expect("#[entrypoint] must be attached to a function");

    let entrypoint = Entrypoint::from_item(item);
    entrypoint.output().parse().expect("#[entrypoint] failed to parse output")
}

struct Entrypoint {
   fn_name: Ident,
   self_type: Option<Ty>,
   input_type: Ty,
   item: Item,
}

impl Entrypoint {
    fn from_item(item: Item) -> Self {
        let item_clone = item.clone();
        match item.node {
            ItemKind::Fn(fn_decl, unsafety, _constness, _abi, generics, _block) => {
                assert_eq!(unsafety, Unsafety::Normal, "Unsafe #[entrypoint] functions are not supported");
                assert_generics_empty(&generics);

                assert_eq!(fn_decl.inputs.len(), 1, "#[entrypoint] function may only take one arg");
                let input_type = match fn_decl.inputs[0] {
                    FnArg::SelfRef(..) | FnArg::SelfValue(..) => panic!("Attach #[entrypoint] to impl block to support &self arg"),
                    FnArg::Captured(_, ref ty) => ty.clone(),
                    FnArg::Ignored(ref ty) => ty.clone(),
                };

                // TODO: assert that fn_decl.output includes a `Result` token

                Entrypoint {
                    fn_name: item.ident,
                    self_type: None,
                    input_type: input_type,
                    item: item_clone,
                }
            }

            ItemKind::Impl(unsafety, _polarity, generics, _path, ty, impl_items) => {
                assert_eq!(unsafety, Unsafety::Normal, "Unsafe #[entrypoint] impls are not supported");
                assert_generics_empty(&generics);
                // TODO: assert that `ty` isn't of type `Algo` which would cause name collisions

                let method_name = Ident::new("apply");

                let fn_decl = impl_items.iter()
                    .filter_map(|item| {
                        match item.node {
                            ImplItemKind::Method(ref sig, _) => {
                                Some((&item.ident, &sig.decl))
                            }
                            _ => None
                        }
                    })
                    .find(|pair| pair.0 == &method_name)
                    .map(|pair| pair.1.clone() )
                    .expect("#[entrypoint] impl must include 'apply' method");

                assert_eq!(fn_decl.inputs.len(), 2, "#[entrypoint] within an impl must take &self and an input arg");
                let input_type = match fn_decl.inputs[1] {
                    FnArg::SelfRef(..) | FnArg::SelfValue(..) => panic!("Are you using self as a second argument?"),
                    FnArg::Captured(_, ref ty) => ty.clone(),
                    FnArg::Ignored(ref ty) => ty.clone(),
                };

                // TODO: assert that fn_decl.output includes a `Result` token

                Entrypoint {
                    fn_name: method_name,
                    self_type: Some(ty.as_ref().clone()),
                    input_type: input_type,
                    item: item_clone,
                }
            }

            _ => panic!("#[entrypoint]` attribute must be attached to a function or impl"),
        }
    }

    fn output(&self) -> Tokens {
        let mut input_type_tokens = Tokens::new();
        self.input_type.to_tokens(&mut input_type_tokens);

        match input_type_tokens.as_str() {
            "& str" | "String" => self.impl_entrypoint(Ident::new("apply_str"), "&str"),
            "& [ u8 ]" | "Vec < u8 >" => self.impl_entrypoint(Ident::new("apply_bytes"), "&[u8]"),
            "& Value" => self.impl_entrypoint(Ident::new("apply_json"), "&Value"),
            "AlgoInput" => self.impl_entrypoint(Ident::new("apply"), "AlgoInput"),
            _ => self.impl_decoded_entrypoint(),
        }
    }

    fn impl_entrypoint(&self, apply_fn: Ident, input_type: &str) -> Tokens {
        let ref item = self.item;
        let ref fn_name = self.fn_name;
        let input_type = parse_type(input_type).unwrap();

        // TODO: if specialization hasn't landed, consider generating the auto-boxing code for Serialize types
        match self.self_type {
            Some(ref self_type) => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    pub struct Algo(#self_type);
                    impl EntryPoint for Algo {
                        fn #apply_fn(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            (self.0).#fn_name(input.into()).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }
                    impl Default for Algo {
                        fn default() -> Self {
                            Algo(Default::default())
                        }
                    }

                    #item
                }
            }
            None => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    #[derive(Default)] pub struct Algo;
                    impl EntryPoint for Algo {
                        fn #apply_fn(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            #fn_name(input.into()).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    #item
                }
            }
        }
    }

    fn impl_decoded_entrypoint(&self) -> Tokens {
        let ref fn_name = self.fn_name;
        let ref input_type = self.input_type;
        let ref item = self.item;

        match self.self_type {
            Some(ref self_type) => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    pub struct Algo(#self_type);
                    impl DecodedEntryPoint for Algo {
                        type Input = #input_type;
                        fn apply_decoded(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            (self.0).#fn_name(input).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    impl Default for Algo {
                        fn default() -> Self {
                            Algo(Default::default())
                        }
                    }

                    #item
                }
            }
            None => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    #[derive(Default)] pub struct Algo;
                    impl DecodedEntryPoint for Algo {
                        type Input = #input_type;
                        fn apply_decoded(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            #fn_name(input).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    #item
                }
            }
        }
    }

}

fn assert_generics_empty(generics: &Generics) {
    assert!(
        generics.lifetimes.is_empty() &&
        generics.ty_params.is_empty() &&
        generics.where_clause.predicates.is_empty(),
        "Generics are not supported on the #[algo_entrypoint] function"
    )
}
<commit_msg>proc_macro stabilizes with 1.29<commit_after>extern crate proc_macro;
extern crate syn;
#[macro_use] extern crate quote;

use syn::*;
use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};

#[proc_macro_attribute]
pub fn entrypoint(_args: TokenStream, input: TokenStream) -> TokenStream {
    // TODO: support #[entrypoint(apply=run, default=init)] when attached to `impl`
    // let args_path = parse_path(&args.to_string()).ok();
    let item = parse_item(&input.to_string())
        .expect("#[entrypoint] must be attached to a function");

    let entrypoint = Entrypoint::from_item(item);
    entrypoint.output().parse().expect("#[entrypoint] failed to parse output")
}

struct Entrypoint {
   fn_name: Ident,
   self_type: Option<Ty>,
   input_type: Ty,
   item: Item,
}

impl Entrypoint {
    fn from_item(item: Item) -> Self {
        let item_clone = item.clone();
        match item.node {
            ItemKind::Fn(fn_decl, unsafety, _constness, _abi, generics, _block) => {
                assert_eq!(unsafety, Unsafety::Normal, "Unsafe #[entrypoint] functions are not supported");
                assert_generics_empty(&generics);

                assert_eq!(fn_decl.inputs.len(), 1, "#[entrypoint] function may only take one arg");
                let input_type = match fn_decl.inputs[0] {
                    FnArg::SelfRef(..) | FnArg::SelfValue(..) => panic!("Attach #[entrypoint] to impl block to support &self arg"),
                    FnArg::Captured(_, ref ty) => ty.clone(),
                    FnArg::Ignored(ref ty) => ty.clone(),
                };

                // TODO: assert that fn_decl.output includes a `Result` token

                Entrypoint {
                    fn_name: item.ident,
                    self_type: None,
                    input_type: input_type,
                    item: item_clone,
                }
            }

            ItemKind::Impl(unsafety, _polarity, generics, _path, ty, impl_items) => {
                assert_eq!(unsafety, Unsafety::Normal, "Unsafe #[entrypoint] impls are not supported");
                assert_generics_empty(&generics);
                // TODO: assert that `ty` isn't of type `Algo` which would cause name collisions

                let method_name = Ident::new("apply");

                let fn_decl = impl_items.iter()
                    .filter_map(|item| {
                        match item.node {
                            ImplItemKind::Method(ref sig, _) => {
                                Some((&item.ident, &sig.decl))
                            }
                            _ => None
                        }
                    })
                    .find(|pair| pair.0 == &method_name)
                    .map(|pair| pair.1.clone() )
                    .expect("#[entrypoint] impl must include 'apply' method");

                assert_eq!(fn_decl.inputs.len(), 2, "#[entrypoint] within an impl must take &self and an input arg");
                let input_type = match fn_decl.inputs[1] {
                    FnArg::SelfRef(..) | FnArg::SelfValue(..) => panic!("Are you using self as a second argument?"),
                    FnArg::Captured(_, ref ty) => ty.clone(),
                    FnArg::Ignored(ref ty) => ty.clone(),
                };

                // TODO: assert that fn_decl.output includes a `Result` token

                Entrypoint {
                    fn_name: method_name,
                    self_type: Some(ty.as_ref().clone()),
                    input_type: input_type,
                    item: item_clone,
                }
            }

            _ => panic!("#[entrypoint]` attribute must be attached to a function or impl"),
        }
    }

    fn output(&self) -> Tokens {
        let mut input_type_tokens = Tokens::new();
        self.input_type.to_tokens(&mut input_type_tokens);

        match input_type_tokens.as_str() {
            "& str" | "String" => self.impl_entrypoint(Ident::new("apply_str"), "&str"),
            "& [ u8 ]" | "Vec < u8 >" => self.impl_entrypoint(Ident::new("apply_bytes"), "&[u8]"),
            "& Value" => self.impl_entrypoint(Ident::new("apply_json"), "&Value"),
            "AlgoInput" => self.impl_entrypoint(Ident::new("apply"), "AlgoInput"),
            _ => self.impl_decoded_entrypoint(),
        }
    }

    fn impl_entrypoint(&self, apply_fn: Ident, input_type: &str) -> Tokens {
        let ref item = self.item;
        let ref fn_name = self.fn_name;
        let input_type = parse_type(input_type).unwrap();

        // TODO: if specialization hasn't landed, consider generating the auto-boxing code for Serialize types
        match self.self_type {
            Some(ref self_type) => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    pub struct Algo(#self_type);
                    impl EntryPoint for Algo {
                        fn #apply_fn(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            (self.0).#fn_name(input.into()).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }
                    impl Default for Algo {
                        fn default() -> Self {
                            Algo(Default::default())
                        }
                    }

                    #item
                }
            }
            None => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    #[derive(Default)] pub struct Algo;
                    impl EntryPoint for Algo {
                        fn #apply_fn(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            #fn_name(input.into()).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    #item
                }
            }
        }
    }

    fn impl_decoded_entrypoint(&self) -> Tokens {
        let ref fn_name = self.fn_name;
        let ref input_type = self.input_type;
        let ref item = self.item;

        match self.self_type {
            Some(ref self_type) => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    pub struct Algo(#self_type);
                    impl DecodedEntryPoint for Algo {
                        type Input = #input_type;
                        fn apply_decoded(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            (self.0).#fn_name(input).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    impl Default for Algo {
                        fn default() -> Self {
                            Algo(Default::default())
                        }
                    }

                    #item
                }
            }
            None => {
                quote! {
                    use algorithmia::algo::{EntryPoint, AlgoOutput};
                    #[derive(Default)] pub struct Algo;
                    impl DecodedEntryPoint for Algo {
                        type Input = #input_type;
                        fn apply_decoded(&self, input: #input_type) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                            #fn_name(input).map(AlgoOutput::from).map_err(|err| err.into())
                        }
                    }

                    #item
                }
            }
        }
    }

}

fn assert_generics_empty(generics: &Generics) {
    assert!(
        generics.lifetimes.is_empty() &&
        generics.ty_params.is_empty() &&
        generics.where_clause.predicates.is_empty(),
        "Generics are not supported on the #[algo_entrypoint] function"
    )
}
<|endoftext|>