<commit_before>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// 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 std::io;
use std::io::{BufRead, Write};
use std::str::FromStr;

use domain::DomainDispatcher;
use io::*;
use proto::*;
use types::*;

mod input;
mod output;

use self::input::RawInputMessage;
use self::output::RawOutputMessage;

pub struct Oacsp {
    dev: Device,
    domains: DomainDispatcher,
    client_id: Option<String>
}

impl Oacsp {

    pub fn new(dev: Device, domains: DomainDispatcher) -> Oacsp {
        Oacsp { dev: dev, domains: domains, client_id: None }
    }

    fn line_is_ready(&self) -> bool {
        self.dev.recv_bytes().contains(&b'\n')
    }

    fn process_input(&mut self) -> io::Result<usize> {
        assert!(self.line_is_ready());
        let dev_id = self.dev.id();
        let mut buf = io::BufReader::new(self.dev.recv_bytes());
        let mut line = String::new();
        let nbytes = try!(buf.read_line(&mut line));
        let begin_received = self.client_id.is_some();
        match (try!(RawInputMessage::from_str(&line)), begin_received) {
            (RawInputMessage::Begin { version: _, client_id }, false) => {
                info!("received a begin message from client {}", client_id);
            	self.client_id = Some(client_id);
            	Ok(nbytes)
            },
            (RawInputMessage::Begin { version: _, client_id: _ }, true) => {
				Err(io::Error::new(io::ErrorKind::InvalidData, "begin message already received"))
            }
            (RawInputMessage::WriteLvar { lvar, value }, true) => {
                debug!("received a WRITE_LVAR message from client {}: {} <- {}",
                    self.client_id_str(), lvar, value);
                try!(self.domains.with_domain("lvar", |dom| {
					dom.write(&Var::Named(lvar), &value)
                }));
                Ok(nbytes)
            }
            (RawInputMessage::WriteOffset { offset, value }, true) => {
                debug!("received a WRITE_OFFSET message from client {}: {} <- {}",
                    self.client_id_str(), offset, value);
                try!(self.domains.with_domain("fsuipc", |dom| {
					dom.write(&Var::Offset(offset), &value)
                }));
                Ok(nbytes)
            }
            (RawInputMessage::ObserveLvar { lvar }, true) => {
                debug!("received a OBSERVE_LVAR message from client {}: {}",
                    self.client_id_str(), lvar);
                try!(self.domains.with_domain("lvar", |dom| {
					dom.subscribe(dev_id, &Var::Named(lvar))
                }));
                Ok(nbytes)
            }
            (RawInputMessage::ObserveOffset { offset }, true) => {
                debug!("received a OBSERVE_OFFSET message from client {}: {}",
                    self.client_id_str(), offset);
                try!(self.domains.with_domain("fsuipc", |dom| {
					dom.subscribe(dev_id, &Var::Offset(offset))
                }));
                Ok(nbytes)
            }
            (_, false) =>  {
                let error = io::Error::new(
                    io::ErrorKind::InvalidData,
                    "unexpected message while waiting for begin");
				Err(error)
            }
        }
    }

    fn client_id_str(&self) -> &str {
        self.client_id
        	.as_ref()
        	.map(|id| id.as_str())
        	.unwrap_or("none")
    }
}

impl DeviceHandler for Oacsp {
    fn device(&mut self) -> &mut Device { &mut self.dev }

    fn process_event(&mut self, event: Event) -> io::Result<()> {
        match event {
            Event::Ready => self.dev.request_read(),
            Event::BytesRead(_) => {
                if self.line_is_ready() {
                    let nread = try!(self.process_input());
                    self.dev.consume_recv_buffer(nread);
                }
                self.dev.request_read()
            }
            Event::BytesWritten(_) => Ok(()),
        }
    }
}

impl Protocol for Oacsp {

    fn send_update(&mut self, domain: &str, variable: Var, value: Value) -> io::Result<()> {
        let raw = try!(match variable {
            Var::Offset(offset) if domain == "fsuipc" =>
                Ok(RawOutputMessage::EventOffset { offset: offset, value: value }),
            Var::Named(ref lvar) if domain == "lvar" =>
                Ok(RawOutputMessage::EventLvar { lvar: lvar.clone(), value: value }),
            _ => {
                Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("cannot encode a message for domain '{}', var '{:?}'",
                        domain, variable)))
            }
        });
        let mut buf = Vec::new();
        try!(write!(&mut buf, "{}\n", raw));
        self.dev.request_write(&buf)
    }
}
<commit_msg>Bug fixing: process all queued messages before requesting bytes<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// 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 std::io;
use std::io::{BufRead, Write};
use std::str::FromStr;

use domain::DomainDispatcher;
use io::*;
use proto::*;
use types::*;

mod input;
mod output;

use self::input::RawInputMessage;
use self::output::RawOutputMessage;

pub struct Oacsp {
    dev: Device,
    domains: DomainDispatcher,
    client_id: Option<String>
}

impl Oacsp {

    pub fn new(dev: Device, domains: DomainDispatcher) -> Oacsp {
        Oacsp { dev: dev, domains: domains, client_id: None }
    }

    fn line_is_ready(&self) -> bool {
        self.dev.recv_bytes().contains(&b'\n')
    }

    fn process_input(&mut self) -> io::Result<usize> {
        assert!(self.line_is_ready());
        let dev_id = self.dev.id();
        let mut buf = io::BufReader::new(self.dev.recv_bytes());
        let mut line = String::new();
        let nbytes = try!(buf.read_line(&mut line));
        let begin_received = self.client_id.is_some();
        match (try!(RawInputMessage::from_str(&line)), begin_received) {
            (RawInputMessage::Begin { version: _, client_id }, false) => {
                info!("received a begin message from client {}", client_id);
            	self.client_id = Some(client_id);
            	Ok(nbytes)
            },
            (RawInputMessage::Begin { version: _, client_id: _ }, true) => {
				Err(io::Error::new(io::ErrorKind::InvalidData, "begin message already received"))
            }
            (RawInputMessage::WriteLvar { lvar, value }, true) => {
                debug!("received a WRITE_LVAR message from client {}: {} <- {}",
                    self.client_id_str(), lvar, value);
                try!(self.domains.with_domain("lvar", |dom| {
					dom.write(&Var::Named(lvar), &value)
                }));
                Ok(nbytes)
            }
            (RawInputMessage::WriteOffset { offset, value }, true) => {
                debug!("received a WRITE_OFFSET message from client {}: {} <- {}",
                    self.client_id_str(), offset, value);
                try!(self.domains.with_domain("fsuipc", |dom| {
					dom.write(&Var::Offset(offset), &value)
                }));
                Ok(nbytes)
            }
            (RawInputMessage::ObserveLvar { lvar }, true) => {
                debug!("received a OBSERVE_LVAR message from client {}: {}",
                    self.client_id_str(), lvar);
                try!(self.domains.with_domain("lvar", |dom| {
					dom.subscribe(dev_id, &Var::Named(lvar))
                }));
                Ok(nbytes)
            }
            (RawInputMessage::ObserveOffset { offset }, true) => {
                debug!("received a OBSERVE_OFFSET message from client {}: {}",
                    self.client_id_str(), offset);
                try!(self.domains.with_domain("fsuipc", |dom| {
					dom.subscribe(dev_id, &Var::Offset(offset))
                }));
                Ok(nbytes)
            }
            (_, false) =>  {
                let error = io::Error::new(
                    io::ErrorKind::InvalidData,
                    "unexpected message while waiting for begin");
				Err(error)
            }
        }
    }

    fn client_id_str(&self) -> &str {
        self.client_id
        	.as_ref()
        	.map(|id| id.as_str())
        	.unwrap_or("none")
    }
}

impl DeviceHandler for Oacsp {
    fn device(&mut self) -> &mut Device { &mut self.dev }

    fn process_event(&mut self, event: Event) -> io::Result<()> {
        match event {
            Event::Ready => self.dev.request_read(),
            Event::BytesRead(_) => {
                while self.line_is_ready() {
                    let nread = try!(self.process_input());
                    self.dev.consume_recv_buffer(nread);
                }
                self.dev.request_read()
            }
            Event::BytesWritten(_) => Ok(()),
        }
    }
}

impl Protocol for Oacsp {

    fn send_update(&mut self, domain: &str, variable: Var, value: Value) -> io::Result<()> {
        let raw = try!(match variable {
            Var::Offset(offset) if domain == "fsuipc" =>
                Ok(RawOutputMessage::EventOffset { offset: offset, value: value }),
            Var::Named(ref lvar) if domain == "lvar" =>
                Ok(RawOutputMessage::EventLvar { lvar: lvar.clone(), value: value }),
            _ => {
                Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("cannot encode a message for domain '{}', var '{:?}'",
                        domain, variable)))
            }
        });
        let mut buf = Vec::new();
        try!(write!(&mut buf, "{}\n", raw));
        self.dev.request_write(&buf)
    }
}
<|endoftext|>


<commit_before>
use std::mem;
use std::ptr;
use std::slice::raw::mut_buf_as_slice;
use collections::treemap::TreeMap;

use cgmath::vector::Vector4;
use gl;

use snowmew::ObjectKey;
use graphics::{Material, Graphics};

#[packed]
struct MaterialStd140 {
    ka: Vector4<f32>,
    kd: Vector4<f32>,
    ks: Vector4<f32>,
    ka_texture: (i32, i32),
    kd_texture: (i32, i32),
    ks_texture: (i32, i32),
    ns: f32,
    ni: f32
}

