<commit_before>extern crate dcpu16;
extern crate getopts;

mod cli;

use std::vec::Vec;
use std::path::Path;
use std::{env, thread, time};
use dcpu16::dcpu;
use dcpu16::disassembler;
//use dcpu16::bin::cli;
use getopts::Options;
use std::process::exit;

use dcpu16::devices::clock_generic::DeviceClockGeneric;

const FPS: usize = 30;

fn main() {
    let mut opts = Options::new();
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    opts.optflag("p", "print", "print CPU info each tick");
    opts.optflag("v", "version", "print version");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(why) => {
            println!("{}", why);
            exit(1);
        },
    };

    if matches.opt_present("h") {
        cli::print_usage(&program, "FILE", opts, &["-p output.bin"]);
        return;
    }

    if matches.opt_present("v") {
        cli::print_version(&program);
        return;
    }

    if matches.free.len() != 1 {
        println!("Please input file");
        return;
    }
    let print = matches.opt_present("p");
    let ref filename = matches.free[0];

    let mut cpu = dcpu::DCPU::new();

    let path = Path::new(filename);
    match cpu.load_from_binary_file(&path) {
        Ok(()) => {},
        Err(why) => {
            println!("Could load file {}: {}", path.display(), why);
            exit(1);
        },
    }

    // Connect hardware
    //cpu.devices.push(Box::new(dcpu::HWMonitorLEM1802{connected: false, ram_location: 0}));
    /*
    let mut floppy = Box::new(dcpu::HWFloppyM35FD::new());
    floppy.sectors.push(dcpu::HWFloppyM35FDSector{mem: [1; 512]});
    floppy.state = 1;
    cpu.devices.push(floppy);
    */

    let clock = DeviceClockGeneric::new();
    cpu.add_device(Box::new(clock));

    // If printing is turned on, CPU will tick through (without proper timing)
    if print {
        while !cpu.terminate {
            cpu.tick();
            let (_, s) = disassembler::disassemble_instruction(&cpu, true);
            println!("---------------------------------------------");
            println!("::: {}", s);
            cpu.print();
        }
    } else { // If printing is not on, then the CPU will run roughly at 100 kHz
        let cycles = dcpu::CYCLE_HZ / FPS;
        while !cpu.terminate {
            let now = time::Instant::now();
            cpu.run(cycles);
            //let elapsed = now.elapsed();
            // TODO: Use elapsed to sleep slightly shorter to get timing right
            thread::sleep(time::Duration::from_millis((1000 / FPS) as u64));
        }
    }
}
<commit_msg>Commented out unused line<commit_after>extern crate dcpu16;
extern crate getopts;

mod cli;

use std::vec::Vec;
use std::path::Path;
use std::{env, thread, time};
use dcpu16::dcpu;
use dcpu16::disassembler;
//use dcpu16::bin::cli;
use getopts::Options;
use std::process::exit;

use dcpu16::devices::clock_generic::DeviceClockGeneric;

const FPS: usize = 30;

fn main() {
    let mut opts = Options::new();
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    opts.optflag("p", "print", "print CPU info each tick");
    opts.optflag("v", "version", "print version");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(why) => {
            println!("{}", why);
            exit(1);
        },
    };

    if matches.opt_present("h") {
        cli::print_usage(&program, "FILE", opts, &["-p output.bin"]);
        return;
    }

    if matches.opt_present("v") {
        cli::print_version(&program);
        return;
    }

    if matches.free.len() != 1 {
        println!("Please input file");
        return;
    }
    let print = matches.opt_present("p");
    let ref filename = matches.free[0];

    let mut cpu = dcpu::DCPU::new();

    let path = Path::new(filename);
    match cpu.load_from_binary_file(&path) {
        Ok(()) => {},
        Err(why) => {
            println!("Could load file {}: {}", path.display(), why);
            exit(1);
        },
    }

    // Connect hardware
    //cpu.devices.push(Box::new(dcpu::HWMonitorLEM1802{connected: false, ram_location: 0}));
    /*
    let mut floppy = Box::new(dcpu::HWFloppyM35FD::new());
    floppy.sectors.push(dcpu::HWFloppyM35FDSector{mem: [1; 512]});
    floppy.state = 1;
    cpu.devices.push(floppy);
    */

    let clock = DeviceClockGeneric::new();
    cpu.add_device(Box::new(clock));

    // If printing is turned on, CPU will tick through (without proper timing)
    if print {
        while !cpu.terminate {
            cpu.tick();
            let (_, s) = disassembler::disassemble_instruction(&cpu, true);
            println!("---------------------------------------------");
            println!("::: {}", s);
            cpu.print();
        }
    } else { // If printing is not on, then the CPU will run roughly at 100 kHz
        let cycles = dcpu::CYCLE_HZ / FPS;
        while !cpu.terminate {
            //let now = time::Instant::now();
            cpu.run(cycles);
            //let elapsed = now.elapsed();
            // TODO: Use elapsed to sleep slightly shorter to get timing right
            thread::sleep(time::Duration::from_millis((1000 / FPS) as u64));
        }
    }
}
<|endoftext|>


<commit_before>use mimirsbrunn::utils::logger::logger_init;
use snafu::{ResultExt, Snafu};
use std::net::ToSocketAddrs;
use tokio::runtime;
use tracing::{info, instrument};
use warp::Filter;

use super::settings::{Error as SettingsError, Opts, Settings};
use mimir::adapters::primary::bragi::prometheus_handler::update_metrics;
use mimir::{
    adapters::primary::bragi::api::{
        features, forward_geocoder, forward_geocoder_explain, reverse_geocoder, status,
    },
    adapters::primary::bragi::{handlers, routes},
    adapters::secondary::elasticsearch::remote::connection_pool_url,
    domain::ports::secondary::remote::{Error as PortRemoteError, Remote},
    metrics,
};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Could not establish Elasticsearch Connection: {}", source))]
    ElasticsearchConnection { source: PortRemoteError },

    #[snafu(display("Could not generate settings: {}", source))]
    SettingsProcessing { source: SettingsError },

    #[snafu(display("Socket Addr Error with host {} / port {}: {}", host, port, source))]
    SockAddr {
        host: String,
        port: u16,
        source: std::io::Error,
    },

    #[snafu(display("Addr Resolution Error {}", msg))]
    AddrResolution { msg: String },

    #[snafu(display("Could not init logger: {}", source))]
    InitLog {
        source: mimirsbrunn::utils::logger::Error,
    },
}

pub fn run(opts: &Opts) -> Result<(), Error> {
    let settings = Settings::new(opts).context(SettingsProcessing)?;

    let _log_guard = logger_init().map_err(|err| Error::InitLog { source: err })?;

    let runtime = runtime::Builder::new_multi_thread()
        .worker_threads(settings.nb_threads.unwrap_or_else(num_cpus::get))
        .enable_all()
        .build()
        .expect("Failed to build tokio runtime.");

    runtime.block_on(run_server(settings))
}

pub fn config(opts: &Opts) -> Result<(), Error> {
    let settings = Settings::new(opts).context(SettingsProcessing)?;
    println!("{}", serde_json::to_string_pretty(&settings).unwrap());
    Ok(())
}

