<commit_before>#![allow(dead_code, unused_variables)]

use std::collections::HashSet;
use std::io::Result;

use crate::proto::{Capability, MessageKind, ModeSet, RawMessage};
use crate::socket::IRCWriter;

enum AuthKind {
    SaslPlain(String, String),
    Pass(String),
    None,
}

#[derive(Debug, Copy, Clone)]
enum ConnectionState {
    Initial,
    CapabilityNegotiation,
    Authentication,
    Registration,
    Registered,
}

/// Represents Birch <-> IRC network connection
pub struct NetworkConnection<'a> {
    nick: String,
    user_modes: ModeSet,
    caps_pending: usize,
    caps: HashSet<Capability>,
    auth: AuthKind,

    state: ConnectionState,

    writer: &'a mut dyn IRCWriter,
    // user_fanout: &'a mut dyn IRCWriter,
}

impl<'a> NetworkConnection<'a> {
    pub fn new(nick: &str, writer: &'a mut dyn IRCWriter) -> Self {
        Self {
            nick: nick.to_string(),
            user_modes: ModeSet::empty(),
            caps_pending: 0,
            caps: HashSet::new(),
            auth: AuthKind::None,

            state: ConnectionState::Initial,

            writer,
        }
    }

    pub fn initialize(&mut self) -> Result<()> {
        self.transition_state(ConnectionState::Initial)
    }

    fn write_network(&mut self, command: &str, params: &[&str]) -> Result<()> {
        self.writer.write_message(&RawMessage::new(command, params))
    }

    fn transition_state(&mut self, next: ConnectionState) -> Result<()> {
        match &next {
            ConnectionState::Initial => {
                self.transition_state(ConnectionState::CapabilityNegotiation)?;
            }

            ConnectionState::CapabilityNegotiation => {
                self.write_network("CAP", &["LS", "302"])?;
            }

            ConnectionState::Authentication => match self.auth {
                AuthKind::SaslPlain(ref _user, ref _pass) => unimplemented!(),
                AuthKind::Pass(ref _pass) => unimplemented!(),
                AuthKind::None => {
                    self.transition_state(ConnectionState::Registration)?;
                }
            },

            ConnectionState::Registration => {
                // TODO: prevent unnecessary clone
                let nick = self.nick.clone();

                self.write_network("NICK", &[&nick])?;
                self.write_network("USER", &[&nick, "0", "*", &nick])?;

                self.transition_state(ConnectionState::Registered)?;
            }

            ConnectionState::Registered => (),
        }

        self.state = next;
        Ok(())
    }

    fn handle_cap_message(&mut self, msg: &RawMessage) -> Result<()> {
        let cmd = msg.param(1).unwrap_or("");
        match cmd {
            "LS" => {
                let caps = msg.trailing().unwrap_or("").split_whitespace();

                for cap_str in caps {
                    if let Some(cap) = Capability::from(cap_str) {
                        self.write_network("CAP", &["REQ", cap_str])?;
                        self.caps_pending += 1;
                    }
                }
            }

            "ACK" | "NAK" => {
                let cap = msg.trailing().and_then(Capability::from);

                if let Some(cap) = cap {
                    if cmd == "ACK" {
                        println!("CAP {:?} enabled", cap);
                        self.caps.insert(cap);
                    }
                }

                self.caps_pending -= 1;

                if self.caps_pending == 0 {
                    self.write_network("CAP", &["END"])?;
                    self.transition_state(ConnectionState::Authentication)?;
                }
            }

            // Not strictly necessary but if we want to support `cap-notify`
            "NEW" | "DEL" => unimplemented!(),

            _ => println!("ignoring unknown cap command: {}", msg),
        }

        Ok(())
    }

    pub fn handle(&mut self, msg: &RawMessage) -> Result<()> {
        let kind = MessageKind::from(msg);
        let should_forward = match kind {
            MessageKind::Ping => {
                let param = msg.param(0).unwrap_or("");
                self.write_network("PONG", &[param])?;
                false
            }

            MessageKind::Capability => {
                self.handle_cap_message(msg)?;
                // We have our own caps, don't send the server's.
                false
            }

            MessageKind::Numeric(code) => self.handle_numeric(code, msg)?,

            MessageKind::Privmsg | MessageKind::Notice => {
                if let Some(ref source) = msg.source {
                    let sender = &source.nick;
                    let msg = msg.trailing().unwrap_or("");

                    // Handle basic CTCP
                    match msg {
                        "\x01VERSION\x01" => {
                            // TODO: Probably should be configurable
                            let version = "\x01VERSION birch\x01";
                            self.write_network("NOTICE", &[sender, version])?;

                            false
                        }
                        _ => true,
                    }
                } else {
                    // Invalid msg? No sender.
                    false
                }
            }

            // MessageKind::Join => true,
            // MessageKind::Part => true,
            // MessageKind::Quit => true,

            // MessageKind::Kick => true,
            MessageKind::Mode => {
                if let Some(target) = msg.param(0) {
                    if target == self.nick {
                        let modes = msg.param(1).and_then(|s| self.user_modes.apply(s));
                        if let Some(modes) = modes {
                            self.user_modes = modes;
                        }
                    } else {
                        // TODO: channel modes, other users
                    }
                }
                true
            }

            _ => {
                println!("Unhandled message: {:?}", msg);

                true
            }
        };

        if should_forward {
            // TODO: send message to user_fanout
        }

        Ok(())
    }

    fn handle_numeric(&mut self, code: u16, msg: &RawMessage) -> Result<bool> {
        let should_forward = match code {
            // :server 001 nick :welcome message
            1 => false,

            // ISUPPORT
            5 => false,

            2 |      // Your host
            3 |      // Server created at
            4 |      // Server info
            250 |    // Highest user count
            251 |    // User count
            252 |    // Oper count
            253 |    // Unknown connections
            254 |    // Channel count
            255 |    // Client count
            265 |    // Local users
            266 => { // Global users
                // TODO: Update network buffer state
                false
            },

            305 => { // Clear AWAY
                false
            }

            306 => { // Set AWAY
                false
            }

            329 => { // :server.com 329 nick #chan <epoch chan creation>
                false
            }

            // :server.com 331 nick #chan :no topic is set
            331 => {
                false
            }

            // :server.com 332 nick #chan :channel topic
            332 => {
                false
            }

            // :server.com 333 nick #chan who_set <epochtime>
            333 => {
                false
            }

            353 |    // :server.com 353 nick @ #chan :nick1 nick2
            366 => { // :server.com 366 nick #chan :End of /NAMES
                false
            }

            375 |    // Begin MOTD
            422 => { // MOTD file is missing
                // TODO: Clear MOTD
                false
            }

            372 |    // MOTD
            376 => { // End MOTD
                // TODO: MOTD
                false
            }

            432 |
            433 => { // :irc.server.com 432 * nick :Erroneous Nickname
                false
            }

            // Multiple possible:
            //
            // :irc.server.net 437 * badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Cannot change nick while banned on channel
            //
            // Only want to try an alt nick in the first case.
            437 => {
                false
            }

            _ => {
                println!("unhandled numeric: {}", code);

                true
            }
        };

        Ok(should_forward)
    }
}
<commit_msg>network: rename write_message to send_message<commit_after>#![allow(dead_code, unused_variables)]

use std::collections::HashSet;
use std::io::Result;

use crate::proto::{Capability, MessageKind, ModeSet, RawMessage};
use crate::socket::IRCWriter;

enum AuthKind {
    SaslPlain(String, String),
    Pass(String),
    None,
}

#[derive(Debug, Copy, Clone)]
enum ConnectionState {
    Initial,
    CapabilityNegotiation,
    Authentication,
    Registration,
    Registered,
}