fn get_mat(ka: Option<ObjectKey>, rd: &Graphics) -> (i32, i32) {
    match ka {
        Some(ref ka) => {
            let (a, b) = *rd.get_texture_atlas_index(*ka).expect("Could not find index");
            (a as i32, b as i32)
        }
        None => (-1i32, 0i32)
    }
}

impl MaterialStd140 {
    pub fn from(mat: &Material, rd: &Graphics) -> MaterialStd140 {
        let ka = mat.Ka();
        let kd = mat.Kd();
        let ks = mat.Ks();

        MaterialStd140 {
            ka: Vector4::new(ka.x, ka.y, ka.z, 1.),
            kd: Vector4::new(kd.x, kd.y, kd.z, 1.),
            ks: Vector4::new(ks.x, ks.y, ks.z, 1.),
            ka_texture: get_mat(mat.map_Ka(), rd),
            kd_texture: get_mat(mat.map_Kd(), rd),
            ks_texture: get_mat(mat.map_Ks(), rd),
            ns: mat.ns(),
            ni: mat.ni()
        }
    }
}

pub struct MaterialBuffer {
    buffer: u32,
    size: uint,
    ptr: *mut MaterialStd140,
    material_to_id: TreeMap<ObjectKey, u32>,
    id_to_material: TreeMap<u32, ObjectKey>,
}

impl MaterialBuffer {
    pub fn new(max: uint) -> MaterialBuffer {
        let ub = &mut [0];

        unsafe {
            gl::GenBuffers(1, ub.unsafe_mut_ref(0));
            gl::BindBuffer(gl::UNIFORM_BUFFER, ub[0]);
            gl::BufferData(gl::UNIFORM_BUFFER,
                           (max * mem::size_of::<MaterialStd140>()) as i64,
                           ptr::null(),
                           gl::DYNAMIC_DRAW);
            gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
        }

        MaterialBuffer {
            buffer: ub[0],
            size: max,
            ptr: ptr::mut_null(),
            material_to_id: TreeMap::new(),
            id_to_material: TreeMap::new()
        }
    }

    pub fn map(&mut self) {
        gl::BindBuffer(gl::UNIFORM_BUFFER, self.buffer);
        self.ptr = gl::MapBufferRange(gl::UNIFORM_BUFFER, 0,
                                      (self.size * mem::size_of::<MaterialStd140>()) as i64,
                                      gl::MAP_WRITE_BIT) as *mut MaterialStd140;
        gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
    }

    pub fn unmap(&mut self) {
        self.ptr = ptr::mut_null();
        gl::BindBuffer(gl::UNIFORM_BUFFER, self.buffer);
        gl::UnmapBuffer(gl::UNIFORM_BUFFER);
        gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
    }

    pub fn build(&mut self, graphics: &Graphics) {
        self.material_to_id.clear();
        self.id_to_material.clear();
        unsafe {
            mut_buf_as_slice(self.ptr, self.size, |b| {
                for (id, (key, mat)) in graphics.material_iter().enumerate() {
                    b[id] = MaterialStd140::from(mat, graphics);
                    self.material_to_id.insert(*key, (id+1) as u32);
                    self.id_to_material.insert((id+1) as u32, *key);
                }
            });
        }
    }

    pub fn id(&self) -> u32 {self.buffer}
}<commit_msg>remove id to material bindings<commit_after>
use std::mem;
use std::ptr;
use std::slice::raw::mut_buf_as_slice;

use cgmath::vector::Vector4;
use gl;

use snowmew::ObjectKey;
use graphics::{Material, Graphics};

#[packed]
struct MaterialStd140 {
    ka: Vector4<f32>,
    kd: Vector4<f32>,
    ks: Vector4<f32>,
    ka_texture: (i32, i32),
    kd_texture: (i32, i32),
    ks_texture: (i32, i32),
    ns: f32,
    ni: f32
}

fn get_mat(ka: Option<ObjectKey>, rd: &Graphics) -> (i32, i32) {
    match ka {
        Some(ref ka) => {
            let (a, b) = *rd.get_texture_atlas_index(*ka).expect("Could not find index");
            (a as i32, b as i32)
        }
        None => (-1i32, 0i32)
    }
}

impl MaterialStd140 {
    pub fn from(mat: &Material, rd: &Graphics) -> MaterialStd140 {
        let ka = mat.Ka();
        let kd = mat.Kd();
        let ks = mat.Ks();

        MaterialStd140 {
            ka: Vector4::new(ka.x, ka.y, ka.z, 1.),
            kd: Vector4::new(kd.x, kd.y, kd.z, 1.),
            ks: Vector4::new(ks.x, ks.y, ks.z, 1.),
            ka_texture: get_mat(mat.map_Ka(), rd),
            kd_texture: get_mat(mat.map_Kd(), rd),
            ks_texture: get_mat(mat.map_Ks(), rd),
            ns: mat.ns(),
            ni: mat.ni()
        }
    }
}

pub struct MaterialBuffer {
    buffer: u32,
    size: uint,
    ptr: *mut MaterialStd140,
}

impl MaterialBuffer {
    pub fn new(max: uint) -> MaterialBuffer {
        let ub = &mut [0];

        unsafe {
            gl::GenBuffers(1, ub.unsafe_mut_ref(0));
            gl::BindBuffer(gl::UNIFORM_BUFFER, ub[0]);
            gl::BufferData(gl::UNIFORM_BUFFER,
                           (max * mem::size_of::<MaterialStd140>()) as i64,
                           ptr::null(),
                           gl::DYNAMIC_DRAW);
            gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
        }

        MaterialBuffer {
            buffer: ub[0],
            size: max,
            ptr: ptr::mut_null(),
        }
    }

    pub fn map(&mut self) {
        gl::BindBuffer(gl::UNIFORM_BUFFER, self.buffer);
        self.ptr = gl::MapBufferRange(gl::UNIFORM_BUFFER, 0,
                                      (self.size * mem::size_of::<MaterialStd140>()) as i64,
                                      gl::MAP_WRITE_BIT) as *mut MaterialStd140;
        gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
    }

    pub fn unmap(&mut self) {
        self.ptr = ptr::mut_null();
        gl::BindBuffer(gl::UNIFORM_BUFFER, self.buffer);
        gl::UnmapBuffer(gl::UNIFORM_BUFFER);
        gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
    }

    pub fn build(&mut self, graphics: &Graphics) {
        unsafe {
            mut_buf_as_slice(self.ptr, self.size, |b| {
                for (id, (_, mat)) in graphics.material_iter().enumerate() {
                    b[id] = MaterialStd140::from(mat, graphics);
                }
            });
        }
    }

    pub fn id(&self) -> u32 {self.buffer}
}<|endoftext|>


<commit_before>// Copyright 2016 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.

enum Foo {
    Bar(u32),
}

fn do_something(x: Foo::Bar) { } //~ ERROR E0248

fn main() {
}
<commit_msg>E0248 Change in issue format<commit_after>// Copyright 2016 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.

enum Foo {
    Bar(u32),
}

fn do_something(x: Foo::Bar) { } //~ ERROR E0248
                //~| NOTE value used as a type
fn main() {
}
<|endoftext|>


<commit_before>use std;

import std::task;
import std::task::task;
import std::comm;
import std::comm::chan;
import std::comm::port;
import std::comm::send;
import std::comm::recv;

fn main() {
    test00();
    // test01();
    test02();
    test03();
    test04();
    test05();
    test06();
}

fn test00_start(ch: chan<int>, message: int, count: int) {
    log "Starting test00_start";
    let i: int = 0;
    while i < count {
        log "Sending Message";
        send(ch, message + 0);
        i = i + 1;
    }
    log "Ending test00_start";
}

fn test00() {
    let number_of_tasks: int = 1;
    let number_of_messages: int = 4;
    log "Creating tasks";

    let po = port();
    let ch = chan(po);

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        let thunk = bind test00_start(ch, i, number_of_messages);
        tasks += [task::spawn_joinable(thunk)];
    }
    let sum: int = 0;
    for t in tasks {
        i = 0;
        while i < number_of_messages { sum += recv(po); i = i + 1; }
    }

    for t in tasks { task::join(t); }

    log "Completed: Final number is: ";
    assert (sum ==
                number_of_messages *
                    (number_of_tasks * number_of_tasks + number_of_tasks) /
                    2);
}

fn test01() {
    let p = port();
    log "Reading from a port that is never written to.";
    let value: int = recv(p);
    log value;
}

fn test02() {
    let p = port();
    let c = chan(p);
    log "Writing to a local task channel.";
    send(c, 42);
    log "Reading from a local task port.";
    let value: int = recv(p);
    log value;
}

obj vector(mutable x: int, y: int) {
    fn length() -> int { x = x + 2; ret x + y; }
}

fn test03() {
    log "Creating object ...";
    let v: vector = vector(1, 2);
    log "created object ...";
    let t: vector = v;
    log v.length();
}

fn test04_start() {
    log "Started task";
    let i: int = 1024 * 1024 * 64;
    while i > 0 { i = i - 1; }
    log "Finished task";
}

fn test04() {
    log "Spawning lots of tasks.";
    let i: int = 4;
    while i > 0 { i = i - 1; let f = test04_start; task::spawn(f); }
    log "Finishing up.";
}

fn test05_start(ch: chan<int>) {
    send(ch, 10);
    send(ch, 20);
    send(ch, 30);
    send(ch, 30);
    send(ch, 30);
}

fn test05() {
    let po = comm::port();
    let ch = chan(po);
    task::spawn(bind test05_start(ch));
    let value: int;
    value = recv(po);
    value = recv(po);
    value = recv(po);
    log value;
}