#[instrument(skip(settings))]
pub async fn run_server(settings: Settings) -> Result<(), Error> {
    info!(
        "Connecting to Elasticsearch at {}",
        &settings.elasticsearch.url
    );

    let client = connection_pool_url(&settings.elasticsearch.url)
        .conn(settings.elasticsearch.clone())
        .await
        .context(ElasticsearchConnection)?;

    // Here I place reverse_geocoder first because its most likely to get hit.
    let api = reverse_geocoder!(client.clone(), settings.query.clone())
        .or(forward_geocoder!(client.clone(), settings.query.clone()))
        .or(features!(client.clone(), settings.query.clone()))
        .or(forward_geocoder_explain!(client.clone(), settings.query))
        .or(status!(client.clone(), &settings.elasticsearch.url))
        .or(metrics!())
        .recover(routes::report_invalid)
        .with(warp::wrap_fn(|filter| {
            routes::cache_filter(filter, settings.http_cache_duration)
        }))
        .with(warp::log::custom(update_metrics));
        .with(warp::trace(|info| {
            // Create a span using tracing macros
            tracing::info_span!(
                "request",
                method = %info.method(),
                path = %info.path(),
            )
        }));

    info!("api ready");

    let host = settings.service.host;
    let port = settings.service.port;
    let addr = (host.as_str(), port);
    let addr = addr
        .to_socket_addrs()
        .context(SockAddr { host, port })?
        .next()
        .ok_or(Error::AddrResolution {
            msg: String::from("Cannot resolve bragi addr."),
        })?;

    info!("Serving bragi on {}", addr);

    warp::serve(api).run(addr).await;

    Ok(())
}
<commit_msg>fix after merge<commit_after>use mimirsbrunn::utils::logger::logger_init;
use snafu::{ResultExt, Snafu};
use std::net::ToSocketAddrs;
use tokio::runtime;
use tracing::{info, instrument};
use warp::Filter;

use super::settings::{Error as SettingsError, Opts, Settings};
use mimir::adapters::primary::bragi::prometheus_handler::update_metrics;
use mimir::{
    adapters::primary::bragi::api::{
        features, forward_geocoder, forward_geocoder_explain, reverse_geocoder, status,
    },
    adapters::primary::bragi::{handlers, routes},
    adapters::secondary::elasticsearch::remote::connection_pool_url,
    domain::ports::secondary::remote::{Error as PortRemoteError, Remote},
    metrics,
};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Could not establish Elasticsearch Connection: {}", source))]
    ElasticsearchConnection { source: PortRemoteError },

    #[snafu(display("Could not generate settings: {}", source))]
    SettingsProcessing { source: SettingsError },

    #[snafu(display("Socket Addr Error with host {} / port {}: {}", host, port, source))]
    SockAddr {
        host: String,
        port: u16,
        source: std::io::Error,
    },

    #[snafu(display("Addr Resolution Error {}", msg))]
    AddrResolution { msg: String },

    #[snafu(display("Could not init logger: {}", source))]
    InitLog {
        source: mimirsbrunn::utils::logger::Error,
    },
}

pub fn run(opts: &Opts) -> Result<(), Error> {
    let settings = Settings::new(opts).context(SettingsProcessing)?;

    let _log_guard = logger_init().map_err(|err| Error::InitLog { source: err })?;

    let runtime = runtime::Builder::new_multi_thread()
        .worker_threads(settings.nb_threads.unwrap_or_else(num_cpus::get))
        .enable_all()
        .build()
        .expect("Failed to build tokio runtime.");

    runtime.block_on(run_server(settings))
}

pub fn config(opts: &Opts) -> Result<(), Error> {
    let settings = Settings::new(opts).context(SettingsProcessing)?;
    println!("{}", serde_json::to_string_pretty(&settings).unwrap());
    Ok(())
}

#[instrument(skip(settings))]
pub async fn run_server(settings: Settings) -> Result<(), Error> {
    info!(
        "Connecting to Elasticsearch at {}",
        &settings.elasticsearch.url
    );

    let client = connection_pool_url(&settings.elasticsearch.url)
        .conn(settings.elasticsearch.clone())
        .await
        .context(ElasticsearchConnection)?;

    // Here I place reverse_geocoder first because its most likely to get hit.
    let api = reverse_geocoder!(client.clone(), settings.query.clone())
        .or(forward_geocoder!(client.clone(), settings.query.clone()))
        .or(features!(client.clone(), settings.query.clone()))
        .or(forward_geocoder_explain!(client.clone(), settings.query))
        .or(status!(client.clone(), &settings.elasticsearch.url))
        .or(metrics!())
        .recover(routes::report_invalid)
        .with(warp::wrap_fn(|filter| {
            routes::cache_filter(filter, settings.http_cache_duration)
        }))
        .with(warp::log::custom(update_metrics))
        .with(warp::trace(|info| {
            // Create a span using tracing macros
            tracing::info_span!(
                "request",
                method = %info.method(),
                path = %info.path(),
            )
        }));

    info!("api ready");

    let host = settings.service.host;
    let port = settings.service.port;
    let addr = (host.as_str(), port);
    let addr = addr
        .to_socket_addrs()
        .context(SockAddr { host, port })?
        .next()
        .ok_or(Error::AddrResolution {
            msg: String::from("Cannot resolve bragi addr."),
        })?;

    info!("Serving bragi on {}", addr);

    warp::serve(api).run(addr).await;

    Ok(())
}
<|endoftext|>


<commit_before>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub(crate) trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter().map(|v| v.len_varint() as u64).sum()
}

/// Size of serialized repeated packed field, excluding length and tag.
pub(crate) fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter().map(|v| v.len_varint_zigzag()).sum()
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .sum()
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag.
pub fn vec_packed_sint32_size(field_number: u32, vec: &[i32]) -> u64 {
    vec_packed_varint_zigzag_size(field_number, vec)
}