/// Represents Birch <-> IRC network connection
pub struct NetworkConnection<'a> {
    nick: String,
    user_modes: ModeSet,
    caps_pending: usize,
    caps: HashSet<Capability>,
    auth: AuthKind,

    state: ConnectionState,

    writer: &'a mut dyn IRCWriter,
    // user_fanout: &'a mut dyn IRCWriter,
}

impl<'a> NetworkConnection<'a> {
    pub fn new(nick: &str, writer: &'a mut dyn IRCWriter) -> Self {
        Self {
            nick: nick.to_string(),
            user_modes: ModeSet::empty(),
            caps_pending: 0,
            caps: HashSet::new(),
            auth: AuthKind::None,

            state: ConnectionState::Initial,

            writer,
        }
    }

    pub fn initialize(&mut self) -> Result<()> {
        self.transition_state(ConnectionState::Initial)
    }

    fn send_network(&mut self, command: &str, params: &[&str]) -> Result<()> {
        self.writer.write_message(&RawMessage::new(command, params))
    }

    fn transition_state(&mut self, next: ConnectionState) -> Result<()> {
        match &next {
            ConnectionState::Initial => {
                self.transition_state(ConnectionState::CapabilityNegotiation)?;
            }

            ConnectionState::CapabilityNegotiation => {
                self.send_network("CAP", &["LS", "302"])?;
            }

            ConnectionState::Authentication => match self.auth {
                AuthKind::SaslPlain(ref _user, ref _pass) => unimplemented!(),
                AuthKind::Pass(ref _pass) => unimplemented!(),
                AuthKind::None => {
                    self.transition_state(ConnectionState::Registration)?;
                }
            },

            ConnectionState::Registration => {
                // TODO: prevent unnecessary clone
                let nick = self.nick.clone();

                self.send_network("NICK", &[&nick])?;
                self.send_network("USER", &[&nick, "0", "*", &nick])?;

                self.transition_state(ConnectionState::Registered)?;
            }

            ConnectionState::Registered => (),
        }

        self.state = next;
        Ok(())
    }

    fn handle_cap_message(&mut self, msg: &RawMessage) -> Result<()> {
        let cmd = msg.param(1).unwrap_or("");
        match cmd {
            "LS" => {
                let caps = msg.trailing().unwrap_or("").split_whitespace();

                for cap_str in caps {
                    if let Some(cap) = Capability::from(cap_str) {
                        self.send_network("CAP", &["REQ", cap_str])?;
                        self.caps_pending += 1;
                    }
                }
            }

            "ACK" | "NAK" => {
                let cap = msg.trailing().and_then(Capability::from);

                if let Some(cap) = cap {
                    if cmd == "ACK" {
                        println!("CAP {:?} enabled", cap);
                        self.caps.insert(cap);
                    }
                }

                self.caps_pending -= 1;

                if self.caps_pending == 0 {
                    self.send_network("CAP", &["END"])?;
                    self.transition_state(ConnectionState::Authentication)?;
                }
            }

            // Not strictly necessary but if we want to support `cap-notify`
            "NEW" | "DEL" => unimplemented!(),

            _ => println!("ignoring unknown cap command: {}", msg),
        }

        Ok(())
    }

    pub fn handle(&mut self, msg: &RawMessage) -> Result<()> {
        let kind = MessageKind::from(msg);
        let should_forward = match kind {
            MessageKind::Ping => {
                let param = msg.param(0).unwrap_or("");
                self.send_network("PONG", &[param])?;
                false
            }

            MessageKind::Capability => {
                self.handle_cap_message(msg)?;
                // We have our own caps, don't send the server's.
                false
            }

            MessageKind::Numeric(code) => self.handle_numeric(code, msg)?,

            MessageKind::Privmsg | MessageKind::Notice => {
                if let Some(ref source) = msg.source {
                    let sender = &source.nick;
                    let msg = msg.trailing().unwrap_or("");

                    // Handle basic CTCP
                    match msg {
                        "\x01VERSION\x01" => {
                            // TODO: Probably should be configurable
                            let version = "\x01VERSION birch\x01";
                            self.send_network("NOTICE", &[sender, version])?;

                            false
                        }
                        _ => true,
                    }
                } else {
                    // Invalid msg? No sender.
                    false
                }
            }

            // MessageKind::Join => true,
            // MessageKind::Part => true,
            // MessageKind::Quit => true,

            // MessageKind::Kick => true,
            MessageKind::Mode => {
                if let Some(target) = msg.param(0) {
                    if target == self.nick {
                        let modes = msg.param(1).and_then(|s| self.user_modes.apply(s));
                        if let Some(modes) = modes {
                            self.user_modes = modes;
                        }
                    } else {
                        // TODO: channel modes, other users
                    }
                }
                true
            }

            _ => {
                println!("Unhandled message: {:?}", msg);

                true
            }
        };

        if should_forward {
            // TODO: send message to user_fanout
        }

        Ok(())
    }

    fn handle_numeric(&mut self, code: u16, msg: &RawMessage) -> Result<bool> {
        let should_forward = match code {
            // :server 001 nick :welcome message
            1 => false,

            // ISUPPORT
            5 => false,

            2 |      // Your host
            3 |      // Server created at
            4 |      // Server info
            250 |    // Highest user count
            251 |    // User count
            252 |    // Oper count
            253 |    // Unknown connections
            254 |    // Channel count
            255 |    // Client count
            265 |    // Local users
            266 => { // Global users
                // TODO: Update network buffer state
                false
            },

            305 => { // Clear AWAY
                false
            }

            306 => { // Set AWAY
                false
            }

            329 => { // :server.com 329 nick #chan <epoch chan creation>
                false
            }

            // :server.com 331 nick #chan :no topic is set
            331 => {
                false
            }

            // :server.com 332 nick #chan :channel topic
            332 => {
                false
            }

            // :server.com 333 nick #chan who_set <epochtime>
            333 => {
                false
            }

            353 |    // :server.com 353 nick @ #chan :nick1 nick2
            366 => { // :server.com 366 nick #chan :End of /NAMES
                false
            }

            375 |    // Begin MOTD
            422 => { // MOTD file is missing
                // TODO: Clear MOTD
                false
            }

            372 |    // MOTD
            376 => { // End MOTD
                // TODO: MOTD
                false
            }

            432 |
            433 => { // :irc.server.com 432 * nick :Erroneous Nickname
                false
            }

            // Multiple possible:
            //
            // :irc.server.net 437 * badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Nick is temporarily unavailable
            // :irc.server.net 437 nick badnick :Cannot change nick while banned on channel
            //
            // Only want to try an alt nick in the first case.
            437 => {
                false
            }

            _ => {
                println!("unhandled numeric: {}", code);

                true
            }
        };

        Ok(should_forward)
    }
}
<|endoftext|>


<commit_before>extern crate elf;
extern crate getopts;

use getopts::Options;
use std::cmp;
use std::env;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::mem;
use std::path::Path;
use std::slice;

/// Takes a value and rounds it up to be aligned % 8
macro_rules! align8 {
    ( $e:expr ) => ( ($e) + ((8 - (($e) % 8)) % 8 ) );
}

/// Takes a value and rounds it up to be aligned % 4
macro_rules! align4 {
    ( $e:expr ) => ( ($e) + ((4 - (($e) % 4)) % 4 ) );
}