fn test06_start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 100000000 { i = i + 1; }
    log "Finished task.";
}

fn test06() {
    let number_of_tasks: int = 4;
    log "Creating tasks";

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::spawn_joinable(bind test06_start(i))];
    }

    for t in tasks { task::join(t); }
}

<commit_msg>Do less work in run-pass/task-comm.rs<commit_after>use std;

import std::task;
import std::task::task;
import std::comm;
import std::comm::chan;
import std::comm::port;
import std::comm::send;
import std::comm::recv;

fn main() {
    test00();
    // test01();
    test02();
    test03();
    test04();
    test05();
    test06();
}

fn test00_start(ch: chan<int>, message: int, count: int) {
    log "Starting test00_start";
    let i: int = 0;
    while i < count {
        log "Sending Message";
        send(ch, message + 0);
        i = i + 1;
    }
    log "Ending test00_start";
}

fn test00() {
    let number_of_tasks: int = 1;
    let number_of_messages: int = 4;
    log "Creating tasks";

    let po = port();
    let ch = chan(po);

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        let thunk = bind test00_start(ch, i, number_of_messages);
        tasks += [task::spawn_joinable(thunk)];
    }
    let sum: int = 0;
    for t in tasks {
        i = 0;
        while i < number_of_messages { sum += recv(po); i = i + 1; }
    }

    for t in tasks { task::join(t); }

    log "Completed: Final number is: ";
    assert (sum ==
                number_of_messages *
                    (number_of_tasks * number_of_tasks + number_of_tasks) /
                    2);
}

fn test01() {
    let p = port();
    log "Reading from a port that is never written to.";
    let value: int = recv(p);
    log value;
}

fn test02() {
    let p = port();
    let c = chan(p);
    log "Writing to a local task channel.";
    send(c, 42);
    log "Reading from a local task port.";
    let value: int = recv(p);
    log value;
}

obj vector(mutable x: int, y: int) {
    fn length() -> int { x = x + 2; ret x + y; }
}

fn test03() {
    log "Creating object ...";
    let v: vector = vector(1, 2);
    log "created object ...";
    let t: vector = v;
    log v.length();
}

fn test04_start() {
    log "Started task";
    let i: int = 1024 * 1024;
    while i > 0 { i = i - 1; }
    log "Finished task";
}

fn test04() {
    log "Spawning lots of tasks.";
    let i: int = 4;
    while i > 0 { i = i - 1; let f = test04_start; task::spawn(f); }
    log "Finishing up.";
}

fn test05_start(ch: chan<int>) {
    send(ch, 10);
    send(ch, 20);
    send(ch, 30);
    send(ch, 30);
    send(ch, 30);
}

fn test05() {
    let po = comm::port();
    let ch = chan(po);
    task::spawn(bind test05_start(ch));
    let value: int;
    value = recv(po);
    value = recv(po);
    value = recv(po);
    log value;
}

fn test06_start(task_number: int) {
    log "Started task.";
    let i: int = 0;
    while i < 1000000 { i = i + 1; }
    log "Finished task.";
}

fn test06() {
    let number_of_tasks: int = 4;
    log "Creating tasks";

    let i: int = 0;

    let tasks = [];
    while i < number_of_tasks {
        i = i + 1;
        tasks += [task::spawn_joinable(bind test06_start(i))];
    }

    for t in tasks { task::join(t); }
}

<|endoftext|>


<commit_before>// Copyright 2018 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.

// ignore-stage1

#![crate_type="proc-macro"]
#![crate_name="some_macros"]

extern crate proc_macro;

use proc_macro::TokenStream;

// @has some_macros/index.html
// @has - '//h2' 'Macros'
// @has - '//h2' 'Attribute Macros'
// @has - '//h2' 'Derive Macros'
// @!has - '//h2' 'Functions'

// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html'
// @!has - '//a/@href' 'fn.some_proc_macro.html'
// @has some_macros/macro.some_proc_macro.html
// @!has some_macros/fn.some_proc_macro.html
/// a proc-macro that swallows its input and does nothing.
#[proc_macro]
pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
    TokenStream::new()
}

// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html'
// @!has - '//a/@href' 'fn.some_proc_attr.html'
// @has some_macros/attr.some_proc_attr.html
// @!has some_macros/fn.some_proc_attr.html
/// a proc-macro attribute that passes its item through verbatim.
#[proc_macro_attribute]
pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}

// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html'
// @!has - '//a/@href' 'fn.some_derive.html'
// @has some_macros/derive.SomeDerive.html
// @!has some_macros/fn.some_derive.html
/// a derive attribute that adds nothing to its input.
#[proc_macro_derive(SomeDerive)]
pub fn some_derive(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}
<commit_msg>check for proc-macros in "all items"<commit_after>// Copyright 2018 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.

// ignore-stage1

#![crate_type="proc-macro"]
#![crate_name="some_macros"]

extern crate proc_macro;

use proc_macro::TokenStream;

// @has some_macros/index.html
// @has - '//h2' 'Macros'
// @has - '//h2' 'Attribute Macros'
// @has - '//h2' 'Derive Macros'
// @!has - '//h2' 'Functions'

// @has some_macros/all.html
// @has - '//a[@href="macro.some_proc_macro.html"]' 'some_proc_macro'
// @has - '//a[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
// @has - '//a[@href="derive.SomeDerive.html"]' 'SomeDerive'
// @!has - '//a/@href' 'fn.some_proc_macro.html'
// @!has - '//a/@href' 'fn.some_proc_attr.html'
// @!has - '//a/@href' 'fn.some_derive.html'

// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html'
// @!has - '//a/@href' 'fn.some_proc_macro.html'
// @has some_macros/macro.some_proc_macro.html
// @!has some_macros/fn.some_proc_macro.html
/// a proc-macro that swallows its input and does nothing.
#[proc_macro]
pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
    TokenStream::new()
}

// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html'
// @!has - '//a/@href' 'fn.some_proc_attr.html'
// @has some_macros/attr.some_proc_attr.html
// @!has some_macros/fn.some_proc_attr.html
/// a proc-macro attribute that passes its item through verbatim.
#[proc_macro_attribute]
pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}

// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html'
// @!has - '//a/@href' 'fn.some_derive.html'
// @has some_macros/derive.SomeDerive.html
// @!has some_macros/fn.some_derive.html
/// a derive attribute that adds nothing to its input.
#[proc_macro_derive(SomeDerive)]
pub fn some_derive(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}
<|endoftext|>


<commit_before>use cookie::Cookie;
use headers::{self, HeaderMapExt};
use http::{Response, StatusCode};

use crate::service::dto;
use crate::service::test::{constants::*, ServiceType, TestService};
use crate::test_name;

fn validate_cookies<T>(response: &Response<T>) {
	let cookies: Vec<Cookie> = response
		.headers()
		.get_all(http::header::SET_COOKIE)
		.iter()
		.map(|c| Cookie::parse(c.to_str().unwrap()).unwrap())
		.collect();
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_SESSION));
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_USERNAME));
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_ADMIN));
}

#[test]
fn test_login_rejects_bad_username() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service.request_builder().login("garbage", TEST_PASSWORD);
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_login_rejects_bad_password() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service.request_builder().login(TEST_USERNAME, "garbage");
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_login_golden_path() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service
		.request_builder()
		.login(TEST_USERNAME, TEST_PASSWORD);
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::OK);

	validate_cookies(&response);
}

#[test]
fn test_authentication_via_http_header_rejects_bad_username() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic("garbage", TEST_PASSWORD);
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_authentication_via_http_header_rejects_bad_password() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic(TEST_PASSWORD, "garbage");
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_authentication_via_http_header_golden_path() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic(TEST_USERNAME, TEST_PASSWORD);
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::OK);

	validate_cookies(&response);
}
<commit_msg>Added tests that auth cookie headers are not emitted in all requests<commit_after>use cookie::Cookie;
use headers::{self, HeaderMapExt};
use http::{Response, StatusCode};

use crate::service::dto;
use crate::service::test::{constants::*, ServiceType, TestService};
use crate::test_name;

fn validate_cookies<T>(response: &Response<T>) {
	let cookies: Vec<Cookie> = response
		.headers()
		.get_all(http::header::SET_COOKIE)
		.iter()
		.map(|c| Cookie::parse(c.to_str().unwrap()).unwrap())
		.collect();
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_SESSION));
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_USERNAME));
	assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_ADMIN));
}

fn validate_no_cookies<T>(response: &Response<T>) {
	let cookies: Vec<Cookie> = response
		.headers()
		.get_all(http::header::SET_COOKIE)
		.iter()
		.map(|c| Cookie::parse(c.to_str().unwrap()).unwrap())
		.collect();
	assert!(!cookies.iter().any(|c| c.name() == dto::COOKIE_SESSION));
	assert!(!cookies.iter().any(|c| c.name() == dto::COOKIE_USERNAME));
	assert!(!cookies.iter().any(|c| c.name() == dto::COOKIE_ADMIN));
}

#[test]
fn test_login_rejects_bad_username() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service.request_builder().login("garbage", TEST_PASSWORD);
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_login_rejects_bad_password() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service.request_builder().login(TEST_USERNAME, "garbage");
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_login_golden_path() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let request = service
		.request_builder()
		.login(TEST_USERNAME, TEST_PASSWORD);
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::OK);

	validate_cookies(&response);
}

#[test]
fn test_requests_without_auth_header_do_not_set_cookies() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();
	service.login();

	let request = service.request_builder().random();
	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::OK);

	validate_no_cookies(&response);
}