/// Size of serialized data with length prefix and tag.
pub fn vec_packed_sint64_size(field_number: u32, vec: &[i64]) -> u64 {
    vec_packed_varint_zigzag_size(field_number, vec)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<commit_msg>Revert "Remove ProtobufVarintZigzag from public API"<commit_after>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter().map(|v| v.len_varint() as u64).sum()
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter().map(|v| v.len_varint_zigzag()).sum()
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .sum()
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag.
pub fn vec_packed_sint32_size(field_number: u32, vec: &[i32]) -> u64 {
    vec_packed_varint_zigzag_size(field_number, vec)
}

/// Size of serialized data with length prefix and tag.
pub fn vec_packed_sint64_size(field_number: u32, vec: &[i64]) -> u64 {
    vec_packed_varint_zigzag_size(field_number, vec)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<|endoftext|>


<commit_before>use codegen::buffer::*;
use codegen::emit;
use codegen::x64::emit::*;
use codegen::x64::reg::*;
use codegen::x64::reg::Reg::*;

use dseg::DSeg;

use parser::ast::ctxt::*;
use parser::ast::*;
use parser::ast::Expr::*;

pub enum ExprLoc {
    LocConst(i32),
    LocReg(Reg),
    LocStack(i32),
}

pub struct ExprGen<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'ast Function,
    buf: &'a mut Buffer,
    dseg: &'a mut DSeg,
}

impl<'a, 'ast> ExprGen<'a, 'ast> where 'ast: 'a {
    pub fn new(
        ctxt: &'a Context<'a, 'ast>,
        fct: &'ast Function,
        buf: &'a mut Buffer,
        dseg: &'a mut DSeg,
    ) -> ExprGen<'a, 'ast> {
        ExprGen {
            ctxt: ctxt,
            fct: fct,
            buf: buf,
            dseg: dseg,
        }
    }

    pub fn generate(mut self, e: &'ast Expr) -> Reg {
        self.emit_expr(e, REG_RESULT)
    }

    fn emit_expr(&mut self, e: &'ast Expr, dest: Reg) -> Reg {
        match *e {
            ExprLitInt(ref expr) => self.emit_lit_int(expr, dest),
            ExprLitBool(ref expr) => self.emit_lit_bool(expr, dest),
            ExprUn(ref expr) => self.emit_un(expr, dest),
            ExprIdent(ref expr) => self.emit_ident(expr, dest),
            ExprAssign(ref expr) => self.emit_assign(expr, dest),
            ExprBin(ref expr) => self.emit_bin(expr, dest),
            ExprCall(ref expr) => self.emit_call(expr, dest),
            _ => unreachable!(),
        }

        dest
    }

    fn emit_lit_int(&mut self, lit: &'ast ExprLitIntType, dest: Reg) {
        emit_movl_imm_reg(self.buf, lit.value as u32, dest);
    }

    fn emit_lit_bool(&mut self, lit: &'ast ExprLitBoolType, dest: Reg) {
        let value : u32 = if lit.value { 1 } else { 0 };
        emit_movl_imm_reg(self.buf, value, dest);
    }

    fn emit_ident(&mut self, e: &'ast ExprIdentType, dest: Reg) {
        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.id).unwrap();

        emit::var_load(self.buf, self.ctxt, varid, dest);
    }

    fn emit_un(&mut self, e: &'ast ExprUnType, dest: Reg) {
        self.emit_expr(&e.opnd, dest);

        match e.op {
            UnOp::Plus => {},
            UnOp::Neg => emit_negl_reg(self.buf, dest),
            UnOp::BitNot => emit_notl_reg(self.buf, dest),
            UnOp::Not => {
                emit_xorb_imm_reg(self.buf, 1, dest);
                emit_andb_imm_reg(self.buf, 1, dest);
            },
        }
    }

    fn emit_assign(&mut self, e: &'ast ExprAssignType, dest: Reg) {
        self.emit_expr(&e.rhs, dest);

        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.lhs.id()).unwrap();

        emit::var_store(&mut self.buf, self.ctxt, dest, varid);
    }

    fn emit_bin(&mut self, e: &'ast ExprBinType, dest: Reg) {
        assert!(e.rhs.is_leaf());

        match e.op {
            BinOp::Add => self.emit_bin_add(e, dest),
            BinOp::Sub => self.emit_bin_sub(e, dest),
            BinOp::Mul => self.emit_bin_mul(e, dest),
            BinOp::Div => self.emit_bin_div(e, dest),
            BinOp::Mod => self.emit_bin_mod(e, dest),
            BinOp::Cmp(op) => self.emit_bin_cmp(e, dest, op),
            BinOp::BitOr => self.emit_bin_bit_or(e, dest),
            BinOp::BitAnd => self.emit_bin_bit_and(e, dest),
            BinOp::BitXor => self.emit_bin_bit_xor(e, dest),
            BinOp::Or => self.emit_bin_or(e, dest),
            BinOp::And => self.emit_bin_and(e, dest),
        }
    }

    fn emit_bin_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jnz(self.buf, lbl_true);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.buf.define_label(lbl_true);
        emit_movl_imm_reg(self.buf, 1, REG_RESULT);
        emit_jmp(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit_movl_imm_reg(self.buf, 0, REG_RESULT);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.buf.define_label(lbl_true);
        emit_movl_imm_reg(self.buf, 1, REG_RESULT);
        emit_jmp(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit_movl_imm_reg(self.buf, 0, REG_RESULT);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_cmp(&mut self, e: &'ast ExprBinType, dest: Reg, op: CmpOp) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cmpl_reg_reg(self.buf, REG_TMP1, REG_RESULT);
        emit_setb_reg(self.buf, op, REG_RESULT);
        emit_movzbl_reg_reg(self.buf, REG_RESULT, REG_RESULT);

        if dest != REG_RESULT {
            emit_movb_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_div(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, RAX);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cltd(self.buf);
        emit_idivl_reg_reg(self.buf, REG_TMP1);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_mod(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, RAX);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cltd(self.buf);
        emit_idivl_reg_reg(self.buf, REG_TMP1);

        if dest != RDX {
            emit_movl_reg_reg(self.buf, RDX, dest);
        }
    }

    fn emit_bin_mul(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_imull_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_add(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_addl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_sub(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_subl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_orl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_andl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_xor(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_xorl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_call(&mut self, e: &'ast ExprCallType, dest: Reg) {
        unreachable!("call");
    }
}
<commit_msg>retrieve function for call<commit_after>use codegen::buffer::*;
use codegen::emit;
use codegen::x64::emit::*;
use codegen::x64::reg::*;
use codegen::x64::reg::Reg::*;

use dseg::DSeg;

use parser::ast::ctxt::*;
use parser::ast::*;
use parser::ast::Expr::*;

pub enum ExprLoc {
    LocConst(i32),
    LocReg(Reg),
    LocStack(i32),
}

pub struct ExprGen<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'ast Function,
    buf: &'a mut Buffer,
    dseg: &'a mut DSeg,
}

impl<'a, 'ast> ExprGen<'a, 'ast> where 'ast: 'a {
    pub fn new(
        ctxt: &'a Context<'a, 'ast>,
        fct: &'ast Function,
        buf: &'a mut Buffer,
        dseg: &'a mut DSeg,
    ) -> ExprGen<'a, 'ast> {
        ExprGen {
            ctxt: ctxt,
            fct: fct,
            buf: buf,
            dseg: dseg,
        }
    }

    pub fn generate(mut self, e: &'ast Expr) -> Reg {
        self.emit_expr(e, REG_RESULT)
    }

    fn emit_expr(&mut self, e: &'ast Expr, dest: Reg) -> Reg {
        match *e {
            ExprLitInt(ref expr) => self.emit_lit_int(expr, dest),
            ExprLitBool(ref expr) => self.emit_lit_bool(expr, dest),
            ExprUn(ref expr) => self.emit_un(expr, dest),
            ExprIdent(ref expr) => self.emit_ident(expr, dest),
            ExprAssign(ref expr) => self.emit_assign(expr, dest),
            ExprBin(ref expr) => self.emit_bin(expr, dest),
            ExprCall(ref expr) => self.emit_call(expr, dest),
            _ => unreachable!(),
        }

        dest
    }

    fn emit_lit_int(&mut self, lit: &'ast ExprLitIntType, dest: Reg) {
        emit_movl_imm_reg(self.buf, lit.value as u32, dest);
    }

    fn emit_lit_bool(&mut self, lit: &'ast ExprLitBoolType, dest: Reg) {
        let value : u32 = if lit.value { 1 } else { 0 };
        emit_movl_imm_reg(self.buf, value, dest);
    }

    fn emit_ident(&mut self, e: &'ast ExprIdentType, dest: Reg) {
        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.id).unwrap();

        emit::var_load(self.buf, self.ctxt, varid, dest);
    }

    fn emit_un(&mut self, e: &'ast ExprUnType, dest: Reg) {
        self.emit_expr(&e.opnd, dest);

        match e.op {
            UnOp::Plus => {},
            UnOp::Neg => emit_negl_reg(self.buf, dest),
            UnOp::BitNot => emit_notl_reg(self.buf, dest),
            UnOp::Not => {
                emit_xorb_imm_reg(self.buf, 1, dest);
                emit_andb_imm_reg(self.buf, 1, dest);
            },
        }
    }

    fn emit_assign(&mut self, e: &'ast ExprAssignType, dest: Reg) {
        self.emit_expr(&e.rhs, dest);

        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.lhs.id()).unwrap();

        emit::var_store(&mut self.buf, self.ctxt, dest, varid);
    }

    fn emit_bin(&mut self, e: &'ast ExprBinType, dest: Reg) {
        assert!(e.rhs.is_leaf());

        match e.op {
            BinOp::Add => self.emit_bin_add(e, dest),
            BinOp::Sub => self.emit_bin_sub(e, dest),
            BinOp::Mul => self.emit_bin_mul(e, dest),
            BinOp::Div => self.emit_bin_div(e, dest),
            BinOp::Mod => self.emit_bin_mod(e, dest),
            BinOp::Cmp(op) => self.emit_bin_cmp(e, dest, op),
            BinOp::BitOr => self.emit_bin_bit_or(e, dest),
            BinOp::BitAnd => self.emit_bin_bit_and(e, dest),
            BinOp::BitXor => self.emit_bin_bit_xor(e, dest),
            BinOp::Or => self.emit_bin_or(e, dest),
            BinOp::And => self.emit_bin_and(e, dest),
        }
    }

    fn emit_bin_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jnz(self.buf, lbl_true);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.buf.define_label(lbl_true);
        emit_movl_imm_reg(self.buf, 1, REG_RESULT);
        emit_jmp(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit_movl_imm_reg(self.buf, 0, REG_RESULT);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit_cmpb_imm_reg(self.buf, 0, REG_RESULT);
        emit_jz(self.buf, lbl_false);

        self.buf.define_label(lbl_true);
        emit_movl_imm_reg(self.buf, 1, REG_RESULT);
        emit_jmp(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit_movl_imm_reg(self.buf, 0, REG_RESULT);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_cmp(&mut self, e: &'ast ExprBinType, dest: Reg, op: CmpOp) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cmpl_reg_reg(self.buf, REG_TMP1, REG_RESULT);
        emit_setb_reg(self.buf, op, REG_RESULT);
        emit_movzbl_reg_reg(self.buf, REG_RESULT, REG_RESULT);

        if dest != REG_RESULT {
            emit_movb_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_div(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, RAX);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cltd(self.buf);
        emit_idivl_reg_reg(self.buf, REG_TMP1);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_mod(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, RAX);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_cltd(self.buf);
        emit_idivl_reg_reg(self.buf, REG_TMP1);

        if dest != RDX {
            emit_movl_reg_reg(self.buf, RDX, dest);
        }
    }

    fn emit_bin_mul(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_imull_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_add(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_addl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_sub(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_subl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_orl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_andl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_bin_bit_xor(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_expr(&e.lhs, REG_RESULT);
        self.emit_expr(&e.rhs, REG_TMP1);

        emit_xorl_reg_reg(self.buf, REG_TMP1, REG_RESULT);

        if dest != REG_RESULT {
            emit_movl_reg_reg(self.buf, REG_RESULT, dest);
        }
    }

    fn emit_call(&mut self, e: &'ast ExprCallType, dest: Reg) {
        let calls = self.ctxt.calls.borrow();
        let fid = *calls.get(&e.id).unwrap();

        let fct_infos = self.ctxt.fct_infos.borrow();
        let fct = &fct_infos[fid.0];

        unreachable!("call");
    }
}
<|endoftext|>


<commit_before>//! Contains functions for tuning and controlling "The GNU Allocator", included in the `glibc`
//! library.
//!
//! https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html
//!
//! These functions are generally only suitable for Linux systems.
use lazy_static::lazy_static;
use lighthouse_metrics::*;
use parking_lot::Mutex;
use std::env;
use std::os::raw::c_int;
use std::result::Result;

/// The value to be provided to `malloc_mmap_threshold`.
///
/// Value chosen so that values of the validators tree hash cache will *not* be allocated via
/// `mmap`.
///
/// The size of a single chunk is:
///
/// NODES_PER_VALIDATOR * VALIDATORS_PER_ARENA * 32 = 15 * 4096 * 32 = 1.875 MiB
const OPTIMAL_MMAP_THRESHOLD: c_int = 2 * 1_024 * 1_024;

/// Constants used to configure malloc internals.
///
/// Source:
///
/// https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/malloc/malloc.h#L115-L123
const M_MMAP_THRESHOLD: c_int = -4;

/// Environment variables used to configure malloc.
///
/// Source:
///
/// https://man7.org/linux/man-pages/man3/mallopt.3.html
const ENV_VAR_MMAP_THRESHOLD: &str = "MALLOC_MMAP_THRESHOLD_";

lazy_static! {
    pub static ref GLOBAL_LOCK: Mutex<()> = <_>::default();
}

// Metrics for the malloc. For more information, see:
//
// https://man7.org/linux/man-pages/man3/mallinfo.3.html
lazy_static! {
    pub static ref MALLINFO_ARENA: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_arena",
        "The total amount of memory allocated by means other than mmap(2). \
            This figure includes both in-use blocks and blocks on the free list.",
    );
    pub static ref MALLINFO_ORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_ordblks",
        "The number of ordinary (i.e., non-fastbin) free blocks.",
    );
    pub static ref MALLINFO_SMBLKS: lighthouse_metrics::Result<IntGauge> =
        try_create_int_gauge("mallinfo_smblks", "The number of fastbin free blocks.",);
    pub static ref MALLINFO_HBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_hblks",
        "The number of blocks currently allocated using mmap.",
    );
    pub static ref MALLINFO_HBLKHD: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_hblkhd",
        "The number of bytes in blocks currently allocated using mmap.",
    );
    pub static ref MALLINFO_FSMBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_fsmblks",
        "The total number of bytes in fastbin free blocks.",
    );
    pub static ref MALLINFO_UORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_uordblks",
        "The total number of bytes used by in-use allocations.",
    );
    pub static ref MALLINFO_FORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_fordblks",
        "The total number of bytes in free blocks.",
    );
    pub static ref MALLINFO_KEEPCOST: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_keepcost",
        "The total amount of releasable free space at the top of the heap..",
    );
}

/// Calls `mallinfo` and updates Prometheus metrics with the results.
pub fn scrape_mallinfo_metrics() {
    let mallinfo = mallinfo();

    set_gauge(&MALLINFO_ARENA, unsigned_i64(mallinfo.arena));
    set_gauge(&MALLINFO_ORDBLKS, unsigned_i64(mallinfo.ordblks));
    set_gauge(&MALLINFO_SMBLKS, unsigned_i64(mallinfo.smblks));
    set_gauge(&MALLINFO_HBLKS, unsigned_i64(mallinfo.hblks));
    set_gauge(&MALLINFO_HBLKHD, unsigned_i64(mallinfo.hblkhd));
    set_gauge(&MALLINFO_FSMBLKS, unsigned_i64(mallinfo.fsmblks));
    set_gauge(&MALLINFO_UORDBLKS, unsigned_i64(mallinfo.uordblks));
    set_gauge(&MALLINFO_FORDBLKS, unsigned_i64(mallinfo.fordblks));
    set_gauge(&MALLINFO_KEEPCOST, unsigned_i64(mallinfo.keepcost));
}

/// Cast a C integer as returned by `mallinfo` to an unsigned i64.
///
/// A cast from `i32` to `i64` preserves the sign bit, resulting in incorrect negative values.
/// Going via `u32` treats the sign bit as part of the number.
///
/// Results are still wrong for memory usage over 4GiB due to limitations of mallinfo.
#[cfg(not(feature = "mallinfo2"))]
fn unsigned_i64(x: i32) -> i64 {
    x as u32 as i64
}

/// Cast a C `size_t` as returned by `mallinfo2` to an unsigned i64.
#[cfg(feature = "mallinfo2")]
fn unsigned_i64(x: usize) -> i64 {
    x as i64
}

/// Perform all configuration routines.
pub fn configure_glibc_malloc() -> Result<(), String> {
    if !env_var_present(ENV_VAR_MMAP_THRESHOLD) {
        if let Err(e) = malloc_mmap_threshold(OPTIMAL_MMAP_THRESHOLD) {
            return Err(format!("failed (code {}) to set malloc mmap threshold", e));
        }
    }

    Ok(())
}

/// Returns `true` if an environment variable is present.
fn env_var_present(name: &str) -> bool {
    env::var(name) != Err(env::VarError::NotPresent)
}

/// Uses `mallopt` to set the `M_MMAP_THRESHOLD` value, specifying the threshold where objects of this
/// size or larger are allocated via an `mmap`.
///
/// ## Resources
///
/// - https://man7.org/linux/man-pages/man3/mallopt.3.html
fn malloc_mmap_threshold(num_arenas: c_int) -> Result<(), c_int> {
    into_result(mallopt(M_MMAP_THRESHOLD, num_arenas))
}

fn mallopt(param: c_int, val: c_int) -> c_int {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallopt(param, val) }
}