#[repr(u16)]
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
enum TbfHeaderTypes {
    TbfHeaderMain = 1,
    TbfHeaderWriteableFlashRegions = 2,
    TbfHeaderPackageName = 3,
    TbfHeaderPicOption1 = 4,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderTlv {
    tipe: TbfHeaderTypes,
    length: u16,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderBase {
    version: u16,
    header_size: u16,
    total_size: u32,
    flags: u32,
    checksum: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderMain {
    base: TbfHeaderTlv,
    init_fn_offset: u32,
    protected_size: u32,
    minimum_ram_size: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderWriteableFlashRegion {
    offset: u32,
    size: u32,
}

impl fmt::Display for TbfHeaderBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
               version: {:>8} {:>#10X}
           header_size: {:>8} {:>#10X}
            total_size: {:>8} {:>#10X}
                 flags: {:>8} {:>#10X}
",
        self.version, self.version,
        self.header_size, self.header_size,
        self.total_size, self.total_size,
        self.flags, self.flags,
        )
    }
}

impl fmt::Display for TbfHeaderMain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
        init_fn_offset: {:>8} {:>#10X}
        protected_size: {:>8} {:>#10X}
      minimum_ram_size: {:>8} {:>#10X}
",
        self.init_fn_offset, self.init_fn_offset,
        self.protected_size, self.protected_size,
        self.minimum_ram_size, self.minimum_ram_size,
        )
    }
}

impl fmt::Display for TbfHeaderWriteableFlashRegion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
    flash region:
                offset: {:>8} {:>#10X}
                  size: {:>8} {:>#10X}
",
        self.offset, self.offset,
        self.size, self.size,
        )
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "OUTFILE");
    opts.optopt("n", "", "set package name", "PACKAGE_NAME");
    opts.optflag("v", "verbose", "be verbose");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    let output = matches.opt_str("o");
    let package_name = matches.opt_str("n");
    let verbose = matches.opt_present("v");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let path = Path::new(&input);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    match output {
            None => {
                let mut out = io::stdout();
                do_work(&file, &mut out, package_name, verbose)
            }
            Some(name) => {
                match File::create(Path::new(&name)) {
                    Ok(mut f) => do_work(&file, &mut f, package_name, verbose),
                    Err(e) => panic!("Error: {:?}", e),
                }
            }
        }
        .expect("Failed to write output");
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [-o OUTFILE] FILE", program);
    print!("{}", opts.usage(&brief));
}

fn get_section<'a>(input: &'a elf::File, name: &str) -> elf::Section {
    match input.get_section(name) {
        Some(section) => {
            elf::Section {
                data: section.data.clone(),
                shdr: section.shdr.clone(),
            }
        }
        None => {
            elf::Section {
                data: Vec::new(),
                shdr: elf::types::SectionHeader {
                    name: String::from(name),
                    shtype: elf::types::SHT_NULL,
                    flags: elf::types::SHF_NONE,
                    addr: 0,
                    offset: 0,
                    size: 0,
                    link: 0,
                    info: 0,
                    addralign: 0,
                    entsize: 0,
                },
            }
        }
    }
}

unsafe fn as_byte_slice<'a, T: Copy>(input: &'a T) -> &'a [u8] {
    slice::from_raw_parts(input as *const T as *const u8, mem::size_of::<T>())
}

fn do_work(input: &elf::File,
           output: &mut Write,
           package_name: Option<String>,
           verbose: bool)
           -> io::Result<()> {
    let package_name = package_name.unwrap_or(String::new());
    let (relocation_data_size, rel_data) = match input.sections
        .iter()
        .find(|section| section.shdr.name == ".rel.data".as_ref()) {
        Some(section) => (section.shdr.size, section.data.as_ref()),
        None => (0 as u64, &[] as &[u8]),

    };
    let text = get_section(input, ".text");
    let got = get_section(input, ".got");
    let data = get_section(input, ".data");
    let bss = get_section(input, ".bss");
    let appstate = get_section(input, ".app_state");

    // For these, we only care about the length
    let stack_len = get_section(input, ".stack").data.len() as u32;
    let app_heap_len = get_section(input, ".app_heap").data.len() as u32;
    let kernel_heap_len = get_section(input, ".kernel_heap").data.len() as u32;

    // Need to calculate lengths ahead of time.
    // Need the base and the main section.
    let mut header_length = mem::size_of::<TbfHeaderBase>() + mem::size_of::<TbfHeaderMain>();

    // If we have a package name, add that section.
    let mut post_name_pad = 0;
    if package_name.len() > 0 {
        let name_total_size = align4!(mem::size_of::<TbfHeaderTlv>() + package_name.len());
        header_length += name_total_size;

        // Calculate the padding required after the package name TLV. All blocks
        // must be four byte aligned, so we may need to add some padding.
        post_name_pad = name_total_size - (mem::size_of::<TbfHeaderTlv>() + package_name.len());
    }

    // We have one app flash region, add that.
    if appstate.data.len() > 0 {
        header_length += mem::size_of::<TbfHeaderTlv>() +
                         mem::size_of::<TbfHeaderWriteableFlashRegion>();
    }

    // Calculate the offset between the start of the flash region and the actual
    // app code. Also need to get the padding size.
    let app_start_offset = align4!(header_length);
    let post_header_pad = app_start_offset as usize - header_length;
    println!("{}", post_header_pad);

    // Now we can calculate the entire size of the app in flash.
    let mut total_size = (header_length + post_header_pad + rel_data.len() + text.data.len() +
                          got.data.len() +
                          data.data.len() + appstate.data.len()) as u32;

    let ending_pad = if total_size.count_ones() > 1 {
        let power2len = cmp::max(1 << (32 - total_size.leading_zeros()), 512);
        power2len - total_size
    } else {
        0
    };
    total_size += ending_pad;

    // To start we just restrict the app from writing all of the space before
    // its actual code and whatnot.
    let protected_size = 0;

    // First up is the app writeable app_state section. If this is not used or
    // non-existent, it will just be zero and won't matter. But we put it first
    // so that changes to the app won't move it.
    let appstate_offset = app_start_offset as u32;
    let appstate_size = appstate.shdr.size as u32;
    // Make sure we pad back to a multiple of 8.
    let post_appstate_pad = align4!(appstate_offset + appstate_size) -
                            (appstate_offset + appstate_size);
    let init_fn_offset = (input.ehdr.entry - text.shdr.addr) as u32;
    let got_size = got.shdr.size as u32;
    let data_size = data.shdr.size as u32;
    let bss_size = bss.shdr.size as u32;
    let minimum_ram_size = stack_len + app_heap_len + kernel_heap_len + got_size + data_size +
                           bss_size;

    // Flags default to app is enabled.
    let flags = 0x00000001;

    let tbf_header_version = 2;

    let tbf_header = TbfHeaderBase {
        version: tbf_header_version,
        header_size: header_length as u16,
        total_size: total_size,
        flags: flags,
        checksum: 0,
    };

    let tbf_main = TbfHeaderMain {
        base: TbfHeaderTlv {
            tipe: TbfHeaderTypes::TbfHeaderMain,
            length: (mem::size_of::<TbfHeaderMain>() - mem::size_of::<TbfHeaderTlv>()) as u16,
        },
        init_fn_offset: init_fn_offset,
        protected_size: protected_size as u32,
        minimum_ram_size: minimum_ram_size,
    };

    let tbf_package_name_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderPackageName,
        length: package_name.len() as u16,
    };