#[test]
fn test_authentication_via_http_header_rejects_bad_username() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic("garbage", TEST_PASSWORD);
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_authentication_via_http_header_rejects_bad_password() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic(TEST_PASSWORD, "garbage");
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[test]
fn test_authentication_via_http_header_golden_path() {
	let mut service = ServiceType::new(&test_name!());
	service.complete_initial_setup();

	let mut request = service.request_builder().random();
	let basic = headers::Authorization::basic(TEST_USERNAME, TEST_PASSWORD);
	request.headers_mut().typed_insert(basic);

	let response = service.fetch(&request);
	assert_eq!(response.status(), StatusCode::OK);

	validate_cookies(&response);
}
<|endoftext|>


<commit_before>use crate::ast::Field;
use crate::attr::{Display, Trait};
use proc_macro2::TokenTree;
use quote::{format_ident, quote_spanned};
use std::collections::{BTreeSet as Set, HashMap as Map};
use syn::ext::IdentExt;
use syn::parse::{ParseStream, Parser};
use syn::{Ident, Index, LitStr, Member, Result, Token};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self, fields: &[Field]) {
        let raw_args = self.args.clone();
        let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
        let mut member_index = Map::new();
        for (i, field) in fields.iter().enumerate() {
            member_index.insert(field.member.clone(), i);
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = self.args.clone();
        let mut has_bonus_display = false;
        let mut implied_bounds = Set::new();

        let mut has_trailing_comma = false;
        if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
            if punct.as_char() == ',' {
                has_trailing_comma = true;
            }
        }

        while let Some(brace) = read.find('{') {
            out += &read[..brace + 1];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let member = match next {
                '0'..='9' => {
                    let int = take_int(&mut read);
                    let member = match int.parse::<u32>() {
                        Ok(index) => Member::Unnamed(Index { index, span }),
                        Err(_) => return,
                    };
                    if !member_index.contains_key(&member) {
                        out += ∫
                        continue;
                    }
                    member
                }
                'a'..='z' | 'A'..='Z' | '_' => {
                    let mut ident = take_ident(&mut read);
                    ident.set_span(span);
                    Member::Named(ident)
                }
                _ => continue,
            };
            if let Some(&field) = member_index.get(&member) {
                let end_spec = match read.find('}') {
                    Some(end_spec) => end_spec,
                    None => return,
                };
                let bound = match read[..end_spec].chars().next_back() {
                    Some('?') => Trait::Debug,
                    Some('o') => Trait::Octal,
                    Some('x') => Trait::LowerHex,
                    Some('X') => Trait::UpperHex,
                    Some('p') => Trait::Pointer,
                    Some('b') => Trait::Binary,
                    Some('e') => Trait::LowerExp,
                    Some('E') => Trait::UpperExp,
                    Some(_) | None => Trait::Display,
                };
                implied_bounds.insert((field, bound));
            }
            let local = match &member {
                Member::Unnamed(index) => format_ident!("_{}", index),
                Member::Named(ident) => ident.clone(),
            };
            let mut formatvar = local.clone();
            if formatvar.to_string().starts_with("r#") {
                formatvar = format_ident!("r_{}", formatvar);
            }
            if formatvar.to_string().starts_with('_') {
                // Work around leading underscore being rejected by 1.40 and
                // older compilers. https://github.com/rust-lang/rust/pull/66847
                formatvar = format_ident!("field_{}", formatvar);
            }
            out += &formatvar.to_string();
            if !named_args.insert(formatvar.clone()) {
                // Already specified in the format argument list.
                continue;
            }
            if !has_trailing_comma {
                args.extend(quote_spanned!(span=> ,));
            }
            args.extend(quote_spanned!(span=> #formatvar = #local));
            if read.starts_with('}') && member_index.contains_key(&member) {
                has_bonus_display = true;
                args.extend(quote_spanned!(span=> .as_display()));
            }
            has_trailing_comma = false;
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.has_bonus_display = has_bonus_display;
        self.implied_bounds = implied_bounds;
    }
}

fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
    let mut named_args = Set::new();

    while !input.is_empty() {
        if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
            input.parse::<Token![,]>()?;
            let ident = input.call(Ident::parse_any)?;
            input.parse::<Token![=]>()?;
            named_args.insert(ident);
        } else {
            input.parse::<TokenTree>()?;
        }
    }

    Ok(named_args)
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> Ident {
    let mut ident = String::new();
    let raw = read.starts_with("r#");
    if raw {
        ident.push_str("r#");
        *read = &read[2..];
    }
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    Ident::parse_any.parse_str(&ident).unwrap()
}
<commit_msg>Skip a redundant Member clone<commit_after>use crate::ast::Field;
use crate::attr::{Display, Trait};
use proc_macro2::TokenTree;
use quote::{format_ident, quote_spanned};
use std::collections::{BTreeSet as Set, HashMap as Map};
use syn::ext::IdentExt;
use syn::parse::{ParseStream, Parser};
use syn::{Ident, Index, LitStr, Member, Result, Token};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self, fields: &[Field]) {
        let raw_args = self.args.clone();
        let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
        let mut member_index = Map::new();
        for (i, field) in fields.iter().enumerate() {
            member_index.insert(&field.member, i);
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = self.args.clone();
        let mut has_bonus_display = false;
        let mut implied_bounds = Set::new();

        let mut has_trailing_comma = false;
        if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
            if punct.as_char() == ',' {
                has_trailing_comma = true;
            }
        }

        while let Some(brace) = read.find('{') {
            out += &read[..brace + 1];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let member = match next {
                '0'..='9' => {
                    let int = take_int(&mut read);
                    let member = match int.parse::<u32>() {
                        Ok(index) => Member::Unnamed(Index { index, span }),
                        Err(_) => return,
                    };
                    if !member_index.contains_key(&member) {
                        out += ∫
                        continue;
                    }
                    member
                }
                'a'..='z' | 'A'..='Z' | '_' => {
                    let mut ident = take_ident(&mut read);
                    ident.set_span(span);
                    Member::Named(ident)
                }
                _ => continue,
            };
            if let Some(&field) = member_index.get(&member) {
                let end_spec = match read.find('}') {
                    Some(end_spec) => end_spec,
                    None => return,
                };
                let bound = match read[..end_spec].chars().next_back() {
                    Some('?') => Trait::Debug,
                    Some('o') => Trait::Octal,
                    Some('x') => Trait::LowerHex,
                    Some('X') => Trait::UpperHex,
                    Some('p') => Trait::Pointer,
                    Some('b') => Trait::Binary,
                    Some('e') => Trait::LowerExp,
                    Some('E') => Trait::UpperExp,
                    Some(_) | None => Trait::Display,
                };
                implied_bounds.insert((field, bound));
            }
            let local = match &member {
                Member::Unnamed(index) => format_ident!("_{}", index),
                Member::Named(ident) => ident.clone(),
            };
            let mut formatvar = local.clone();
            if formatvar.to_string().starts_with("r#") {
                formatvar = format_ident!("r_{}", formatvar);
            }
            if formatvar.to_string().starts_with('_') {
                // Work around leading underscore being rejected by 1.40 and
                // older compilers. https://github.com/rust-lang/rust/pull/66847
                formatvar = format_ident!("field_{}", formatvar);
            }
            out += &formatvar.to_string();
            if !named_args.insert(formatvar.clone()) {
                // Already specified in the format argument list.
                continue;
            }
            if !has_trailing_comma {
                args.extend(quote_spanned!(span=> ,));
            }
            args.extend(quote_spanned!(span=> #formatvar = #local));
            if read.starts_with('}') && member_index.contains_key(&member) {
                has_bonus_display = true;
                args.extend(quote_spanned!(span=> .as_display()));
            }
            has_trailing_comma = false;
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.has_bonus_display = has_bonus_display;
        self.implied_bounds = implied_bounds;
    }
}

fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
    let mut named_args = Set::new();

    while !input.is_empty() {
        if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
            input.parse::<Token![,]>()?;
            let ident = input.call(Ident::parse_any)?;
            input.parse::<Token![=]>()?;
            named_args.insert(ident);
        } else {
            input.parse::<TokenTree>()?;
        }
    }

    Ok(named_args)
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> Ident {
    let mut ident = String::new();
    let raw = read.starts_with("r#");
    if raw {
        ident.push_str("r#");
        *read = &read[2..];
    }
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    Ident::parse_any.parse_str(&ident).unwrap()
}
<|endoftext|>


<commit_before>use base64;
use line_wrap;
use std::{borrow::Cow, io::Write};
use xml_rs::{
    name::Name,
    namespace::Namespace,
    writer::{EmitterConfig, Error as XmlWriterError, EventWriter, XmlEvent},
};

use crate::{
    error::{self, Error, ErrorKind, EventKind},
    stream::{Writer, XmlWriteOptions},
    Date, Integer, Uid,
};

static XML_PROLOGUE: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
"#;

#[derive(PartialEq)]
enum Element {
    Dictionary,
    Array,
}

pub struct XmlWriter<W: Write> {
    xml_writer: EventWriter<W>,
    stack: Vec<Element>,
    expecting_key: bool,
    written_prologue: bool,
    // Not very nice
    empty_namespace: Namespace,
}

impl<W: Write> XmlWriter<W> {
    pub fn new(writer: W) -> XmlWriter<W> {
        let opts = XmlWriteOptions::default();
        XmlWriter::new_with_options(writer, &opts)
    }

    pub fn new_with_options(writer: W, opts: &XmlWriteOptions) -> XmlWriter<W> {
        let config = EmitterConfig::new()
            .line_separator("\n")
            .indent_string(opts.indent_str.clone())
            .perform_indent(true)
            .write_document_declaration(false)
            .normalize_empty_elements(true)
            .cdata_to_characters(true)
            .keep_element_names_stack(false)
            .autopad_comments(true);

        XmlWriter {
            xml_writer: EventWriter::new_with_config(writer, config),
            stack: Vec::new(),
            expecting_key: false,
            written_prologue: false,
            empty_namespace: Namespace::empty(),
        }
    }

    fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), Error> {
        self.start_element(name)?;
        self.write_value(value)?;
        self.end_element(name)?;
        Ok(())
    }

    fn start_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::StartElement {
                name: Name::local(name),
                attributes: Cow::Borrowed(&[]),
                namespace: Cow::Borrowed(&self.empty_namespace),
            })
            .map_err(from_xml_error)?;
        Ok(())
    }

    fn end_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::EndElement {
                name: Some(Name::local(name)),
            })
            .map_err(from_xml_error)?;
        Ok(())
    }

    fn write_value(&mut self, value: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::Characters(value))
            .map_err(from_xml_error)?;
        Ok(())
    }

    pub fn into_inner(self) -> W {
        self.xml_writer.into_inner()
    }

    fn write_event<F: FnOnce(&mut Self) -> Result<(), Error>>(
        &mut self,
        f: F,
    ) -> Result<(), Error> {
        if !self.written_prologue {
            self.xml_writer
                .inner_mut()
                .write_all(XML_PROLOGUE.as_bytes())
                .map_err(error::from_io_without_position)?;

            self.written_prologue = true;
        }

        f(self)?;

        // If there are no more open tags then write the </plist> element
        if self.stack.is_empty() {
            // We didn't tell the xml_writer about the <plist> tag so we'll skip telling it
            // about the </plist> tag as well.
            self.xml_writer
                .inner_mut()
                .write_all(b"\n</plist>")
                .map_err(error::from_io_without_position)?;
            self.xml_writer
                .inner_mut()
                .flush()
                .map_err(error::from_io_without_position)?;
        }

        Ok(())
    }

    fn write_value_event<F: FnOnce(&mut Self) -> Result<(), Error>>(
        &mut self,
        event_kind: EventKind,
        f: F,
    ) -> Result<(), Error> {
        self.write_event(|this| {
            if this.expecting_key {
                return Err(ErrorKind::UnexpectedEventType {
                    expected: EventKind::DictionaryKeyOrEndCollection,
                    found: event_kind,
                }
                .without_position());
            }
            f(this)?;
            this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            Ok(())
        })
    }
}