/// By default we use `mallinfo`, but it overflows, so `mallinfo2` should be enabled if available.
///
/// https://man7.org/linux/man-pages/man3/mallinfo.3.html
#[cfg(not(feature = "mallinfo2"))]
fn mallinfo() -> libc::mallinfo {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallinfo() }
}

/// Use `mallinfo2` if enabled.
#[cfg(feature = "mallinfo2")]
fn mallinfo() -> libc::mallinfo2 {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallinfo2() }
}

fn into_result(result: c_int) -> Result<(), c_int> {
    if result == 1 {
        Ok(())
    } else {
        Err(result)
    }
}

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

    #[test]
    fn malloc_mmap_threshold_does_not_panic() {
        malloc_mmap_threshold(OPTIMAL_MMAP_THRESHOLD).unwrap();
    }
}
<commit_msg>Set mmap threshold to 128KB in malloc utils (#2937)<commit_after>//! Contains functions for tuning and controlling "The GNU Allocator", included in the `glibc`
//! library.
//!
//! https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html
//!
//! These functions are generally only suitable for Linux systems.
use lazy_static::lazy_static;
use lighthouse_metrics::*;
use parking_lot::Mutex;
use std::env;
use std::os::raw::c_int;
use std::result::Result;

/// The optimal mmap threshold for Lighthouse seems to be around 128KB.
///
/// By default GNU malloc will start with a threshold of 128KB and adjust it upwards, but we've
/// found that the upwards adjustments tend to result in heap fragmentation. Explicitly setting the
/// threshold to 128KB disables the dynamic adjustments and encourages `mmap` usage, which keeps the
/// heap size under control.
const OPTIMAL_MMAP_THRESHOLD: c_int = 128 * 1_024;

/// Constants used to configure malloc internals.
///
/// Source:
///
/// https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/malloc/malloc.h#L115-L123
const M_MMAP_THRESHOLD: c_int = -3;

/// Environment variables used to configure malloc.
///
/// Source:
///
/// https://man7.org/linux/man-pages/man3/mallopt.3.html
const ENV_VAR_MMAP_THRESHOLD: &str = "MALLOC_MMAP_THRESHOLD_";

lazy_static! {
    pub static ref GLOBAL_LOCK: Mutex<()> = <_>::default();
}

// Metrics for the malloc. For more information, see:
//
// https://man7.org/linux/man-pages/man3/mallinfo.3.html
lazy_static! {
    pub static ref MALLINFO_ARENA: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_arena",
        "The total amount of memory allocated by means other than mmap(2). \
            This figure includes both in-use blocks and blocks on the free list.",
    );
    pub static ref MALLINFO_ORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_ordblks",
        "The number of ordinary (i.e., non-fastbin) free blocks.",
    );
    pub static ref MALLINFO_SMBLKS: lighthouse_metrics::Result<IntGauge> =
        try_create_int_gauge("mallinfo_smblks", "The number of fastbin free blocks.",);
    pub static ref MALLINFO_HBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_hblks",
        "The number of blocks currently allocated using mmap.",
    );
    pub static ref MALLINFO_HBLKHD: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_hblkhd",
        "The number of bytes in blocks currently allocated using mmap.",
    );
    pub static ref MALLINFO_FSMBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_fsmblks",
        "The total number of bytes in fastbin free blocks.",
    );
    pub static ref MALLINFO_UORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_uordblks",
        "The total number of bytes used by in-use allocations.",
    );
    pub static ref MALLINFO_FORDBLKS: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_fordblks",
        "The total number of bytes in free blocks.",
    );
    pub static ref MALLINFO_KEEPCOST: lighthouse_metrics::Result<IntGauge> = try_create_int_gauge(
        "mallinfo_keepcost",
        "The total amount of releasable free space at the top of the heap..",
    );
}