    let tbf_flash_regions_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderWriteableFlashRegions,
        length: 8,
    };

    let tbf_flash_region = TbfHeaderWriteableFlashRegion {
        offset: appstate_offset,
        size: appstate_size,
    };

    if verbose {
        print!("{}", tbf_header);
        print!("{}", tbf_main);
        print!("{}", tbf_flash_region);
    }

    // Calculate the header checksum.
    let mut header_buf = Cursor::new(Vec::new());

    // Write all bytes to an in-memory file for the header.
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_header) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_main) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_package_name_tlv) }));
    try!(header_buf.write_all(package_name.as_ref()));
    try!(do_pad(&mut header_buf, post_name_pad));

    // Only put these in the header if the app_state section is nonzero.
    if appstate.data.len() > 0 {
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_regions_tlv) }));
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_region) }));
    }

    // Start from the beginning and iterate through the buffer as words.
    try!(header_buf.seek(SeekFrom::Start(0)));
    let mut wordbuf = [0u8; 4];
    let mut checksum: u32 = 0;
    loop {
        let ret = header_buf.read(&mut wordbuf);
        match ret {
            Ok(count) => {
                // Combine the bytes back into a word, handling if we don't
                // get a full word.
                let mut word = 0;
                for i in 0..count {
                    word |= (wordbuf[i] as u32) << (8 * i);
                }
                checksum ^= word;
                if count != 4 {
                    break;
                }
            }
            Err(_) => println!("Error calculating checksum."),
        }
    }

    // Now we need to insert the checksum into the correct position in the
    // header.
    try!(header_buf.seek(SeekFrom::Start(12)));
    wordbuf[0] = ((checksum >> 0) & 0xFF) as u8;
    wordbuf[1] = ((checksum >> 8) & 0xFF) as u8;
    wordbuf[2] = ((checksum >> 16) & 0xFF) as u8;
    wordbuf[3] = ((checksum >> 24) & 0xFF) as u8;
    try!(header_buf.write(&wordbuf));
    try!(header_buf.seek(SeekFrom::Start(0)));

    fn do_pad(output: &mut Write, length: usize) -> io::Result<()> {
        let mut pad = length;
        let zero_buf = [0u8; 512];
        while pad > 0 {
            let amount_to_write = cmp::min(zero_buf.len(), pad);
            pad -= try!(output.write(&zero_buf[..amount_to_write]));
        }
        Ok(())
    }

    // Write the header and actual app to a binary file.
    try!(output.write_all(header_buf.get_ref()));
    try!(do_pad(output, post_header_pad as usize));
    try!(output.write_all(appstate.data.as_ref()));
    try!(do_pad(output, post_appstate_pad as usize));
    try!(output.write_all(text.data.as_ref()));
    try!(output.write_all(got.data.as_ref()));
    try!(output.write_all(data.data.as_ref()));
    let rel_data_len: [u8; 4] = [(rel_data.len() & 0xff) as u8,
                                 (rel_data.len() >> 8 & 0xff) as u8,
                                 (rel_data.len() >> 16 & 0xff) as u8,
                                 (rel_data.len() >> 24 & 0xff) as u8];
    try!(output.write_all(&rel_data_len));
    try!(output.write_all(rel_data.as_ref()));

    // Pad to get a power of 2 sized flash app.
    try!(do_pad(output, ending_pad as usize));

    Ok(())
}
<commit_msg>Cleanup elf2tbf<commit_after>extern crate elf;
extern crate getopts;

use getopts::Options;
use std::cmp;
use std::env;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::mem;
use std::path::Path;
use std::slice;

/// Takes a value and rounds it up to be aligned % 4
macro_rules! align4 {
    ( $e:expr ) => ( ($e) + ((4 - (($e) % 4)) % 4 ) );
}

#[repr(u16)]
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
enum TbfHeaderTypes {
    TbfHeaderMain = 1,
    TbfHeaderWriteableFlashRegions = 2,
    TbfHeaderPackageName = 3,
    TbfHeaderPicOption1 = 4,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderTlv {
    tipe: TbfHeaderTypes,
    length: u16,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderBase {
    version: u16,
    header_size: u16,
    total_size: u32,
    flags: u32,
    checksum: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderMain {
    base: TbfHeaderTlv,
    init_fn_offset: u32,
    protected_size: u32,
    minimum_ram_size: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct TbfHeaderWriteableFlashRegion {
    offset: u32,
    size: u32,
}

impl fmt::Display for TbfHeaderBase {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
               version: {:>8} {:>#10X}
           header_size: {:>8} {:>#10X}
            total_size: {:>8} {:>#10X}
                 flags: {:>8} {:>#10X}
",
        self.version, self.version,
        self.header_size, self.header_size,
        self.total_size, self.total_size,
        self.flags, self.flags,
        )
    }
}

impl fmt::Display for TbfHeaderMain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
        init_fn_offset: {:>8} {:>#10X}
        protected_size: {:>8} {:>#10X}
      minimum_ram_size: {:>8} {:>#10X}
",
        self.init_fn_offset, self.init_fn_offset,
        self.protected_size, self.protected_size,
        self.minimum_ram_size, self.minimum_ram_size,
        )
    }
}

impl fmt::Display for TbfHeaderWriteableFlashRegion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "
    flash region:
                offset: {:>8} {:>#10X}
                  size: {:>8} {:>#10X}
",
        self.offset, self.offset,
        self.size, self.size,
        )
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "OUTFILE");
    opts.optopt("n", "", "set package name", "PACKAGE_NAME");
    opts.optflag("v", "verbose", "be verbose");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string()),
    };
    let output = matches.opt_str("o");
    let package_name = matches.opt_str("n");
    let verbose = matches.opt_present("v");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    let path = Path::new(&input);
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };

    match output {
            None => {
                let mut out = io::stdout();
                do_work(&file, &mut out, package_name, verbose)
            }
            Some(name) => {
                match File::create(Path::new(&name)) {
                    Ok(mut f) => do_work(&file, &mut f, package_name, verbose),
                    Err(e) => panic!("Error: {:?}", e),
                }
            }
        }
        .expect("Failed to write output");
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [-o OUTFILE] FILE", program);
    print!("{}", opts.usage(&brief));
}

fn get_section<'a>(input: &'a elf::File, name: &str) -> elf::Section {
    match input.get_section(name) {
        Some(section) => {
            elf::Section {
                data: section.data.clone(),
                shdr: section.shdr.clone(),
            }
        }
        None => {
            elf::Section {
                data: Vec::new(),
                shdr: elf::types::SectionHeader {
                    name: String::from(name),
                    shtype: elf::types::SHT_NULL,
                    flags: elf::types::SHF_NONE,
                    addr: 0,
                    offset: 0,
                    size: 0,
                    link: 0,
                    info: 0,
                    addralign: 0,
                    entsize: 0,
                },
            }
        }
    }
}

unsafe fn as_byte_slice<'a, T: Copy>(input: &'a T) -> &'a [u8] {
    slice::from_raw_parts(input as *const T as *const u8, mem::size_of::<T>())
}