impl<W: Write> Writer for XmlWriter<W> {
    fn write_start_array(&mut self, _len: Option<u64>) -> Result<(), Error> {
        self.write_value_event(EventKind::StartArray, |this| {
            this.start_element("array")?;
            this.stack.push(Element::Array);
            Ok(())
        })
    }

    fn write_start_dictionary(&mut self, _len: Option<u64>) -> Result<(), Error> {
        self.write_value_event(EventKind::StartDictionary, |this| {
            this.start_element("dict")?;
            this.stack.push(Element::Dictionary);
            Ok(())
        })
    }

    fn write_end_collection(&mut self) -> Result<(), Error> {
        self.write_event(|this| {
            match (this.stack.pop(), this.expecting_key) {
                (Some(Element::Dictionary), true) => {
                    this.end_element("dict")?;
                }
                (Some(Element::Array), _) => {
                    this.end_element("array")?;
                }
                (Some(Element::Dictionary), false) | (None, _) => {
                    return Err(ErrorKind::UnexpectedEventType {
                        expected: EventKind::ValueOrStartCollection,
                        found: EventKind::EndCollection,
                    }
                    .without_position());
                }
            }
            this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            Ok(())
        })
    }

    fn write_boolean(&mut self, value: bool) -> Result<(), Error> {
        self.write_value_event(EventKind::Boolean, |this| {
            let value_str = if value { "true" } else { "false" };
            this.start_element(value_str)?;
            this.end_element(value_str)
        })
    }

    fn write_data(&mut self, value: &[u8]) -> Result<(), Error> {
        self.write_value_event(EventKind::Data, |this| {
            let base64_data = base64_encode_plist(&value, this.stack.len());
            this.write_element_and_value("data", &base64_data)
        })
    }

    fn write_date(&mut self, value: Date) -> Result<(), Error> {
        self.write_value_event(EventKind::Date, |this| {
            this.write_element_and_value("date", &value.to_rfc3339())
        })
    }

    fn write_integer(&mut self, value: Integer) -> Result<(), Error> {
        self.write_value_event(EventKind::Integer, |this| {
            this.write_element_and_value("integer", &value.to_string())
        })
    }

    fn write_real(&mut self, value: f64) -> Result<(), Error> {
        self.write_value_event(EventKind::Real, |this| {
            this.write_element_and_value("real", &value.to_string())
        })
    }

    fn write_string(&mut self, value: &str) -> Result<(), Error> {
        self.write_event(|this| {
            if this.expecting_key {
                this.write_element_and_value("key", &*value)?;
                this.expecting_key = false;
            } else {
                this.write_element_and_value("string", &*value)?;
                this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            }
            Ok(())
        })
    }

    fn write_uid(&mut self, _value: Uid) -> Result<(), Error> {
        Err(ErrorKind::UidNotSupportedInXmlPlist.without_position())
    }
}

pub(crate) fn from_xml_error(err: XmlWriterError) -> Error {
    match err {
        XmlWriterError::Io(err) => ErrorKind::Io(err).without_position(),
        XmlWriterError::DocumentStartAlreadyEmitted
        | XmlWriterError::LastElementNameNotAvailable
        | XmlWriterError::EndElementNameIsNotEqualToLastStartElementName
        | XmlWriterError::EndElementNameIsNotSpecified => unreachable!(),
    }
}

fn base64_encode_plist(data: &[u8], indent: usize) -> String {
    // XML plist data elements are always formatted by apple tools as
    // <data>
    // AAAA..AA (68 characters per line)
    // </data>
    // Allocate space for base 64 string and line endings up front
    const LINE_LEN: usize = 68;
    let mut line_ending = Vec::with_capacity(1 + indent);
    line_ending.push(b'\n');
    (0..indent).for_each(|_| line_ending.push(b'\t'));

    // Find the max length of `data` encoded as a base 64 string with padding
    let base64_max_string_len = data.len() * 4 / 3 + 4;

    // Find the max length of the formatted base 64 string as: max length of the base 64 string
    // + line endings and indents at the start of the string and after every line
    let base64_max_string_len_with_formatting =
        base64_max_string_len + (2 + base64_max_string_len / LINE_LEN) * line_ending.len();

    let mut output = vec![0; base64_max_string_len_with_formatting];

    // Start output with a line ending and indent
    output[..line_ending.len()].copy_from_slice(&line_ending);

    // Encode `data` as a base 64 string
    let base64_string_len =
        base64::encode_config_slice(data, base64::STANDARD, &mut output[line_ending.len()..]);

    // Line wrap the base 64 encoded string
    let line_wrap_len = line_wrap::line_wrap(
        &mut output[line_ending.len()..],
        base64_string_len,
        LINE_LEN,
        &line_wrap::SliceLineEnding::new(&line_ending),
    );

    // Add the final line ending and indent
    output[line_ending.len() + base64_string_len + line_wrap_len..][..line_ending.len()]
        .copy_from_slice(&line_ending);

    // Ensure output is the correct length
    output.truncate(base64_string_len + line_wrap_len + 2 * line_ending.len());
    String::from_utf8(output).expect("base 64 string must be valid utf8")
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use super::*;
    use crate::stream::Event;

    #[test]
    fn streaming_parser() {
        let plist = &[
            Event::StartDictionary(None),
            Event::String("Author".into()),
            Event::String("William Shakespeare".into()),
            Event::String("Lines".into()),
            Event::StartArray(None),
            Event::String("It is a tale told by an idiot,".into()),
            Event::String("Full of sound and fury, signifying nothing.".into()),
            Event::Data((0..128).collect::<Vec<_>>().into()),
            Event::EndCollection,
            Event::String("Death".into()),
            Event::Integer(1564.into()),
            Event::String("Height".into()),
            Event::Real(1.60),
            Event::String("Data".into()),
            Event::Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
            Event::String("Birthdate".into()),
            Event::Date(super::Date::from_rfc3339("1981-05-16T11:32:06Z").unwrap()),
            Event::String("Comment".into()),
            Event::String("2 < 3".into()), // make sure characters are escaped
            Event::String("BiggestNumber".into()),
            Event::Integer(18446744073709551615u64.into()),
            Event::String("SmallestNumber".into()),
            Event::Integer((-9223372036854775808i64).into()),
            Event::String("IsTrue".into()),
            Event::Boolean(true),
            Event::String("IsNotFalse".into()),
            Event::Boolean(false),
            Event::EndCollection,
        ];

        let mut cursor = Cursor::new(Vec::new());

        {
            let mut plist_w = XmlWriter::new(&mut cursor);

            for item in plist {
                plist_w.write(item).unwrap();
            }
        }

        let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>Author</key>
\t<string>William Shakespeare</string>
\t<key>Lines</key>
\t<array>
\t\t<string>It is a tale told by an idiot,</string>
\t\t<string>Full of sound and fury, signifying nothing.</string>
\t\t<data>
\t\tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEy
\t\tMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2Rl
\t\tZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=
\t\t</data>
\t</array>
\t<key>Death</key>
\t<integer>1564</integer>
\t<key>Height</key>
\t<real>1.6</real>
\t<key>Data</key>
\t<data>
\tAAAAvgAAAAMAAAAeAAAA
\t</data>
\t<key>Birthdate</key>
\t<date>1981-05-16T11:32:06Z</date>
\t<key>Comment</key>
\t<string>2 < 3</string>
\t<key>BiggestNumber</key>
\t<integer>18446744073709551615</integer>
\t<key>SmallestNumber</key>
\t<integer>-9223372036854775808</integer>
\t<key>IsTrue</key>
\t<true />
\t<key>IsNotFalse</key>
\t<false />
</dict>
</plist>";

        let s = String::from_utf8(cursor.into_inner()).unwrap();

        assert_eq!(s, comparison);
    }
}
<commit_msg>Add .pad_self_closing(false) to improve compatibility with Apple's XML parser<commit_after>use base64;
use line_wrap;
use std::{borrow::Cow, io::Write};
use xml_rs::{
    name::Name,
    namespace::Namespace,
    writer::{EmitterConfig, Error as XmlWriterError, EventWriter, XmlEvent},
};