/// Calls `mallinfo` and updates Prometheus metrics with the results.
pub fn scrape_mallinfo_metrics() {
    let mallinfo = mallinfo();

    set_gauge(&MALLINFO_ARENA, unsigned_i64(mallinfo.arena));
    set_gauge(&MALLINFO_ORDBLKS, unsigned_i64(mallinfo.ordblks));
    set_gauge(&MALLINFO_SMBLKS, unsigned_i64(mallinfo.smblks));
    set_gauge(&MALLINFO_HBLKS, unsigned_i64(mallinfo.hblks));
    set_gauge(&MALLINFO_HBLKHD, unsigned_i64(mallinfo.hblkhd));
    set_gauge(&MALLINFO_FSMBLKS, unsigned_i64(mallinfo.fsmblks));
    set_gauge(&MALLINFO_UORDBLKS, unsigned_i64(mallinfo.uordblks));
    set_gauge(&MALLINFO_FORDBLKS, unsigned_i64(mallinfo.fordblks));
    set_gauge(&MALLINFO_KEEPCOST, unsigned_i64(mallinfo.keepcost));
}

/// Cast a C integer as returned by `mallinfo` to an unsigned i64.
///
/// A cast from `i32` to `i64` preserves the sign bit, resulting in incorrect negative values.
/// Going via `u32` treats the sign bit as part of the number.
///
/// Results are still wrong for memory usage over 4GiB due to limitations of mallinfo.
#[cfg(not(feature = "mallinfo2"))]
fn unsigned_i64(x: i32) -> i64 {
    x as u32 as i64
}

/// Cast a C `size_t` as returned by `mallinfo2` to an unsigned i64.
#[cfg(feature = "mallinfo2")]
fn unsigned_i64(x: usize) -> i64 {
    x as i64
}

/// Perform all configuration routines.
pub fn configure_glibc_malloc() -> Result<(), String> {
    if !env_var_present(ENV_VAR_MMAP_THRESHOLD) {
        if let Err(e) = malloc_mmap_threshold(OPTIMAL_MMAP_THRESHOLD) {
            return Err(format!("failed (code {}) to set malloc mmap threshold", e));
        }
    }

    Ok(())
}

/// Returns `true` if an environment variable is present.
fn env_var_present(name: &str) -> bool {
    env::var(name) != Err(env::VarError::NotPresent)
}

/// Uses `mallopt` to set the `M_MMAP_THRESHOLD` value, specifying the threshold where objects of this
/// size or larger are allocated via an `mmap`.
///
/// ## Resources
///
/// - https://man7.org/linux/man-pages/man3/mallopt.3.html
fn malloc_mmap_threshold(threshold: c_int) -> Result<(), c_int> {
    into_result(mallopt(M_MMAP_THRESHOLD, threshold))
}