fn do_work(input: &elf::File,
           output: &mut Write,
           package_name: Option<String>,
           verbose: bool)
           -> io::Result<()> {
    let package_name = package_name.unwrap_or(String::new());
    let rel_data = input.sections
        .iter()
        .find(|section| section.shdr.name == ".rel.data".as_ref())
        .map(|section| section.data.as_ref())
        .unwrap_or(&[] as &[u8]);
    let text = get_section(input, ".text");
    let got = get_section(input, ".got");
    let data = get_section(input, ".data");
    let bss = get_section(input, ".bss");
    let appstate = get_section(input, ".app_state");

    // For these, we only care about the length
    let stack_len = get_section(input, ".stack").data.len() as u32;
    let app_heap_len = get_section(input, ".app_heap").data.len() as u32;
    let kernel_heap_len = get_section(input, ".kernel_heap").data.len() as u32;

    // Need to calculate lengths ahead of time.
    // Need the base and the main section.
    let mut header_length = mem::size_of::<TbfHeaderBase>() + mem::size_of::<TbfHeaderMain>();

    // If we have a package name, add that section.
    let mut post_name_pad = 0;
    if package_name.len() > 0 {
        let name_total_size = align4!(mem::size_of::<TbfHeaderTlv>() + package_name.len());
        header_length += name_total_size;

        // Calculate the padding required after the package name TLV. All blocks
        // must be four byte aligned, so we may need to add some padding.
        post_name_pad = name_total_size - (mem::size_of::<TbfHeaderTlv>() + package_name.len());
    }

    // We have one app flash region, add that.
    if appstate.data.len() > 0 {
        header_length += mem::size_of::<TbfHeaderTlv>() +
                         mem::size_of::<TbfHeaderWriteableFlashRegion>();
    }

    // Calculate the offset between the start of the flash region and the actual
    // app code. Also need to get the padding size.
    let app_start_offset = align4!(header_length);
    let post_header_pad = app_start_offset as usize - header_length;
    println!("{}", post_header_pad);

    // Now we can calculate the entire size of the app in flash.
    let mut total_size = (header_length + post_header_pad + rel_data.len() + text.data.len() +
                          got.data.len() +
                          data.data.len() + appstate.data.len()) as u32;

    let ending_pad = if total_size.count_ones() > 1 {
        let power2len = cmp::max(1 << (32 - total_size.leading_zeros()), 512);
        power2len - total_size
    } else {
        0
    };
    total_size += ending_pad;

    // To start we just restrict the app from writing all of the space before
    // its actual code and whatnot.
    let protected_size = 0;

    // First up is the app writeable app_state section. If this is not used or
    // non-existent, it will just be zero and won't matter. But we put it first
    // so that changes to the app won't move it.
    let appstate_offset = app_start_offset as u32;
    let appstate_size = appstate.shdr.size as u32;
    // Make sure we pad back to a multiple of 8.
    let post_appstate_pad = align4!(appstate_offset + appstate_size) -
                            (appstate_offset + appstate_size);
    let init_fn_offset = (input.ehdr.entry - text.shdr.addr) as u32;
    let got_size = got.shdr.size as u32;
    let data_size = data.shdr.size as u32;
    let bss_size = bss.shdr.size as u32;
    let minimum_ram_size = stack_len + app_heap_len + kernel_heap_len + got_size + data_size +
                           bss_size;

    // Flags default to app is enabled.
    let flags = 0x00000001;

    let tbf_header_version = 2;

    let tbf_header = TbfHeaderBase {
        version: tbf_header_version,
        header_size: header_length as u16,
        total_size: total_size,
        flags: flags,
        checksum: 0,
    };

    let tbf_main = TbfHeaderMain {
        base: TbfHeaderTlv {
            tipe: TbfHeaderTypes::TbfHeaderMain,
            length: (mem::size_of::<TbfHeaderMain>() - mem::size_of::<TbfHeaderTlv>()) as u16,
        },
        init_fn_offset: init_fn_offset,
        protected_size: protected_size as u32,
        minimum_ram_size: minimum_ram_size,
    };

    let tbf_package_name_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderPackageName,
        length: package_name.len() as u16,
    };

    let tbf_flash_regions_tlv = TbfHeaderTlv {
        tipe: TbfHeaderTypes::TbfHeaderWriteableFlashRegions,
        length: 8,
    };

    let tbf_flash_region = TbfHeaderWriteableFlashRegion {
        offset: appstate_offset,
        size: appstate_size,
    };

    if verbose {
        print!("{}", tbf_header);
        print!("{}", tbf_main);
        print!("{}", tbf_flash_region);
    }

    // Calculate the header checksum.
    let mut header_buf = Cursor::new(Vec::new());

    // Write all bytes to an in-memory file for the header.
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_header) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_main) }));
    try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_package_name_tlv) }));
    try!(header_buf.write_all(package_name.as_ref()));
    try!(do_pad(&mut header_buf, post_name_pad));

    // Only put these in the header if the app_state section is nonzero.
    if appstate.data.len() > 0 {
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_regions_tlv) }));
        try!(header_buf.write_all(unsafe { as_byte_slice(&tbf_flash_region) }));
    }

    // Start from the beginning and iterate through the buffer as words.
    try!(header_buf.seek(SeekFrom::Start(0)));
    let mut wordbuf = [0u8; 4];
    let mut checksum: u32 = 0;
    loop {
        let ret = header_buf.read(&mut wordbuf);
        match ret {
            Ok(count) => {
                // Combine the bytes back into a word, handling if we don't
                // get a full word.
                let mut word = 0;
                for i in 0..count {
                    word |= (wordbuf[i] as u32) << (8 * i);
                }
                checksum ^= word;
                if count != 4 {
                    break;
                }
            }
            Err(_) => println!("Error calculating checksum."),
        }
    }

    // Now we need to insert the checksum into the correct position in the
    // header.
    try!(header_buf.seek(SeekFrom::Start(12)));
    wordbuf[0] = ((checksum >> 0) & 0xFF) as u8;
    wordbuf[1] = ((checksum >> 8) & 0xFF) as u8;
    wordbuf[2] = ((checksum >> 16) & 0xFF) as u8;
    wordbuf[3] = ((checksum >> 24) & 0xFF) as u8;
    try!(header_buf.write(&wordbuf));
    try!(header_buf.seek(SeekFrom::Start(0)));

    fn do_pad(output: &mut Write, length: usize) -> io::Result<()> {
        let mut pad = length;
        let zero_buf = [0u8; 512];
        while pad > 0 {
            let amount_to_write = cmp::min(zero_buf.len(), pad);
            pad -= try!(output.write(&zero_buf[..amount_to_write]));
        }
        Ok(())
    }

    // Write the header and actual app to a binary file.
    try!(output.write_all(header_buf.get_ref()));
    try!(do_pad(output, post_header_pad as usize));
    try!(output.write_all(appstate.data.as_ref()));
    try!(do_pad(output, post_appstate_pad as usize));
    try!(output.write_all(text.data.as_ref()));
    try!(output.write_all(got.data.as_ref()));
    try!(output.write_all(data.data.as_ref()));
    let rel_data_len: [u8; 4] = [(rel_data.len() & 0xff) as u8,
                                 (rel_data.len() >> 8 & 0xff) as u8,
                                 (rel_data.len() >> 16 & 0xff) as u8,
                                 (rel_data.len() >> 24 & 0xff) as u8];
    try!(output.write_all(&rel_data_len));
    try!(output.write_all(rel_data.as_ref()));

    // Pad to get a power of 2 sized flash app.
    try!(do_pad(output, ending_pad as usize));

    Ok(())
}
<|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/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;

use util::str::DOMString;

use std::borrow::ToOwned;
use std::cell::Cell;

#[dom_struct]
pub struct CloseEvent {
    event: Event,
    wasClean: Cell<bool>,
    code: Cell<u16>,
    reason: DOMRefCell<DOMString>
}