use crate::{
    error::{self, Error, ErrorKind, EventKind},
    stream::{Writer, XmlWriteOptions},
    Date, Integer, Uid,
};

static XML_PROLOGUE: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
"#;

#[derive(PartialEq)]
enum Element {
    Dictionary,
    Array,
}

pub struct XmlWriter<W: Write> {
    xml_writer: EventWriter<W>,
    stack: Vec<Element>,
    expecting_key: bool,
    written_prologue: bool,
    // Not very nice
    empty_namespace: Namespace,
}

impl<W: Write> XmlWriter<W> {
    pub fn new(writer: W) -> XmlWriter<W> {
        let opts = XmlWriteOptions::default();
        XmlWriter::new_with_options(writer, &opts)
    }

    pub fn new_with_options(writer: W, opts: &XmlWriteOptions) -> XmlWriter<W> {
        let config = EmitterConfig::new()
            .line_separator("\n")
            .indent_string(opts.indent_str.clone())
            .perform_indent(true)
            .write_document_declaration(false)
            .normalize_empty_elements(true)
            .cdata_to_characters(true)
            .keep_element_names_stack(false)
            .autopad_comments(true)
            .pad_self_closing(false);

        XmlWriter {
            xml_writer: EventWriter::new_with_config(writer, config),
            stack: Vec::new(),
            expecting_key: false,
            written_prologue: false,
            empty_namespace: Namespace::empty(),
        }
    }

    fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), Error> {
        self.start_element(name)?;
        self.write_value(value)?;
        self.end_element(name)?;
        Ok(())
    }

    fn start_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::StartElement {
                name: Name::local(name),
                attributes: Cow::Borrowed(&[]),
                namespace: Cow::Borrowed(&self.empty_namespace),
            })
            .map_err(from_xml_error)?;
        Ok(())
    }

    fn end_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::EndElement {
                name: Some(Name::local(name)),
            })
            .map_err(from_xml_error)?;
        Ok(())
    }

    fn write_value(&mut self, value: &str) -> Result<(), Error> {
        self.xml_writer
            .write(XmlEvent::Characters(value))
            .map_err(from_xml_error)?;
        Ok(())
    }

    pub fn into_inner(self) -> W {
        self.xml_writer.into_inner()
    }

    fn write_event<F: FnOnce(&mut Self) -> Result<(), Error>>(
        &mut self,
        f: F,
    ) -> Result<(), Error> {
        if !self.written_prologue {
            self.xml_writer
                .inner_mut()
                .write_all(XML_PROLOGUE.as_bytes())
                .map_err(error::from_io_without_position)?;

            self.written_prologue = true;
        }

        f(self)?;

        // If there are no more open tags then write the </plist> element
        if self.stack.is_empty() {
            // We didn't tell the xml_writer about the <plist> tag so we'll skip telling it
            // about the </plist> tag as well.
            self.xml_writer
                .inner_mut()
                .write_all(b"\n</plist>")
                .map_err(error::from_io_without_position)?;
            self.xml_writer
                .inner_mut()
                .flush()
                .map_err(error::from_io_without_position)?;
        }

        Ok(())
    }

    fn write_value_event<F: FnOnce(&mut Self) -> Result<(), Error>>(
        &mut self,
        event_kind: EventKind,
        f: F,
    ) -> Result<(), Error> {
        self.write_event(|this| {
            if this.expecting_key {
                return Err(ErrorKind::UnexpectedEventType {
                    expected: EventKind::DictionaryKeyOrEndCollection,
                    found: event_kind,
                }
                .without_position());
            }
            f(this)?;
            this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            Ok(())
        })
    }
}

impl<W: Write> Writer for XmlWriter<W> {
    fn write_start_array(&mut self, _len: Option<u64>) -> Result<(), Error> {
        self.write_value_event(EventKind::StartArray, |this| {
            this.start_element("array")?;
            this.stack.push(Element::Array);
            Ok(())
        })
    }

    fn write_start_dictionary(&mut self, _len: Option<u64>) -> Result<(), Error> {
        self.write_value_event(EventKind::StartDictionary, |this| {
            this.start_element("dict")?;
            this.stack.push(Element::Dictionary);
            Ok(())
        })
    }

    fn write_end_collection(&mut self) -> Result<(), Error> {
        self.write_event(|this| {
            match (this.stack.pop(), this.expecting_key) {
                (Some(Element::Dictionary), true) => {
                    this.end_element("dict")?;
                }
                (Some(Element::Array), _) => {
                    this.end_element("array")?;
                }
                (Some(Element::Dictionary), false) | (None, _) => {
                    return Err(ErrorKind::UnexpectedEventType {
                        expected: EventKind::ValueOrStartCollection,
                        found: EventKind::EndCollection,
                    }
                    .without_position());
                }
            }
            this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            Ok(())
        })
    }

    fn write_boolean(&mut self, value: bool) -> Result<(), Error> {
        self.write_value_event(EventKind::Boolean, |this| {
            let value_str = if value { "true" } else { "false" };
            this.start_element(value_str)?;
            this.end_element(value_str)
        })
    }

    fn write_data(&mut self, value: &[u8]) -> Result<(), Error> {
        self.write_value_event(EventKind::Data, |this| {
            let base64_data = base64_encode_plist(&value, this.stack.len());
            this.write_element_and_value("data", &base64_data)
        })
    }

    fn write_date(&mut self, value: Date) -> Result<(), Error> {
        self.write_value_event(EventKind::Date, |this| {
            this.write_element_and_value("date", &value.to_rfc3339())
        })
    }

    fn write_integer(&mut self, value: Integer) -> Result<(), Error> {
        self.write_value_event(EventKind::Integer, |this| {
            this.write_element_and_value("integer", &value.to_string())
        })
    }

    fn write_real(&mut self, value: f64) -> Result<(), Error> {
        self.write_value_event(EventKind::Real, |this| {
            this.write_element_and_value("real", &value.to_string())
        })
    }

    fn write_string(&mut self, value: &str) -> Result<(), Error> {
        self.write_event(|this| {
            if this.expecting_key {
                this.write_element_and_value("key", &*value)?;
                this.expecting_key = false;
            } else {
                this.write_element_and_value("string", &*value)?;
                this.expecting_key = this.stack.last() == Some(&Element::Dictionary);
            }
            Ok(())
        })
    }

    fn write_uid(&mut self, _value: Uid) -> Result<(), Error> {
        Err(ErrorKind::UidNotSupportedInXmlPlist.without_position())
    }
}

pub(crate) fn from_xml_error(err: XmlWriterError) -> Error {
    match err {
        XmlWriterError::Io(err) => ErrorKind::Io(err).without_position(),
        XmlWriterError::DocumentStartAlreadyEmitted
        | XmlWriterError::LastElementNameNotAvailable
        | XmlWriterError::EndElementNameIsNotEqualToLastStartElementName
        | XmlWriterError::EndElementNameIsNotSpecified => unreachable!(),
    }
}