fn mallopt(param: c_int, val: c_int) -> c_int {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallopt(param, val) }
}

/// By default we use `mallinfo`, but it overflows, so `mallinfo2` should be enabled if available.
///
/// https://man7.org/linux/man-pages/man3/mallinfo.3.html
#[cfg(not(feature = "mallinfo2"))]
fn mallinfo() -> libc::mallinfo {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallinfo() }
}

/// Use `mallinfo2` if enabled.
#[cfg(feature = "mallinfo2")]
fn mallinfo() -> libc::mallinfo2 {
    // Prevent this function from being called in parallel with any other non-thread-safe function.
    let _lock = GLOBAL_LOCK.lock();
    unsafe { libc::mallinfo2() }
}

fn into_result(result: c_int) -> Result<(), c_int> {
    if result == 1 {
        Ok(())
    } else {
        Err(result)
    }
}

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

    #[test]
    fn malloc_mmap_threshold_does_not_panic() {
        malloc_mmap_threshold(OPTIMAL_MMAP_THRESHOLD).unwrap();
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbimage;
extern crate orbfont;

#[cfg(target_os = "redox")]
static UI_PATH: &'static str = "/ui";

#[cfg(not(target_os = "redox"))]
static UI_PATH: &'static str = "ui";

#[cfg(not(target_os = "redox"))]
fn wait(status: &mut i32) -> usize {
    extern crate libc;

    use std::io::Error;

    let pid = unsafe { libc::waitpid(0, status as *mut i32, libc::WNOHANG) };
    if pid < 0 {
        panic!("waitpid failed: {}", Error::last_os_error());
    }
    pid as usize
}

#[cfg(target_os = "redox")]
fn wait(status: &mut usize) -> usize {
    extern crate syscall;

    syscall::waitpid(0, status, syscall::WNOHANG).unwrap()
}

use std::env;
use std::os::unix::process::ExitStatusExt;
use std::path::Path;
use std::process::{Command, ExitStatus};

use orbclient::{Color, EventOption, Renderer, Window, K_ESC};
use orbimage::Image;
use orbfont::Font;

use package::Package;

pub mod package;

const BAR_COLOR: Color = Color::rgb(40, 45, 57);
const BAR_HIGHLIGHT_COLOR: Color = Color::rgb(80, 86, 102);
const TEXT_COLOR: Color = Color::rgb(204, 210, 224);
const TEXT_HIGHLIGHT_COLOR: Color = Color::rgb(235, 241, 255);

fn get_packages() -> Vec<Package> {
    let read_dir = Path::new(&format!("{}/apps/", UI_PATH)).read_dir().expect("failed to read apps directory");

    let mut entries = vec![];
    for dir in read_dir {
        let dir = match dir {
            Ok(x) => x,
            Err(_) => continue,
        };
        let file_name = dir.file_name().to_string_lossy().into_owned();
        if dir.file_type().expect("failed to get file_type").is_file() {
            entries.push(file_name);
        }
    }

    entries.sort();

    let mut packages: Vec<Package> = Vec::new();
    for entry in entries.iter() {
        packages.push(Package::from_path(&format!("{}/apps/{}", UI_PATH, entry)));
    }

    packages
}

fn draw(window: &mut Window, packages: &Vec<Package>, start: &Image, shutdown: &Image, selected: i32){
    let w = window.width();
    let h = window.height();
    window.set(BAR_COLOR);

    let mut x = 0;
    let mut i = 0;

    {
        let y = h as isize - start.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              start.width() as u32, start.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        start.draw(window, x as i32, y as i32);

        x += start.width() as i32;
        i += 1;
    }

    for package in packages.iter() {
        let y = h as isize - package.icon.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              package.icon.width() as u32, package.icon.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, x as i32, y as i32);

        x += package.icon.width() as i32;
        i += 1;
    }

    {
        x = w as i32 - shutdown.width() as i32;
        let y = h as isize - shutdown.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              shutdown.width() as u32, shutdown.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        shutdown.draw(window, x as i32, y as i32);
    }

    window.sync();
}

fn draw_chooser(window: &mut Window, font: &Font, packages: &Vec<Package>, selected: i32){
    let w = window.width();

    window.set(BAR_COLOR);

    let mut y = 0;
    for (i, package) in packages.iter().enumerate() {
        if i as i32 == selected {
            window.rect(0, y, w, 32, BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, 0, y);

        let mut c_x = 40;
        for c in package.name.chars() {
            font.render(&c.to_string(), 16.0).draw(window, c_x as i32, y + 8, if i as i32 == selected { TEXT_HIGHLIGHT_COLOR } else { TEXT_COLOR });
            c_x += 8;
        }

        y += 32;
    }

    window.sync();
}

fn bar_main() {
    let mut children = Vec::new();

    let packages = get_packages();

    let start = Image::from_path(format!("{}/icons/start.png", UI_PATH)).unwrap_or(Image::default());

    let shutdown = Image::from_path(format!("{}/icons/actions/system-log-out.png", UI_PATH)).unwrap_or(Image::default());

    let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
    let mut window = Window::new(0, height as i32 - 32, width, 32, "").expect("launcher: failed to open window");

    let mut selected = -1;
    let mut last_left_button = false;

    draw(&mut window, &packages, &start, &shutdown, selected);
    'running: loop {
        for event in window.events() {
            match event.to_option() {
                EventOption::Mouse(mouse_event) => {
                    let mut now_selected = -1;

                    {
                        let mut x = 0;
                        let mut i = 0;

                        {
                            let y = window.height() as i32 - start.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + start.width() as i32 {
                                   now_selected = i;
                            }
                            x += start.width() as i32;
                            i += 1;
                        }

                        for package in packages.iter() {
                            let y = window.height() as i32 - package.icon.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + package.icon.width() as i32 {
                                now_selected = i;
                            }
                            x += package.icon.width() as i32;
                            i += 1;
                        }

                        {
                            x = window.width() as i32 - shutdown.width() as i32;
                            let y = window.height() as i32 - shutdown.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + shutdown.width() as i32 {
                                   now_selected = i;
                            }
                        }
                    }

                    if now_selected != selected {
                        selected = now_selected;
                        draw(&mut window, &packages, &start, &shutdown, selected);
                    }

                    if ! mouse_event.left_button && last_left_button {
                        let mut i = 0;

                        if i == selected {
                            let start_h = packages.len() as u32 * 32;
                            let mut start_window = Window::new(0, height as i32 - 32 - start_h as i32, 400, start_h, "").unwrap();
                            let font = Font::find(None, None, None).unwrap();

                            let mut selected = -1;
                            let mut last_left_button = false;

                            draw_chooser(&mut start_window, &font, &packages, selected);
                            'start_choosing: loop {
                                for event in start_window.events() {
                                    match event.to_option() {
                                        EventOption::Mouse(mouse_event) => {
                                            let mut now_selected = -1;

                                            let mut y = 0;
                                            for (i, _package) in packages.iter().enumerate() {
                                                if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                    now_selected = i as i32;
                                                }
                                                y += 32;
                                            }

                                            if now_selected != selected {
                                                selected = now_selected;
                                                draw_chooser(&mut start_window, &font, &packages, selected);
                                            }

                                            if ! mouse_event.left_button && last_left_button {
                                                let mut y = 0;
                                                for package in packages.iter() {
                                                    if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                        match Command::new(&package.binary).spawn() {
                                                            Ok(child) => children.push(child),
                                                            Err(err) => println!("launcher: failed to launch {}: {}", package.binary, err)
                                                        }
                                                        break 'start_choosing;
                                                    }
                                                    y += 32;
                                                }
                                            }

                                            last_left_button = mouse_event.left_button;
                                        },
                                        EventOption::Key(key_event) => {
                                            match key_event.scancode {
                                                K_ESC => break 'start_choosing,
                                                _ => ()
                                            }
                                        },
                                        EventOption::Focus(focus_event) => if ! focus_event.focused {
                                            break 'start_choosing;
                                        },
                                        EventOption::Quit(_) => break 'start_choosing,
                                        _ => ()
                                    }
                                }
                            }
                        }
                        i += 1;

                        for package in packages.iter() {
                            if i == selected {
                                match Command::new(&package.binary).spawn() {
                                    Ok(child) => children.push(child),
                                    Err(err) => println!("launcher: failed to launch {}: {}", package.binary, err)
                                }
                            }
                            i += 1;
                        }

                        if i == selected {
                               break 'running;
                        }
                    }

                    last_left_button = mouse_event.left_button;
                },
                EventOption::Quit(_) => break 'running,
                _ => ()
            }
        }
    }

    for mut child in children {
        let pid = child.id();
        match child.kill() {
            Ok(()) => (),
            Err(err) => println!("launcher: failed to kill {}: {}", pid, err),
        }
        match child.wait() {
            Ok(status) => println!("launcher: {} exited with {}", pid, status),
            Err(err) => println!("launcher: failed to wait for {}: {}", pid, err),
        }
    }

    loop {
        let mut status = 0;
        let pid = wait(&mut status);
        if pid == 0 {
            break;
        } else {
            println!("launcher: reaping zombie {}: {}", pid, ExitStatus::from_raw(status as i32));
        }
    }
}