impl CloseEvent {
    pub fn new_inherited(type_id: EventTypeId) -> CloseEvent {
        CloseEvent {
            event: Event::new_inherited(type_id),
            wasClean: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned())
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let ev = reflect_dom_object(box CloseEvent::new_inherited(EventTypeId::CloseEvent),
                                    global,
                                    CloseEventBinding::Wrap);
        let ev = ev.root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        let ev = ev.r();
        ev.wasClean.set(wasClean);
        ev.code.set(code);
        *ev.reason.borrow_mut() = reason;
        Temporary::from_rooted(ev)
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit)
                       -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or(true);
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent> {
    fn WasClean(self) -> bool {
        self.wasClean.get()
    }

    fn Code(self) -> u16 {
        self.code.get()
    }

    fn Reason(self) -> DOMString {
        let reason = self.reason.borrow();
        reason.clone()
    }
}
<commit_msg>Make the CloseEvent members immutable.<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/. */

use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;

use util::str::DOMString;

use std::borrow::ToOwned;

#[dom_struct]
pub struct CloseEvent {
    event: Event,
    wasClean: bool,
    code: u16,
    reason: DOMString,
}

impl CloseEvent {
    pub fn new_inherited(type_id: EventTypeId, wasClean: bool, code: u16,
                         reason: DOMString) -> CloseEvent {
        CloseEvent {
            event: Event::new_inherited(type_id),
            wasClean: wasClean,
            code: code,
            reason: reason,
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let event = box CloseEvent::new_inherited(EventTypeId::CloseEvent,
                                                  wasClean, code, reason);
        let ev = reflect_dom_object(event, global, CloseEventBinding::Wrap).root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        Temporary::from_rooted(ev.r())
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit)
                       -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or(true);
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent> {
    fn WasClean(self) -> bool {
        self.wasClean
    }

    fn Code(self) -> u16 {
        self.code
    }

    fn Reason(self) -> DOMString {
        self.reason.clone()
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRViewportBinding;
use crate::dom::bindings::codegen::Bindings::XRViewportBinding::XRViewportMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;

#[dom_struct]
pub struct XRViewport {
    reflector_: Reflector,
    x: u32,
    y: u32,
    width: u32,
    height: u32,
}

impl XRViewport {
    fn new_inherited(x: u32, y: u32, width: u32, height: u32) -> XRViewport {
        XRViewport {
            reflector_: Reflector::new(),
            x,
            y,
            width,
            height,
        }
    }

    pub fn new(
        global: &GlobalScope,
        x: u32,
        y: u32,
        width: u32,
        height: u32,
    ) -> DomRoot<XRViewport> {
        reflect_dom_object(
            Box::new(XRViewport::new_inherited(x, y, width, height)),
            global,
            XRViewportBinding::Wrap,
        )
    }
}

impl XRViewportMethods for XRViewport {
    /// https://immersive-web.github.io/webxr/#dom-xrviewport-x
    fn X(&self) -> i32 {
        self.x as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-y
    fn Y(&self) -> i32 {
        self.y as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-width
    fn Width(&self) -> i32 {
        self.height as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-height
    fn Height(&self) -> i32 {
        self.height as i32
    }
}
<commit_msg>Fix xrviewport.height<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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRViewportBinding;
use crate::dom::bindings::codegen::Bindings::XRViewportBinding::XRViewportMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;

#[dom_struct]
pub struct XRViewport {
    reflector_: Reflector,
    x: u32,
    y: u32,
    width: u32,
    height: u32,
}

impl XRViewport {
    fn new_inherited(x: u32, y: u32, width: u32, height: u32) -> XRViewport {
        XRViewport {
            reflector_: Reflector::new(),
            x,
            y,
            width,
            height,
        }
    }

    pub fn new(
        global: &GlobalScope,
        x: u32,
        y: u32,
        width: u32,
        height: u32,
    ) -> DomRoot<XRViewport> {
        reflect_dom_object(
            Box::new(XRViewport::new_inherited(x, y, width, height)),
            global,
            XRViewportBinding::Wrap,
        )
    }
}

impl XRViewportMethods for XRViewport {
    /// https://immersive-web.github.io/webxr/#dom-xrviewport-x
    fn X(&self) -> i32 {
        self.x as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-y
    fn Y(&self) -> i32 {
        self.y as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-width
    fn Width(&self) -> i32 {
        self.width as i32
    }

    /// https://immersive-web.github.io/webxr/#dom-xrviewport-height
    fn Height(&self) -> i32 {
        self.height as i32
    }
}
<|endoftext|>


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

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(~BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>auto merge of #13958 : pcwalton/rust/detilde, r=pcwalton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(box BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_json;

use handlebars::Handlebars;

#[test]
#[cfg(feature = "rust-embed")]
fn test_embed() {
    use rust_embed::RustEmbed;

    #[derive(RustEmbed)]
    #[folder = "tests/templates/"]
    #[include = "*.hbs"]
    struct Templates;

    let mut hbs = Handlebars::new();
    hbs.register_embed_templates::<Templates>().unwrap();

    assert_eq!(1, hbs.get_templates().len());

    let data = json!({
        "name": "Andy"
    });

    assert_eq!(hbs.render("hello.hbs", &data).unwrap(), "Hello, Andy\n");
}
<commit_msg>fix: LS on windows causing failed test<commit_after>#[macro_use]
extern crate serde_json;

use handlebars::Handlebars;

#[test]
#[cfg(feature = "rust-embed")]
fn test_embed() {
    use rust_embed::RustEmbed;

    #[derive(RustEmbed)]
    #[folder = "tests/templates/"]
    #[include = "*.hbs"]
    struct Templates;

    let mut hbs = Handlebars::new();
    hbs.register_embed_templates::<Templates>().unwrap();

    assert_eq!(1, hbs.get_templates().len());

    let data = json!({
        "name": "Andy"
    });

    assert_eq!(
        hbs.render("hello.hbs", &data).unwrap().trim(),
        "Hello, Andy"
    );
}
<|endoftext|>


<commit_before>extern crate ktensor as k;
use std::path::{Path};

fn read_mnist<P: AsRef<Path>>(path: P, num_samples: usize) -> Vec<f32> {

}

#[test]
#[ignore]
fn mnist(){

}
<commit_msg>mnist can read data<commit_after>extern crate ktensor as k;
use std::path::{Path};
use std::fs::{File};
use std::io::{self, BufReader, Read};
use std::error::{Error};
use std::cmp::{min};

fn read_u8(reader: &mut Read) -> u8 {
    use std::mem;

    let mut buf: [u8; 1] = [0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u8 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u8: {}", Error::description(&reason)),
        Ok(file)    => file,
    }
}

fn read_u32(reader: &mut Read) -> u32 {
    use std::mem;

    let mut buf: [u8; 4] = [0, 0, 0, 0];
    match reader.read_exact(&mut buf).map(|_| {
        let data: u32 = unsafe { mem::transmute(buf) };
        data
    }) {
        Err(reason) => panic!("failed to read u8: {}", Error::description(&reason)),
        Ok(file)    => file,
    }
}

fn read_mnist(labels_path: &Path, labels_checknum: u32, data_path: &Path, data_checknum: u32, samples: usize) {
    let mut labels_file = match File::open(&labels_path) {
        Err(reason) => panic!("failed to open {}: {}", labels_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let mut data_file = match File::open(&data_path) {
        Err(reason) => panic!("failed to open {}: {}", data_path.display(), Error::description(&reason)),
        Ok(file)    => file,
    };
    let mut labels_reader = BufReader::new(labels_file);
    let mut data_reader = BufReader::new(data_file);
    let labels_magic = u32::from_be(read_u32(&mut labels_reader));
    let data_magic = u32::from_be(read_u32(&mut data_reader));
    println!("{} {}", labels_magic, data_magic);
    assert_eq!(labels_magic, labels_checknum);
    assert_eq!(data_magic, data_checknum);
}

#[test]
#[ignore]
fn mnist(){
    let train_labels_path = Path::new("data/train-labels-idx1-ubyte");
    let train_data_path = Path::new("data/train-images-idx3-ubyte");
    read_mnist(&train_labels_path, 2049, &train_data_path, 2051, 1);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::collections::HashSet;

use enums;
use parse;

pub fn write_descriptor_sets(doc: &parse::Spirv) -> String {
    // TODO: not implemented

    // finding all the descriptors
    let mut descriptors = Vec::new();
    struct Descriptor {
        name: String,
        desc_ty: String,
        bind_ty: String,
        bind_template_params: Vec<String>,
        bind_where_clauses: String,
        bind: String,
        set: u32,
        binding: u32,
    }

    // template parameter names that are available for the purpose of the code below
    // TODO: better system
    let mut template_params = vec!["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"].into_iter();

    // looping to find all the elements that have the `DescriptorSet` decoration
    for instruction in doc.instructions.iter() {
        let (variable_id, descriptor_set) = match instruction {
            &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationDescriptorSet, ref params } => {
                (target_id, params[0])
            },
            _ => continue
        };

        // find which type is pointed to by this variable
        let pointed_ty = pointer_variable_ty(doc, variable_id);
        // name of the variable
        let name = ::name_from_id(doc, variable_id);

        // find the binding point of this descriptor
        let binding = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBinding, ref params } if target_id == variable_id => {
                    Some(params[0])
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Uniform `{}` is missing a binding", name));

        // find informations about the kind of binding for this descriptor
        let (desc_ty, bind_template_params, bind_where_clauses, bind_ty, bind) = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::TypeStruct { result_id, .. } if result_id == pointed_ty => {
                    let tp_buffer = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::UniformBuffer",
                        vec![tp_buffer.to_owned()],
                        format!("{}: 'static + ::vulkano::buffer::Buffer", tp_buffer),
                        format!("&'a ::std::sync::Arc<{}>", tp_buffer),
                        "unsafe { ::vulkano::descriptor_set::DescriptorBind::unchecked_uniform_buffer(data, 0 .. data.size()) }"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(true) =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::SampledImage",
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("&'a ::std::sync::Arc<{}>", img),
                        "::vulkano::descriptor_set::DescriptorBind::sampled_image(data)"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(false) =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::InputAttachment",       // FIXME: can be `StorageImage`
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("&'a ::std::sync::Arc<{}>", img),
                        "::vulkano::descriptor_set::DescriptorBind::input_attachment(data)"
                    ))
                },
                &parse::Instruction::TypeSampledImage { result_id, image_type_id }
                                                                    if result_id == pointed_ty =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::CombinedImageSampler",
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("(&'a ::std::sync::Arc<::vulkano::sampler::Sampler>, &'a ::std::sync::Arc<{}>)", img),
                        "::vulkano::descriptor_set::DescriptorBind::combined_image_sampler(data.0, data.1)"
                    ))
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));

        descriptors.push(Descriptor {
            name: name,
            desc_ty: desc_ty.to_owned(),
            bind_ty: bind_ty,
            bind_template_params: bind_template_params,
            bind_where_clauses: bind_where_clauses,
            bind: bind.to_owned(),
            set: descriptor_set,
            binding: binding,
        });
    }

    let sets_list = descriptors.iter().map(|d| d.set).collect::<HashSet<u32>>();

    let mut output = String::new();

    // iterate once per set that is defined somewhere
    for set in sets_list.iter() {
        let write_ty = descriptors.iter().filter(|d| d.set == *set)
                                  .map(|d| d.bind_ty.clone())
                                  .collect::<Vec<_>>();

        let write_tp = {
            let v = descriptors.iter().filter(|d| d.set == *set)
                               .map(|d| d.bind_template_params.join(", "))
                               .collect::<Vec<_>>().join(", ");
            if v.is_empty() { v } else { ", ".to_owned() + &v }
        };

        let write_where = {
            let v = descriptors.iter().filter(|d| d.set == *set)
                               .map(|d| d.bind_where_clauses.clone())
                               .collect::<Vec<_>>().join(", ");
            if v.is_empty() { v } else { "where ".to_owned() + &v }
        };

        let writes = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                                .map(|(entry, d)| {
                                    let entry = if write_ty.len() == 1 {
                                        "".to_owned()
                                    } else {
                                        format!(".{}", entry)
                                    };

                                    format!("{{ let data = data{entry};
                                            ::vulkano::descriptor_set::DescriptorWrite {{
                                                 binding: {binding},
                                                 array_element: 0,
                                                 content: {bind},
                                             }} }}", binding = d.binding, bind = d.bind,
                                                     entry = entry)
                                })
                                .collect::<Vec<_>>();

        let write_ty = if write_ty.len() == 1 {
            write_ty.into_iter().next().unwrap()
        } else {
            format!("({})", write_ty.join(", "))
        };

        let descr = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                               .map(|(entry, d)| {
                                   format!("::vulkano::descriptor_set::DescriptorDesc {{
                                                binding: {binding},
                                                ty: {desc_ty},
                                                array_count: 1,
                                                stages: ::vulkano::descriptor_set::ShaderStages::all(),        // TODO:
                                            }}", binding = d.binding, desc_ty = d.desc_ty)
                               })
                               .collect::<Vec<_>>();

        output.push_str(&format!(r#"
#[derive(Default)]
pub struct Set{set};

unsafe impl ::vulkano::descriptor_set::SetLayout for Set{set} {{
    fn descriptors(&self) -> Vec<::vulkano::descriptor_set::DescriptorDesc> {{
        vec![
            {descr}
        ]
    }}
}}

unsafe impl<'a {write_tp}> ::vulkano::descriptor_set::SetLayoutWrite<{write_ty}> for Set{set}
    {write_where}
{{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        vec![
            {writes}
        ]
    }}
}}

unsafe impl<'a {write_tp}> ::vulkano::descriptor_set::SetLayoutInit<{write_ty}> for Set{set}
    {write_where}
{{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        ::vulkano::descriptor_set::SetLayoutWrite::decode(self, data)
    }}
}}

"#, set = set, write_ty = write_ty, writes = writes.join(","), write_tp = write_tp,
    write_where = write_where, descr = descr.join(",")));
    }