fn base64_encode_plist(data: &[u8], indent: usize) -> String {
    // XML plist data elements are always formatted by apple tools as
    // <data>
    // AAAA..AA (68 characters per line)
    // </data>
    // Allocate space for base 64 string and line endings up front
    const LINE_LEN: usize = 68;
    let mut line_ending = Vec::with_capacity(1 + indent);
    line_ending.push(b'\n');
    (0..indent).for_each(|_| line_ending.push(b'\t'));

    // Find the max length of `data` encoded as a base 64 string with padding
    let base64_max_string_len = data.len() * 4 / 3 + 4;

    // Find the max length of the formatted base 64 string as: max length of the base 64 string
    // + line endings and indents at the start of the string and after every line
    let base64_max_string_len_with_formatting =
        base64_max_string_len + (2 + base64_max_string_len / LINE_LEN) * line_ending.len();

    let mut output = vec![0; base64_max_string_len_with_formatting];

    // Start output with a line ending and indent
    output[..line_ending.len()].copy_from_slice(&line_ending);

    // Encode `data` as a base 64 string
    let base64_string_len =
        base64::encode_config_slice(data, base64::STANDARD, &mut output[line_ending.len()..]);

    // Line wrap the base 64 encoded string
    let line_wrap_len = line_wrap::line_wrap(
        &mut output[line_ending.len()..],
        base64_string_len,
        LINE_LEN,
        &line_wrap::SliceLineEnding::new(&line_ending),
    );

    // Add the final line ending and indent
    output[line_ending.len() + base64_string_len + line_wrap_len..][..line_ending.len()]
        .copy_from_slice(&line_ending);

    // Ensure output is the correct length
    output.truncate(base64_string_len + line_wrap_len + 2 * line_ending.len());
    String::from_utf8(output).expect("base 64 string must be valid utf8")
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use super::*;
    use crate::stream::Event;

    #[test]
    fn streaming_parser() {
        let plist = &[
            Event::StartDictionary(None),
            Event::String("Author".into()),
            Event::String("William Shakespeare".into()),
            Event::String("Lines".into()),
            Event::StartArray(None),
            Event::String("It is a tale told by an idiot,".into()),
            Event::String("Full of sound and fury, signifying nothing.".into()),
            Event::Data((0..128).collect::<Vec<_>>().into()),
            Event::EndCollection,
            Event::String("Death".into()),
            Event::Integer(1564.into()),
            Event::String("Height".into()),
            Event::Real(1.60),
            Event::String("Data".into()),
            Event::Data(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0].into()),
            Event::String("Birthdate".into()),
            Event::Date(super::Date::from_rfc3339("1981-05-16T11:32:06Z").unwrap()),
            Event::String("Comment".into()),
            Event::String("2 < 3".into()), // make sure characters are escaped
            Event::String("BiggestNumber".into()),
            Event::Integer(18446744073709551615u64.into()),
            Event::String("SmallestNumber".into()),
            Event::Integer((-9223372036854775808i64).into()),
            Event::String("IsTrue".into()),
            Event::Boolean(true),
            Event::String("IsNotFalse".into()),
            Event::Boolean(false),
            Event::EndCollection,
        ];

        let mut cursor = Cursor::new(Vec::new());

        {
            let mut plist_w = XmlWriter::new(&mut cursor);

            for item in plist {
                plist_w.write(item).unwrap();
            }
        }

        let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>Author</key>
\t<string>William Shakespeare</string>
\t<key>Lines</key>
\t<array>
\t\t<string>It is a tale told by an idiot,</string>
\t\t<string>Full of sound and fury, signifying nothing.</string>
\t\t<data>
\t\tAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEy
\t\tMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2Rl
\t\tZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=
\t\t</data>
\t</array>
\t<key>Death</key>
\t<integer>1564</integer>
\t<key>Height</key>
\t<real>1.6</real>
\t<key>Data</key>
\t<data>
\tAAAAvgAAAAMAAAAeAAAA
\t</data>
\t<key>Birthdate</key>
\t<date>1981-05-16T11:32:06Z</date>
\t<key>Comment</key>
\t<string>2 < 3</string>
\t<key>BiggestNumber</key>
\t<integer>18446744073709551615</integer>
\t<key>SmallestNumber</key>
\t<integer>-9223372036854775808</integer>
\t<key>IsTrue</key>
\t<true/>
\t<key>IsNotFalse</key>
\t<false/>
</dict>
</plist>";

        let s = String::from_utf8(cursor.into_inner()).unwrap();

        assert_eq!(s, comparison);
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata::VorbisComment;

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <input>
       metadata comments <input>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_input: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
}

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    println!("Sample rate: {} Hz", info.sample_rate);
  }

  if no_flags || args.flag_channels {
    println!("Number of channels: {}", info.channels);
  }

  if no_flags || args.flag_bits_per_sample {
    println!("Bits per sample: {}", info.bits_per_sample);
  }

  if no_flags || args.flag_total_samples {
    println!("Total samples: {}", info.total_samples);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    println!("MD5 sum: {}", md5);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment) {
  let mut index = 1;

  println!("Vendor String: {}", vorbis_comment.vendor_string);
  println!("Number of Comments: {}", vorbis_comment.comments.len());

  for comment in &vorbis_comment.comments {
    println!("  {}: \"{}\" = {}", index, comment.0, comment.1);

    index += 1;
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_input)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }
}
<commit_msg>Hook VorbisComment printing into CLI<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata;
use flac::metadata::VorbisComment;

use std::env;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <input>
       metadata comments <input>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_input: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
}

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    println!("Sample rate: {} Hz", info.sample_rate);
  }

  if no_flags || args.flag_channels {
    println!("Number of channels: {}", info.channels);
  }

  if no_flags || args.flag_bits_per_sample {
    println!("Bits per sample: {}", info.bits_per_sample);
  }

  if no_flags || args.flag_total_samples {
    println!("Total samples: {}", info.total_samples);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    println!("MD5 sum: {}", md5);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment) {
  let mut index = 1;

  println!("Vendor String: {}", vorbis_comment.vendor_string);
  println!("Number of Comments: {}", vorbis_comment.comments.len());

  for comment in &vorbis_comment.comments {
    println!("  {}: \"{}\" = {}", index, comment.0, comment.1);

    index += 1;
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_input)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }

  for meta in stream.metadata() {
    match meta.data {
      metadata::Data::VorbisComment(ref v) => {
        if args.cmd_comments {
          print_vorbis_comments(v)
        }
      }
      _                                    => continue,
    }
  }
}
<|endoftext|>


<commit_before>pub mod editor;
<commit_msg>Add helper: get_tempfile()<commit_after>use std::fs::File;

pub mod editor;

pub fn get_tempfile(ext: &str) -> Option<(String, File)> {
    use rand::random;

    let randomname = format!("/tmp/imag-{}.{}", random::<u64>(), ext);
    debug!("Attempting to create tempfile at {}", randomname);
    File::create(randomname.clone())
        .map_err(|e| debug!(" Error -> {}", e))
        .ok()
        .map(|f| (randomname, f))
}
<|endoftext|>


<commit_before>use calx::{hex_disc, CellVector, FromPrefab, IntoPrefab, MinimapSpace, ProjectedImage};
use euclid::vec2;
use image::{GenericImage, GenericImageView, Pixel, SubImage};
use std::collections::HashMap;
use structopt::StructOpt;
use vitral::SRgba;
use world::{Location, Sector, Terrain};

type ImageBuffer = image::ImageBuffer<image::Rgba<u8>, Vec<u8>>;

type Prefab<T> = HashMap<CellVector, T>;

#[derive(StructOpt, Debug)]
struct Opt {
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(StructOpt, Debug)]
enum Command {
    #[structopt(name = "generate", help = "Generate a blank overland map image")]
    Generate {
        #[structopt(long = "minimap", help = "Use minimap projection")]
        minimap: bool,

        #[structopt(
            short = "w",
            long = "width",
            default_value = "12",
            help = "Width in sectors"
        )]
        width: u32,

        #[structopt(
            short = "h",
            long = "height",
            default_value = "7",
            help = "Height in sectors"
        )]
        height: u32,

        #[structopt(help = "Output PNG file")]
        output: String,
    },

    #[structopt(
        name = "convert",
        help = "Convert map from one projection to another and normalize the checkerboard pattern"
    )]
    Convert {
        #[structopt(long = "input-minimap", help = "Input file has minimap projection")]
        input_minimap: bool,

        #[structopt(
            long = "output-minimap",
            help = "Use minimap projection in output file"
        )]
        output_minimap: bool,

        #[structopt(help = "Input file")]
        input: String,

        #[structopt(help = "Output file (if different from input)")]
        output: Option<String>,
    },
}

fn default_map(width: u32, height: u32) -> Prefab<Terrain> {
    fn p(loc: Location) -> CellVector { vec2(loc.x as i32, loc.y as i32) }

    let mut terrain = HashMap::new();

    for &loc in &overland_locs(width, height) {
        for edge in hex_disc(loc, 1) {
            // Ensure land is surrounded by water past the sector edges.
            terrain.entry(p(edge)).or_insert(Terrain::Water);
        }
        terrain.insert(p(loc), Terrain::Grass);
    }

    terrain
}

fn dark(color: SRgba) -> SRgba {
    let mut color = color;
    color.r &= !0xF;
    color.g &= !0xF;
    color.b &= !0xF;
    color
}

fn mid(color: SRgba) -> SRgba {
    let mut color = dark(color);
    color.r += 0x8;
    color.g += 0x8;
    color.b += 0x8;
    color
}

fn light(color: SRgba) -> SRgba {
    let mut color = dark(color);
    color.r += 0xF;
    color.g += 0xF;
    color.b += 0xF;
    color
}

fn checkerboard((pos, color): (CellVector, SRgba)) -> (CellVector, SRgba) {
    let sec = Sector::from(Location::new(pos.x as i16, pos.y as i16, 0));
    let color = match (sec.x + sec.y) % 3 {
        0 => dark(color),
        1 => mid(color),
        _ => light(color),
    };
    (pos, color)
}

fn terrain_to_color((pos, terrain): (CellVector, Terrain)) -> (CellVector, SRgba) {
    checkerboard((pos, terrain.color()))
}