fn chooser_main(paths: env::Args) {
    for ref path in paths.skip(1) {
        let mut packages = get_packages();

        packages.retain(|package| -> bool {
            for accept in package.accepts.iter() {
                if (accept.starts_with('*') && path.ends_with(&accept[1 ..])) ||
                   (accept.ends_with('*') && path.starts_with(&accept[.. accept.len() - 1])) {
                    return true;
                }
            }
            false
        });

        if packages.len() > 1 {
            let mut window = Window::new(-1, -1, 400, packages.len() as u32 * 32, path).expect("launcher: failed to open window");
            let font = Font::find(None, None, None).expect("launcher: failed to open font");

            let mut selected = -1;
            let mut last_left_button = false;

            draw_chooser(&mut window, &font, &packages, selected);
            'choosing: loop {
                for event in window.events() {
                    match event.to_option() {
                        EventOption::Mouse(mouse_event) => {
                            let mut now_selected = -1;

                            let mut y = 0;
                            for (i, _package) in packages.iter().enumerate() {
                                if mouse_event.y >= y && mouse_event.y < y + 32 {
                                    now_selected = i as i32;
                                }
                                y += 32;
                            }

                            if now_selected != selected {
                                selected = now_selected;
                                draw_chooser(&mut window, &font, &packages, selected);
                            }

                            if ! mouse_event.left_button && last_left_button {
                                let mut y = 0;
                                for package in packages.iter() {
                                    if mouse_event.y >= y && mouse_event.y < y + 32 {
                                        if let Err(err) = Command::new(&package.binary).arg(path).spawn() {
                                            println!("launcher: failed to launch {}: {}", package.binary, err);
                                        }
                                        break 'choosing;
                                    }
                                    y += 32;
                                }
                            }

                            last_left_button = mouse_event.left_button;
                        },
                        EventOption::Quit(_) => break 'choosing,
                        _ => ()
                    }
                }
            }
        } else if let Some(package) = packages.get(0) {
            if let Err(err) = Command::new(&package.binary).arg(&path).spawn() {
                println!("launcher: failed to launch '{}': {}", package.binary, err);
            }
        } else {
            println!("launcher: no application found for '{}'", path);
        }
    }
}

fn main() {
    let paths = env::args();
    if paths.len() > 1 {
        chooser_main(paths);
    } else {
        bar_main();
    }
}
<commit_msg>Transparent launcher, resize chooser<commit_after>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbimage;
extern crate orbfont;

#[cfg(target_os = "redox")]
static UI_PATH: &'static str = "/ui";

#[cfg(not(target_os = "redox"))]
static UI_PATH: &'static str = "ui";

#[cfg(not(target_os = "redox"))]
fn wait(status: &mut i32) -> usize {
    extern crate libc;

    use std::io::Error;

    let pid = unsafe { libc::waitpid(0, status as *mut i32, libc::WNOHANG) };
    if pid < 0 {
        panic!("waitpid failed: {}", Error::last_os_error());
    }
    pid as usize
}

#[cfg(target_os = "redox")]
fn wait(status: &mut usize) -> usize {
    extern crate syscall;

    syscall::waitpid(0, status, syscall::WNOHANG).unwrap()
}

use std::env;
use std::os::unix::process::ExitStatusExt;
use std::path::Path;
use std::process::{Command, ExitStatus};

use orbclient::{Color, EventOption, Renderer, Window, K_ESC};
use orbimage::Image;
use orbfont::Font;

use package::Package;

pub mod package;

const BAR_COLOR: Color = Color::rgba(40, 45, 57, 224);
const BAR_HIGHLIGHT_COLOR: Color = Color::rgb(80, 86, 102);
const TEXT_COLOR: Color = Color::rgb(204, 210, 224);
const TEXT_HIGHLIGHT_COLOR: Color = Color::rgb(235, 241, 255);

fn get_packages() -> Vec<Package> {
    let read_dir = Path::new(&format!("{}/apps/", UI_PATH)).read_dir().expect("failed to read apps directory");

    let mut entries = vec![];
    for dir in read_dir {
        let dir = match dir {
            Ok(x) => x,
            Err(_) => continue,
        };
        let file_name = dir.file_name().to_string_lossy().into_owned();
        if dir.file_type().expect("failed to get file_type").is_file() {
            entries.push(file_name);
        }
    }

    entries.sort();

    let mut packages: Vec<Package> = Vec::new();
    for entry in entries.iter() {
        packages.push(Package::from_path(&format!("{}/apps/{}", UI_PATH, entry)));
    }

    packages
}

fn draw(window: &mut Window, packages: &Vec<Package>, start: &Image, shutdown: &Image, selected: i32){
    let w = window.width();
    let h = window.height();
    window.set(BAR_COLOR);

    let mut x = 0;
    let mut i = 0;

    {
        let y = h as isize - start.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              start.width() as u32, start.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        start.draw(window, x as i32, y as i32);

        x += start.width() as i32;
        i += 1;
    }

    for package in packages.iter() {
        let y = h as isize - package.icon.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              package.icon.width() as u32, package.icon.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, x as i32, y as i32);

        x += package.icon.width() as i32;
        i += 1;
    }

    {
        x = w as i32 - shutdown.width() as i32;
        let y = h as isize - shutdown.height() as isize;

        if i == selected {
            window.rect(x as i32, y as i32,
                              shutdown.width() as u32, shutdown.height() as u32,
                              BAR_HIGHLIGHT_COLOR);
        }

        shutdown.draw(window, x as i32, y as i32);
    }

    window.sync();
}