    let max_set = sets_list.iter().cloned().max().map(|v| v + 1).unwrap_or(0);

    let sets_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSet<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let sets = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if sets_defs.len() == 1 {
                format!("sets")
            } else {
                format!("sets.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    let layouts_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSetLayout<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let layouts = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if layouts_defs.len() == 1 {
                format!("layouts")
            } else {
                format!("layouts.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    output.push_str(&format!(r#"
#[derive(Default)]
pub struct Layout;

unsafe impl ::vulkano::descriptor_set::Layout for Layout {{
    type DescriptorSets = ({sets_defs});
    type DescriptorSetLayouts = ({layouts_defs});
    type PushConstants = ();

    fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSetLayout>>
    {{
        vec![
            {layouts}
        ]
    }}

    fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSet>>
    {{
        vec![
            {sets}
        ]
    }}
}}
"#, sets_defs = sets_defs.join(","), layouts_defs = layouts_defs.join(","),
    layouts = layouts.join(","), sets = sets.join(",")));

    output
}

/// Assumes that `variable` is a variable with a `TypePointer` and returns the id of the pointed
/// type.
fn pointer_variable_ty(doc: &parse::Spirv, variable: u32) -> u32 {
    let var_ty = doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::Variable { result_type_id, result_id, .. } if result_id == variable => {
                Some(result_type_id)
            },
            _ => None
        }
    }).next().unwrap();

    doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == var_ty => {
                Some(type_id)
            },
            _ => None
        }
    }).next().unwrap()
}
<commit_msg>Fixed using unchecked_uniform_buffer<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::collections::HashSet;

use enums;
use parse;