fn overland_locs(width: u32, height: u32) -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..(height as i16) {
        for x in 0..(width as i16) {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn save(prefab: Prefab<SRgba>, is_minimap: bool, output_path: String) {
    let image: ImageBuffer = if is_minimap {
        let p: ProjectedImage<ImageBuffer, MinimapSpace> = FromPrefab::from_prefab(&prefab);
        p.image
    } else {
        FromPrefab::from_prefab(&prefab)
    };

    // Impose palette
    let mut result = ImageBuffer::new(image.width(), image.height() + 1);
    result.copy_from(&image, 0, 0).expect("copy_from failed");

    for (x, t) in Terrain::iter().filter(|t| t.is_regular()).enumerate() {
        let light = light(t.color());
        let dark = dark(t.color());
        let y = result.height() - 1;
        result.put_pixel(
            x as u32 * 2,
            y,
            image::Rgba::from_channels(light.r, light.g, light.b, 0xff),
        );
        result.put_pixel(
            x as u32 * 2 + 1,
            y,
            image::Rgba::from_channels(dark.r, dark.g, dark.b, 0xff),
        );
    }

    image::save_buffer(
        output_path,
        &result,
        result.width(),
        result.height(),
        image::ColorType::Rgba8,
    )
    .unwrap();
}

fn generate(width: u32, height: u32, is_minimap: bool, output_path: String) {
    let prefab: Prefab<SRgba> = default_map(width, height)
        .into_iter()
        .map(terrain_to_color)
        .collect();

    save(prefab, is_minimap, output_path);
}

fn convert(
    input_path: String,
    input_is_minimap: bool,
    output_path: Option<String>,
    output_is_minimap: bool,
) {
    let mut input =
        image::open(input_path.clone()).expect(&format!("Unable to load '{}'", input_path.clone()));
    // Slice off the bottom row containing palette (h - 1).
    let (w, h) = (input.width(), input.height());
    let input_map = SubImage::new(&mut input, 0, 0, w, h - 1);

    let prefab: Prefab<SRgba> = if input_is_minimap {
        let p: ProjectedImage<_, MinimapSpace> = ProjectedImage::new(input_map);
        p.into_prefab().expect("Bad map image")
    } else {
        input_map.into_prefab().expect("Bad map image")
    };

    // Impose sector checkerboard.
    let prefab: Prefab<SRgba> = prefab.into_iter().map(checkerboard).collect();

    save(prefab, output_is_minimap, output_path.unwrap_or(input_path));
}

fn main() {
    let opt = Opt::from_args();
    match opt.cmd {
        Command::Generate {
            width,
            height,
            minimap,
            output,
        } => generate(width, height, minimap, output),
        Command::Convert {
            input,
            input_minimap,
            output,
            output_minimap,
        } => convert(input, input_minimap, output, output_minimap),
    }
}
<commit_msg>Generate tiled sectorizations<commit_after>use calx::{tiled, CellVector, FromPrefab, IntoPrefab, MinimapSpace, ProjectedImage};
use euclid::vec2;
use image::{GenericImage, GenericImageView, Pixel, SubImage};
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::iter::FromIterator;
use structopt::StructOpt;
use vitral::SRgba;
use world::{Location, Sector, Terrain};

type ImageBuffer = image::ImageBuffer<image::Rgba<u8>, Vec<u8>>;

type Prefab<T> = HashMap<CellVector, T>;

#[derive(StructOpt, Debug)]
struct Opt {
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(StructOpt, Debug)]
enum Command {
    #[structopt(name = "generate", help = "Generate a blank overland map image")]
    Generate {
        #[structopt(long = "minimap", help = "Use minimap projection")]
        minimap: bool,

        #[structopt(
            short = "w",
            long = "width",
            default_value = "12",
            help = "Width in sectors"
        )]
        width: u32,

        #[structopt(
            short = "h",
            long = "height",
            default_value = "7",
            help = "Height in sectors"
        )]
        height: u32,

        #[structopt(help = "Output PNG file")]
        output: String,
    },

    #[structopt(name = "generate-tiled", help = "Generate a blank overland Tiled json")]
    GenerateTiled {
        #[structopt(
            short = "w",
            long = "width",
            default_value = "12",
            help = "Width in sectors"
        )]
        width: u32,

        #[structopt(
            short = "h",
            long = "height",
            default_value = "7",
            help = "Height in sectors"
        )]
        height: u32,

        #[structopt(help = "Existing Tiled map to impose sector pattern on")]
        path: String,
    },

    #[structopt(
        name = "convert",
        help = "Convert map from one projection to another and normalize the checkerboard pattern"
    )]
    Convert {
        #[structopt(long = "input-minimap", help = "Input file has minimap projection")]
        input_minimap: bool,

        #[structopt(
            long = "output-minimap",
            help = "Use minimap projection in output file"
        )]
        output_minimap: bool,

        #[structopt(help = "Input file")]
        input: String,

        #[structopt(help = "Output file (if different from input)")]
        output: Option<String>,
    },
}

fn default_map(width: u32, height: u32) -> Prefab<Terrain> {
    fn p(loc: Location) -> CellVector { vec2(loc.x as i32, loc.y as i32) }

    let mut terrain = HashMap::new();

    for &loc in &overland_locs(width, height) {
        terrain.insert(p(loc), Terrain::Grass);
    }

    terrain
}

fn dark(color: SRgba) -> SRgba {
    let mut color = color;
    color.r &= !0xF;
    color.g &= !0xF;
    color.b &= !0xF;
    color
}

fn mid(color: SRgba) -> SRgba {
    let mut color = dark(color);
    color.r += 0x8;
    color.g += 0x8;
    color.b += 0x8;
    color
}

fn light(color: SRgba) -> SRgba {
    let mut color = dark(color);
    color.r += 0xF;
    color.g += 0xF;
    color.b += 0xF;
    color
}

fn checkerboard((pos, color): (CellVector, SRgba)) -> (CellVector, SRgba) {
    let sec = Sector::from(Location::new(pos.x as i16, pos.y as i16, 0));
    let color = match (sec.x + sec.y) % 3 {
        0 => dark(color),
        1 => mid(color),
        _ => light(color),
    };
    (pos, color)
}

fn terrain_to_color((pos, terrain): (CellVector, Terrain)) -> (CellVector, SRgba) {
    checkerboard((pos, terrain.color()))
}

fn overland_locs(width: u32, height: u32) -> Vec<Location> {
    let mut ret = Vec::new();
    for y in 0..(height as i16) {
        for x in 0..(width as i16) {
            let sec = Sector::new(x, y, 0);
            for loc in sec.iter() {
                ret.push(loc);
            }
        }
    }
    ret
}

fn save(prefab: Prefab<SRgba>, is_minimap: bool, output_path: String) {
    let image: ImageBuffer = if is_minimap {
        let p: ProjectedImage<ImageBuffer, MinimapSpace> = FromPrefab::from_prefab(&prefab);
        p.image
    } else {
        FromPrefab::from_prefab(&prefab)
    };

    // Impose palette
    let mut result = ImageBuffer::new(image.width(), image.height() + 1);
    result.copy_from(&image, 0, 0).expect("copy_from failed");

    for (x, t) in Terrain::iter().filter(|t| t.is_regular()).enumerate() {
        let light = light(t.color());
        let dark = dark(t.color());
        let y = result.height() - 1;
        result.put_pixel(
            x as u32 * 2,
            y,
            image::Rgba::from_channels(light.r, light.g, light.b, 0xff),
        );
        result.put_pixel(
            x as u32 * 2 + 1,
            y,
            image::Rgba::from_channels(dark.r, dark.g, dark.b, 0xff),
        );
    }

    image::save_buffer(
        output_path,
        &result,
        result.width(),
        result.height(),
        image::ColorType::Rgba8,
    )
    .unwrap();
}

fn generate(width: u32, height: u32, is_minimap: bool, output_path: String) {
    let prefab: Prefab<SRgba> = default_map(width, height)
        .into_iter()
        .map(terrain_to_color)
        .collect();

    save(prefab, is_minimap, output_path);
}

fn convert(
    input_path: String,
    input_is_minimap: bool,
    output_path: Option<String>,
    output_is_minimap: bool,
) {
    let mut input =
        image::open(input_path.clone()).expect(&format!("Unable to load '{}'", input_path.clone()));
    // Slice off the bottom row containing palette (h - 1).
    let (w, h) = (input.width(), input.height());
    let input_map = SubImage::new(&mut input, 0, 0, w, h - 1);

    let prefab: Prefab<SRgba> = if input_is_minimap {
        let p: ProjectedImage<_, MinimapSpace> = ProjectedImage::new(input_map);
        p.into_prefab().expect("Bad map image")
    } else {
        input_map.into_prefab().expect("Bad map image")
    };

    // Impose sector checkerboard.
    let prefab: Prefab<SRgba> = prefab.into_iter().map(checkerboard).collect();

    save(prefab, output_is_minimap, output_path.unwrap_or(input_path));
}

fn generate_tiled(path: String, width: u32, height: u32) {
    let map = default_map(width, height);
    let mut tiled_map: tiled::Map = serde_json::from_reader(BufReader::new(
        File::open(path).expect("Couldn't open file"),
    ))
    .expect("Couldn't parse Tiled JSON map");

    tiled_map.layers = Vec::new();

    let chunks = tiled::ChunkMap::from_iter(map.into_iter().map(|(pos, _)| {
        let sec = Sector::from(Location::new(pos.x as i16, pos.y as i16, 0));
        let tile = match (sec.x + sec.y) % 3 {
            0 => 1,
            1 => 2,
            _ => 3,
        };
        (euclid::point2(pos.x, pos.y), tile)
    }));

    tiled_map.infinite = true;
    tiled_map.layers.push(tiled::Layer::TileLayer {
        name: "surface".into(),
        id: 0,
        visible: true,
        opacity: 1.0,
        x: 0,
        y: 0,
        width: 0,
        height: 0,
        chunks: Some(chunks),
        data: None,
    });

    print!("{}", serde_json::to_string(&tiled_map).unwrap());
}

fn main() {
    let opt = Opt::from_args();
    match opt.cmd {
        Command::Generate {
            width,
            height,
            minimap,
            output,
        } => generate(width, height, minimap, output),
        Command::GenerateTiled {
            width,
            height,
            path,
        } => generate_tiled(path, width, height),
        Command::Convert {
            input,
            input_minimap,
            output,
            output_minimap,
        } => convert(input, input_minimap, output, output_minimap),
    }
}
<|endoftext|>