fn draw_chooser(window: &mut Window, font: &Font, packages: &Vec<Package>, selected: i32){
    let w = window.width();

    window.set(BAR_COLOR);

    let mut y = 0;
    for (i, package) in packages.iter().enumerate() {
        if i as i32 == selected {
            window.rect(0, y, w, 32, BAR_HIGHLIGHT_COLOR);
        }

        package.icon.draw(window, 0, y);

        let mut c_x = 40;
        for c in package.name.chars() {
            font.render(&c.to_string(), 16.0).draw(window, c_x as i32, y + 8, if i as i32 == selected { TEXT_HIGHLIGHT_COLOR } else { TEXT_COLOR });
            c_x += 8;
        }

        y += 32;
    }

    window.sync();
}

fn bar_main() {
    let mut children = Vec::new();

    let packages = get_packages();

    let start = Image::from_path(format!("{}/icons/start.png", UI_PATH)).unwrap_or(Image::default());

    let shutdown = Image::from_path(format!("{}/icons/actions/system-log-out.png", UI_PATH)).unwrap_or(Image::default());

    let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
    let mut window = Window::new(0, height as i32 - 32, width, 32, "").expect("launcher: failed to open window");

    let mut selected = -1;
    let mut last_left_button = false;

    draw(&mut window, &packages, &start, &shutdown, selected);
    'running: loop {
        for event in window.events() {
            match event.to_option() {
                EventOption::Mouse(mouse_event) => {
                    let mut now_selected = -1;

                    {
                        let mut x = 0;
                        let mut i = 0;

                        {
                            let y = window.height() as i32 - start.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + start.width() as i32 {
                                   now_selected = i;
                            }
                            x += start.width() as i32;
                            i += 1;
                        }

                        for package in packages.iter() {
                            let y = window.height() as i32 - package.icon.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + package.icon.width() as i32 {
                                now_selected = i;
                            }
                            x += package.icon.width() as i32;
                            i += 1;
                        }

                        {
                            x = window.width() as i32 - shutdown.width() as i32;
                            let y = window.height() as i32 - shutdown.height() as i32;
                            if mouse_event.y >= y && mouse_event.x >= x &&
                               mouse_event.x < x + shutdown.width() as i32 {
                                   now_selected = i;
                            }
                        }
                    }

                    if now_selected != selected {
                        selected = now_selected;
                        draw(&mut window, &packages, &start, &shutdown, selected);
                    }

                    if ! mouse_event.left_button && last_left_button {
                        let mut i = 0;

                        if i == selected {
                            let start_h = packages.len() as u32 * 32;
                            let mut start_window = Window::new(0, height as i32 - 32 - start_h as i32, 320, start_h, "").unwrap();
                            let font = Font::find(None, None, None).unwrap();

                            let mut selected = -1;
                            let mut last_left_button = false;

                            draw_chooser(&mut start_window, &font, &packages, selected);
                            'start_choosing: loop {
                                for event in start_window.events() {
                                    match event.to_option() {
                                        EventOption::Mouse(mouse_event) => {
                                            let mut now_selected = -1;

                                            let mut y = 0;
                                            for (i, _package) in packages.iter().enumerate() {
                                                if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                    now_selected = i as i32;
                                                }
                                                y += 32;
                                            }

                                            if now_selected != selected {
                                                selected = now_selected;
                                                draw_chooser(&mut start_window, &font, &packages, selected);
                                            }

                                            if ! mouse_event.left_button && last_left_button {
                                                let mut y = 0;
                                                for package in packages.iter() {
                                                    if mouse_event.y >= y && mouse_event.y < y + 32 {
                                                        match Command::new(&package.binary).spawn() {
                                                            Ok(child) => children.push(child),
                                                            Err(err) => println!("launcher: failed to launch {}: {}", package.binary, err)
                                                        }
                                                        break 'start_choosing;
                                                    }
                                                    y += 32;
                                                }
                                            }

                                            last_left_button = mouse_event.left_button;
                                        },
                                        EventOption::Key(key_event) => {
                                            match key_event.scancode {
                                                K_ESC => break 'start_choosing,
                                                _ => ()
                                            }
                                        },
                                        EventOption::Focus(focus_event) => if ! focus_event.focused {
                                            break 'start_choosing;
                                        },
                                        EventOption::Quit(_) => break 'start_choosing,
                                        _ => ()
                                    }
                                }
                            }
                        }
                        i += 1;

                        for package in packages.iter() {
                            if i == selected {
                                match Command::new(&package.binary).spawn() {
                                    Ok(child) => children.push(child),
                                    Err(err) => println!("launcher: failed to launch {}: {}", package.binary, err)
                                }
                            }
                            i += 1;
                        }

                        if i == selected {
                               break 'running;
                        }
                    }

                    last_left_button = mouse_event.left_button;
                },
                EventOption::Quit(_) => break 'running,
                _ => ()
            }
        }
    }

    for mut child in children {
        let pid = child.id();
        match child.kill() {
            Ok(()) => (),
            Err(err) => println!("launcher: failed to kill {}: {}", pid, err),
        }
        match child.wait() {
            Ok(status) => println!("launcher: {} exited with {}", pid, status),
            Err(err) => println!("launcher: failed to wait for {}: {}", pid, err),
        }
    }

    loop {
        let mut status = 0;
        let pid = wait(&mut status);
        if pid == 0 {
            break;
        } else {
            println!("launcher: reaping zombie {}: {}", pid, ExitStatus::from_raw(status as i32));
        }
    }
}

fn chooser_main(paths: env::Args) {
    for ref path in paths.skip(1) {
        let mut packages = get_packages();

        packages.retain(|package| -> bool {
            for accept in package.accepts.iter() {
                if (accept.starts_with('*') && path.ends_with(&accept[1 ..])) ||
                   (accept.ends_with('*') && path.starts_with(&accept[.. accept.len() - 1])) {
                    return true;
                }
            }
            false
        });

        if packages.len() > 1 {
            let mut window = Window::new(-1, -1, 320, packages.len() as u32 * 32, path).expect("launcher: failed to open window");
            let font = Font::find(None, None, None).expect("launcher: failed to open font");

            let mut selected = -1;
            let mut last_left_button = false;

            draw_chooser(&mut window, &font, &packages, selected);
            'choosing: loop {
                for event in window.events() {
                    match event.to_option() {
                        EventOption::Mouse(mouse_event) => {
                            let mut now_selected = -1;

                            let mut y = 0;
                            for (i, _package) in packages.iter().enumerate() {
                                if mouse_event.y >= y && mouse_event.y < y + 32 {
                                    now_selected = i as i32;
                                }
                                y += 32;
                            }

                            if now_selected != selected {
                                selected = now_selected;
                                draw_chooser(&mut window, &font, &packages, selected);
                            }

                            if ! mouse_event.left_button && last_left_button {
                                let mut y = 0;
                                for package in packages.iter() {
                                    if mouse_event.y >= y && mouse_event.y < y + 32 {
                                        if let Err(err) = Command::new(&package.binary).arg(path).spawn() {
                                            println!("launcher: failed to launch {}: {}", package.binary, err);
                                        }
                                        break 'choosing;
                                    }
                                    y += 32;
                                }
                            }

                            last_left_button = mouse_event.left_button;
                        },
                        EventOption::Quit(_) => break 'choosing,
                        _ => ()
                    }
                }
            }
        } else if let Some(package) = packages.get(0) {
            if let Err(err) = Command::new(&package.binary).arg(&path).spawn() {
                println!("launcher: failed to launch '{}': {}", package.binary, err);
            }
        } else {
            println!("launcher: no application found for '{}'", path);
        }
    }
}

fn main() {
    let paths = env::args();
    if paths.len() > 1 {
        chooser_main(paths);
    } else {
        bar_main();
    }
}
<|endoftext|>