pub fn write_descriptor_sets(doc: &parse::Spirv) -> String {
    // TODO: not implemented

    // finding all the descriptors
    let mut descriptors = Vec::new();
    struct Descriptor {
        name: String,
        desc_ty: String,
        bind_ty: String,
        bind_template_params: Vec<String>,
        bind_where_clauses: String,
        bind: String,
        set: u32,
        binding: u32,
    }

    // template parameter names that are available for the purpose of the code below
    // TODO: better system
    let mut template_params = vec!["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"].into_iter();

    // looping to find all the elements that have the `DescriptorSet` decoration
    for instruction in doc.instructions.iter() {
        let (variable_id, descriptor_set) = match instruction {
            &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationDescriptorSet, ref params } => {
                (target_id, params[0])
            },
            _ => continue
        };

        // find which type is pointed to by this variable
        let pointed_ty = pointer_variable_ty(doc, variable_id);
        // name of the variable
        let name = ::name_from_id(doc, variable_id);

        // find the binding point of this descriptor
        let binding = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::Decorate { target_id, decoration: enums::Decoration::DecorationBinding, ref params } if target_id == variable_id => {
                    Some(params[0])
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Uniform `{}` is missing a binding", name));

        // find informations about the kind of binding for this descriptor
        let (desc_ty, bind_template_params, bind_where_clauses, bind_ty, bind) = doc.instructions.iter().filter_map(|i| {
            match i {
                &parse::Instruction::TypeStruct { result_id, .. } if result_id == pointed_ty => {
                    let tp_buffer = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::UniformBuffer",
                        vec![tp_buffer.to_owned()],
                        format!("{}: 'static + ::vulkano::buffer::TypedBuffer", tp_buffer),
                        format!("&'a ::std::sync::Arc<{}>", tp_buffer),
                        "::vulkano::descriptor_set::DescriptorBind::uniform_buffer(data)"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(true) =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::SampledImage",
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("&'a ::std::sync::Arc<{}>", img),
                        "::vulkano::descriptor_set::DescriptorBind::sampled_image(data)"
                    ))
                },
                &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, arrayed, ms,
                                                 sampled, ref format, ref access, .. }
                                        if result_id == pointed_ty && sampled == Some(false) =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::InputAttachment",       // FIXME: can be `StorageImage`
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("&'a ::std::sync::Arc<{}>", img),
                        "::vulkano::descriptor_set::DescriptorBind::input_attachment(data)"
                    ))
                },
                &parse::Instruction::TypeSampledImage { result_id, image_type_id }
                                                                    if result_id == pointed_ty =>
                {
                    let img = template_params.next().unwrap();

                    Some((
                        "::vulkano::descriptor_set::DescriptorType::CombinedImageSampler",
                        vec![img.to_owned()],
                        format!("{}: 'static + ::vulkano::image::ImageView", img),
                        format!("(&'a ::std::sync::Arc<::vulkano::sampler::Sampler>, &'a ::std::sync::Arc<{}>)", img),
                        "::vulkano::descriptor_set::DescriptorBind::combined_image_sampler(data.0, data.1)"
                    ))
                },
                _ => None,      // TODO: other types
            }
        }).next().expect(&format!("Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)", name, pointed_ty));

        descriptors.push(Descriptor {
            name: name,
            desc_ty: desc_ty.to_owned(),
            bind_ty: bind_ty,
            bind_template_params: bind_template_params,
            bind_where_clauses: bind_where_clauses,
            bind: bind.to_owned(),
            set: descriptor_set,
            binding: binding,
        });
    }

    let sets_list = descriptors.iter().map(|d| d.set).collect::<HashSet<u32>>();

    let mut output = String::new();

    // iterate once per set that is defined somewhere
    for set in sets_list.iter() {
        let write_ty = descriptors.iter().filter(|d| d.set == *set)
                                  .map(|d| d.bind_ty.clone())
                                  .collect::<Vec<_>>();

        let write_tp = {
            let v = descriptors.iter().filter(|d| d.set == *set)
                               .map(|d| d.bind_template_params.join(", "))
                               .collect::<Vec<_>>().join(", ");
            if v.is_empty() { v } else { ", ".to_owned() + &v }
        };

        let write_where = {
            let v = descriptors.iter().filter(|d| d.set == *set)
                               .map(|d| d.bind_where_clauses.clone())
                               .collect::<Vec<_>>().join(", ");
            if v.is_empty() { v } else { "where ".to_owned() + &v }
        };

        let writes = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                                .map(|(entry, d)| {
                                    let entry = if write_ty.len() == 1 {
                                        "".to_owned()
                                    } else {
                                        format!(".{}", entry)
                                    };

                                    format!("{{ let data = data{entry};
                                            ::vulkano::descriptor_set::DescriptorWrite {{
                                                 binding: {binding},
                                                 array_element: 0,
                                                 content: {bind},
                                             }} }}", binding = d.binding, bind = d.bind,
                                                     entry = entry)
                                })
                                .collect::<Vec<_>>();

        let write_ty = if write_ty.len() == 1 {
            write_ty.into_iter().next().unwrap()
        } else {
            format!("({})", write_ty.join(", "))
        };

        let descr = descriptors.iter().enumerate().filter(|&(_, d)| d.set == *set)
                               .map(|(entry, d)| {
                                   format!("::vulkano::descriptor_set::DescriptorDesc {{
                                                binding: {binding},
                                                ty: {desc_ty},
                                                array_count: 1,
                                                stages: ::vulkano::descriptor_set::ShaderStages::all(),        // TODO:
                                            }}", binding = d.binding, desc_ty = d.desc_ty)
                               })
                               .collect::<Vec<_>>();

        output.push_str(&format!(r#"
#[derive(Default)]
pub struct Set{set};

unsafe impl ::vulkano::descriptor_set::SetLayout for Set{set} {{
    fn descriptors(&self) -> Vec<::vulkano::descriptor_set::DescriptorDesc> {{
        vec![
            {descr}
        ]
    }}
}}

unsafe impl<'a {write_tp}> ::vulkano::descriptor_set::SetLayoutWrite<{write_ty}> for Set{set}
    {write_where}
{{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        vec![
            {writes}
        ]
    }}
}}

unsafe impl<'a {write_tp}> ::vulkano::descriptor_set::SetLayoutInit<{write_ty}> for Set{set}
    {write_where}
{{
    fn decode(&self, data: {write_ty}) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {{
        ::vulkano::descriptor_set::SetLayoutWrite::decode(self, data)
    }}
}}

"#, set = set, write_ty = write_ty, writes = writes.join(","), write_tp = write_tp,
    write_where = write_where, descr = descr.join(",")));
    }

    let max_set = sets_list.iter().cloned().max().map(|v| v + 1).unwrap_or(0);

    let sets_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSet<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let sets = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if sets_defs.len() == 1 {
                format!("sets")
            } else {
                format!("sets.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    let layouts_defs = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            format!("::std::sync::Arc<::vulkano::descriptor_set::DescriptorSetLayout<Set{}>>", num)
        } else {
            "()".to_owned()
        }
    }).collect::<Vec<_>>();

    let layouts = (0 .. max_set).map(|num| {
        if sets_list.contains(&num) {
            if layouts_defs.len() == 1 {
                format!("layouts")
            } else {
                format!("layouts.{}", num)
            }
        } else {
            "()".to_owned()     // FIXME: wrong
        }
    }).collect::<Vec<_>>();

    output.push_str(&format!(r#"
#[derive(Default)]
pub struct Layout;

unsafe impl ::vulkano::descriptor_set::Layout for Layout {{
    type DescriptorSets = ({sets_defs});
    type DescriptorSetLayouts = ({layouts_defs});
    type PushConstants = ();

    fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSetLayout>>
    {{
        vec![
            {layouts}
        ]
    }}

    fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
        -> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSet>>
    {{
        vec![
            {sets}
        ]
    }}
}}
"#, sets_defs = sets_defs.join(","), layouts_defs = layouts_defs.join(","),
    layouts = layouts.join(","), sets = sets.join(",")));

    output
}

/// Assumes that `variable` is a variable with a `TypePointer` and returns the id of the pointed
/// type.
fn pointer_variable_ty(doc: &parse::Spirv, variable: u32) -> u32 {
    let var_ty = doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::Variable { result_type_id, result_id, .. } if result_id == variable => {
                Some(result_type_id)
            },
            _ => None
        }
    }).next().unwrap();

    doc.instructions.iter().filter_map(|i| {
        match i {
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == var_ty => {
                Some(type_id)
            },
            _ => None
        }
    }).next().unwrap()
}
<|endoftext|>