<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 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)
        .fold(0, |a, i| a + i)
}

/// 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())
        .fold(0, |a, i| a + i)
}

/// 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))
        .fold(0, |a, i| a + i)
}

/// 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
pub 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_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.
#[inline]
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

fn value_size_no_tag<T: ProtobufVarint>(value: T, wt: WireType) -> u64 {
    match wt {
        WireType::Fixed64 => 8,
        WireType::Fixed32 => 4,
        WireType::Varint => value.len_varint(),
        _ => panic!(),
    }
}

/// Integer value size when encoded as specified wire type.
pub fn value_size<T: ProtobufVarint>(field_number: u32, value: T, wt: WireType) -> u64 {
    tag_size(field_number) + value_size_no_tag(value, wt)
}

/// Integer value size when encoded as specified wire type.
pub(crate) fn value_varint_zigzag_size_no_tag<T: ProtobufVarintZigzag>(value: T) -> u64 {
    value.len_varint_zigzag()
}

/// Length of value when encoding with zigzag encoding with tag
#[inline]
pub(crate) fn value_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, value: T) -> u64 {
    tag_size(field_number) + value_varint_zigzag_size_no_tag(value)
}

/// Size of serialized `sint32` field.
#[inline]
pub fn sint32_size(field_number: u32, value: i32) -> u64 {
    value_varint_zigzag_size(field_number, value)
}

/// Size of serialized `sint64` field.
#[inline]
pub fn sint64_size(field_number: u32, value: i64) -> u64 {
    value_varint_zigzag_size(field_number, value)
}

fn enum_or_unknown_size_no_tag<E: Enum>(value: EnumOrUnknown<E>) -> u64 {
    value.value().len_varint() as u64
}

/// Size of encoded enum field value.
pub fn enum_or_unknown_size<E: Enum>(field_number: u32, value: EnumOrUnknown<E>) -> u64 {
    tag_size(field_number) + enum_or_unknown_size_no_tag(value)
}

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

/// Size of encoded bytes field.
pub fn bytes_size(field_number: u32, bytes: &[u8]) -> u64 {
    tag_size(field_number) + bytes_size_no_tag(bytes)
}

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

/// Size of encoded string field.
pub fn string_size(field_number: u32, s: &str) -> u64 {
    tag_size(field_number) + string_size_no_tag(s)
}

/// 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>Mark some functions inline<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)
        .fold(0, |a, i| a + i)
}

/// 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())
        .fold(0, |a, i| a + i)
}

/// 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))
        .fold(0, |a, i| a + i)
}

/// 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
pub 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_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.
#[inline]
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

fn value_size_no_tag<T: ProtobufVarint>(value: T, wt: WireType) -> u64 {
    match wt {
        WireType::Fixed64 => 8,
        WireType::Fixed32 => 4,
        WireType::Varint => value.len_varint(),
        _ => panic!(),
    }
}

/// Integer value size when encoded as specified wire type.
pub fn value_size<T: ProtobufVarint>(field_number: u32, value: T, wt: WireType) -> u64 {
    tag_size(field_number) + value_size_no_tag(value, wt)
}

/// Integer value size when encoded as specified wire type.
pub(crate) fn value_varint_zigzag_size_no_tag<T: ProtobufVarintZigzag>(value: T) -> u64 {
    value.len_varint_zigzag()
}

/// Length of value when encoding with zigzag encoding with tag
#[inline]
pub(crate) fn value_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, value: T) -> u64 {
    tag_size(field_number) + value_varint_zigzag_size_no_tag(value)
}

/// Size of serialized `sint32` field.
#[inline]
pub fn sint32_size(field_number: u32, value: i32) -> u64 {
    value_varint_zigzag_size(field_number, value)
}

/// Size of serialized `sint64` field.
#[inline]
pub fn sint64_size(field_number: u32, value: i64) -> u64 {
    value_varint_zigzag_size(field_number, value)
}

fn enum_or_unknown_size_no_tag<E: Enum>(value: EnumOrUnknown<E>) -> u64 {
    value.value().len_varint() as u64
}

/// Size of encoded enum field value.
#[inline]
pub fn enum_or_unknown_size<E: Enum>(field_number: u32, value: EnumOrUnknown<E>) -> u64 {
    tag_size(field_number) + enum_or_unknown_size_no_tag(value)
}

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

/// Size of encoded bytes field.
#[inline]
pub fn bytes_size(field_number: u32, bytes: &[u8]) -> u64 {
    tag_size(field_number) + bytes_size_no_tag(bytes)
}

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

/// Size of encoded string field.
#[inline]
pub fn string_size(field_number: u32, s: &str) -> u64 {
    tag_size(field_number) + string_size_no_tag(s)
}

/// 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>//! Library for generating relative datestream
//!
//! This is some long documentation

extern crate chrono;

#[cfg(test)]
mod test {
    use chrono::{Datelike, Duration, NaiveDate, Weekday};

    #[test]
    fn can_detect_day_of_week() {
        let date = NaiveDate::from_ymd(2016, 3, 24);

        assert!(Weekday::Thu == date.weekday());
    }

}<commit_msg>go to rust book and come back later<commit_after>//! Library for generating relative datestream
//!
//! This is some long documentation

extern crate chrono;

use chrono::{Datelike, Duration, NaiveDate, Weekday};

/// Allows iteration of arbitary range
///
/// This is some long description of below code.
pub struct DateRangeIterator<F> {
    d: NaiveDate,
    f: F,
}

// what is where F: FnMut .... ?
impl<F> Iterator for DateRangeIterator<F>
    where F: FnMut(&NaiveDate) -> Option<NaiveDate>
{
    type Item = NaiveDate;

    fn next(&mut self) -> Option<NaiveDate> {
        let ret = (self.f)(&self.i);
        if ret.is_some() { self.i = ret.unwrap(); }
        ret
    }
}

#[cfg(test)]
mod test {
    use chrono::{Datelike, Duration, NaiveDate, Weekday};

    #[test]
    fn can_detect_day_of_week() {
        let date = NaiveDate::from_ymd(2016, 3, 24);

        assert!(Weekday::Thu == date.weekday());
    }

}<|endoftext|>


<commit_before>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

pub use vm_memory_upstream::{
    address, bitmap::Bitmap, mmap::MmapRegionBuilder, mmap::MmapRegionError, Address, ByteValued,
    Bytes, Error, FileOffset, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion,
    GuestUsize, MemoryRegionAddress,
};

use std::io::Error as IoError;
use std::os::unix::io::AsRawFd;

use vm_memory_upstream::bitmap::AtomicBitmap;
use vm_memory_upstream::mmap::{check_file_offset, NewBitmap};
use vm_memory_upstream::{
    GuestMemoryMmap as UpstreamGuestMemoryMmap, GuestRegionMmap as UpstreamGuestRegionMmap,
    MmapRegion as UpstreamMmapRegion,
};

pub type GuestMemoryMmap = UpstreamGuestMemoryMmap<Option<AtomicBitmap>>;
pub type GuestRegionMmap = UpstreamGuestRegionMmap<Option<AtomicBitmap>>;
pub type MmapRegion = UpstreamMmapRegion<Option<AtomicBitmap>>;

const GUARD_PAGE_COUNT: usize = 1;

/// Build a `MmapRegion` surrounded by guard pages.
///
/// Initially, we map a `PROT_NONE` guard region of size:
/// `size` + (GUARD_PAGE_COUNT * 2 * page_size).
/// The guard region is mapped with `PROT_NONE`, so that any access to this region will cause
/// a SIGSEGV.
///
/// The actual accessible region is going to be nested in the larger guard region.
/// This is done by mapping over the guard region, starting at an address of
/// `guard_region_addr + (GUARD_PAGE_COUNT * page_size)`.
/// This results in a border of `GUARD_PAGE_COUNT` pages on either side of the region, which
/// acts as a safety net for accessing out-of-bounds addresses that are not allocated for the
/// guest's memory.
fn build_guarded_region(
    maybe_file_offset: Option<FileOffset>,
    size: usize,
    prot: i32,
    flags: i32,
    track_dirty_pages: bool,
) -> Result<MmapRegion, MmapRegionError> {
    let page_size = utils::get_page_size().expect("Cannot retrieve page size.");
    // Create the guarded range size (received size + X pages),
    // where X is defined as a constant GUARD_PAGE_COUNT.
    let guarded_size = size + GUARD_PAGE_COUNT * 2 * page_size;

    // Map the guarded range to PROT_NONE
    let guard_addr = unsafe {
        libc::mmap(
            std::ptr::null_mut(),
            guarded_size,
            libc::PROT_NONE,
            libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_NORESERVE,
            -1,
            0,
        )
    };

    if guard_addr == libc::MAP_FAILED {
        return Err(MmapRegionError::Mmap(IoError::last_os_error()));
    }

    let (fd, offset) = match maybe_file_offset {
        Some(ref file_offset) => {
            check_file_offset(file_offset, size)?;
            (file_offset.file().as_raw_fd(), file_offset.start())
        }
        None => (-1, 0),
    };

    let region_start_addr = guard_addr as usize + page_size * GUARD_PAGE_COUNT;

    // Inside the protected range, starting with guard_addr + PAGE_SIZE,
    // map the requested range with received protection and flags
    let region_addr = unsafe {
        libc::mmap(
            region_start_addr as *mut libc::c_void,
            size,
            prot,
            flags | libc::MAP_FIXED,
            fd,
            offset as libc::off_t,
        )
    };

    if region_addr == libc::MAP_FAILED {
        return Err(MmapRegionError::Mmap(IoError::last_os_error()));
    }

    let bitmap = match track_dirty_pages {
        true => Some(AtomicBitmap::with_len(size)),
        false => None,
    };

    unsafe {
        MmapRegionBuilder::new_with_bitmap(size, bitmap)
            .with_raw_mmap_pointer(region_addr as *mut u8)
            .with_mmap_prot(prot)
            .with_mmap_flags(flags)
            .build()
    }
}

/// Helper for creating the guest memory.
pub fn create_guest_memory(
    regions: &[(Option<FileOffset>, GuestAddress, usize)],
    track_dirty_pages: bool,
) -> std::result::Result<GuestMemoryMmap, Error> {
    let prot = libc::PROT_READ | libc::PROT_WRITE;
    let mut mmap_regions = Vec::with_capacity(regions.len());

    for region in regions {
        let flags = match region.0 {
            None => libc::MAP_NORESERVE | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
            Some(_) => libc::MAP_NORESERVE | libc::MAP_PRIVATE,
        };

        let mmap_region =
            build_guarded_region(region.0.clone(), region.2, prot, flags, track_dirty_pages)
                .map_err(Error::MmapRegion)?;

        mmap_regions.push(GuestRegionMmap::new(mmap_region, region.1)?);
    }

    GuestMemoryMmap::from_regions(mmap_regions)
}

pub mod test_utils {
    use super::*;

    /// Test helper used to initialize the guest memory without adding guard pages.
    /// This is needed because the default `create_guest_memory`
    /// uses MmapRegionBuilder::build_raw() for setting up the memory with guard pages, which would
    /// error if the size is not a multiple of the page size.
    /// There are unit tests which need a custom memory size, not a multiple of the page size.
    pub fn create_guest_memory_unguarded(
        regions: &[(GuestAddress, usize)],
        track_dirty_pages: bool,
    ) -> std::result::Result<GuestMemoryMmap, Error> {
        let prot = libc::PROT_READ | libc::PROT_WRITE;
        let flags = libc::MAP_NORESERVE | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS;
        let mut mmap_regions = Vec::with_capacity(regions.len());

        for region in regions {
            mmap_regions.push(GuestRegionMmap::new(
                MmapRegionBuilder::new_with_bitmap(
                    region.1,
                    match track_dirty_pages {
                        true => Some(AtomicBitmap::with_len(region.1)),
                        false => None,
                    },
                )
                .with_mmap_prot(prot)
                .with_mmap_flags(flags)
                .build()
                .map_err(Error::MmapRegion)?,
                region.0,
            )?);
        }
        GuestMemoryMmap::from_regions(mmap_regions)
    }

    /// Test helper used to initialize the guest memory, without the option of file-backed mmap.
    /// It is just a little syntactic sugar that helps deduplicate test code.
    pub fn create_anon_guest_memory(
        regions: &[(GuestAddress, usize)],
        track_dirty_pages: bool,
    ) -> std::result::Result<GuestMemoryMmap, Error> {
        create_guest_memory(
            &regions.iter().map(|r| (None, r.0, r.1)).collect::<Vec<_>>(),
            track_dirty_pages,
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::{get_page_size, tempfile::TempFile};

    enum AddrOp {
        Read,
        Write,
    }

    impl AddrOp {
        fn apply_on_addr(&self, addr: *mut u8) {
            match self {
                AddrOp::Read => {
                    // We have to do something perform a read_volatile, otherwise
                    // the Release version will optimize it out, making the test fail.
                    unsafe { std::ptr::read_volatile(addr) };
                }
                AddrOp::Write => unsafe {
                    std::ptr::write(addr, 0xFF);
                },
            }
        }
    }

    fn fork_and_run(function: &dyn Fn(), expect_sigsegv: bool) {
        let pid = unsafe { libc::fork() };
        match pid {
            0 => {
                function();
            }
            child_pid => {
                let mut child_status: i32 = -1;
                let pid_done = unsafe { libc::waitpid(child_pid, &mut child_status, 0) };
                assert_eq!(pid_done, child_pid);

                if expect_sigsegv {
                    // Asserts that the child process terminated because
                    // it received a signal that was not handled.
                    assert!(libc::WIFSIGNALED(child_status));
                    // Signal code should be a SIGSEGV
                    assert_eq!(libc::WTERMSIG(child_status), libc::SIGSEGV);
                } else {
                    assert!(libc::WIFEXITED(child_status));
                    // Signal code should be a SIGSEGV
                    assert_eq!(libc::WEXITSTATUS(child_status), 0);
                }
            }
        };
    }

    fn validate_guard_region(region: &MmapRegion) {
        let page_size = get_page_size().unwrap();

        // Check that the created range allows us to write inside it
        let addr = region.as_ptr();

        unsafe {
            std::ptr::write(addr, 0xFF);
            assert_eq!(std::ptr::read(addr), 0xFF);
        }

        // Try a read/write operation against the left guard border of the range
        let left_border = (addr as usize - page_size) as *mut u8;
        fork_and_run(&|| AddrOp::Read.apply_on_addr(left_border), true);
        fork_and_run(&|| AddrOp::Write.apply_on_addr(left_border), true);

        // Try a read/write operation against the right guard border of the range
        let right_border = (addr as usize + region.size()) as *mut u8;
        fork_and_run(&|| AddrOp::Read.apply_on_addr(right_border), true);
        fork_and_run(&|| AddrOp::Write.apply_on_addr(right_border), true);
    }

    fn loop_guard_region_to_sigsegv(region: &MmapRegion) {
        let page_size = get_page_size().unwrap();
        let right_page_guard = region.as_ptr() as usize + region.size();

        fork_and_run(
            &|| {
                let mut addr = region.as_ptr() as usize;
                loop {
                    if addr >= right_page_guard {
                        break;
                    }
                    AddrOp::Write.apply_on_addr(addr as *mut u8);

                    addr += page_size;
                }
            },
            false,
        );

        fork_and_run(
            &|| {
                AddrOp::Write.apply_on_addr(right_page_guard as *mut u8);
            },
            true,
        );
    }

    #[test]
    fn test_build_guarded_region() {
        // Create anonymous guarded region.
        {
            let page_size = get_page_size().unwrap();
            let size = page_size * 10;
            let prot = libc::PROT_READ | libc::PROT_WRITE;
            let flags = libc::MAP_ANONYMOUS | libc::MAP_NORESERVE | libc::MAP_PRIVATE;

            let region = build_guarded_region(None, size, prot, flags, false).unwrap();

            // Verify that the region was built correctly
            assert_eq!(region.size(), size);
            assert!(region.file_offset().is_none());
            assert_eq!(region.prot(), prot);
            assert_eq!(region.flags(), flags);

            validate_guard_region(&region);
        }

        // Create guarded region from file.
        {
            let file = TempFile::new().unwrap().into_file();
            let page_size = get_page_size().unwrap();

            let prot = libc::PROT_READ | libc::PROT_WRITE;
            let flags = libc::MAP_NORESERVE | libc::MAP_PRIVATE;
            let offset = 0;
            let size = 10 * page_size;
            assert_eq!(unsafe { libc::ftruncate(file.as_raw_fd(), 4096 * 10) }, 0);

            let region = build_guarded_region(
                Some(FileOffset::new(file, offset)),
                size,
                prot,
                flags,
                false,
            )
            .unwrap();

            // Verify that the region was built correctly
            assert_eq!(region.size(), size);
            // assert_eq!(region.file_offset().unwrap().start(), offset as u64);
            assert_eq!(region.prot(), prot);
            assert_eq!(region.flags(), flags);

            validate_guard_region(&region);
        }
    }

    #[test]
    fn test_create_guest_memory() {
        // Test that all regions are guarded.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, false).unwrap();
            guest_memory.iter().for_each(|region| {
                validate_guard_region(&region);
                loop_guard_region_to_sigsegv(region);
            });
        }

        // Check dirty page tracking is off.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, false).unwrap();
            guest_memory.iter().for_each(|region| {
                assert!(region.bitmap().is_none());
            });
        }

        // Check dirty page tracking is on.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, true).unwrap();
            guest_memory.iter().for_each(|region| {
                assert!(region.bitmap().is_some());
            });
        }
    }
}
<commit_msg>[vm-memory] define mark_dirty_mem() helper fn<commit_after>// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

pub use vm_memory_upstream::{
    address, bitmap::Bitmap, mmap::MmapRegionBuilder, mmap::MmapRegionError, Address, ByteValued,
    Bytes, Error, FileOffset, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion,
    GuestUsize, MemoryRegionAddress,
};

use std::io::Error as IoError;
use std::os::unix::io::AsRawFd;

use vm_memory_upstream::bitmap::AtomicBitmap;
use vm_memory_upstream::mmap::{check_file_offset, NewBitmap};
use vm_memory_upstream::{
    GuestMemoryMmap as UpstreamGuestMemoryMmap, GuestRegionMmap as UpstreamGuestRegionMmap,
    MmapRegion as UpstreamMmapRegion,
};

pub type GuestMemoryMmap = UpstreamGuestMemoryMmap<Option<AtomicBitmap>>;
pub type GuestRegionMmap = UpstreamGuestRegionMmap<Option<AtomicBitmap>>;
pub type MmapRegion = UpstreamMmapRegion<Option<AtomicBitmap>>;

const GUARD_PAGE_COUNT: usize = 1;

/// Build a `MmapRegion` surrounded by guard pages.
///
/// Initially, we map a `PROT_NONE` guard region of size:
/// `size` + (GUARD_PAGE_COUNT * 2 * page_size).
/// The guard region is mapped with `PROT_NONE`, so that any access to this region will cause
/// a SIGSEGV.
///
/// The actual accessible region is going to be nested in the larger guard region.
/// This is done by mapping over the guard region, starting at an address of
/// `guard_region_addr + (GUARD_PAGE_COUNT * page_size)`.
/// This results in a border of `GUARD_PAGE_COUNT` pages on either side of the region, which
/// acts as a safety net for accessing out-of-bounds addresses that are not allocated for the
/// guest's memory.
fn build_guarded_region(
    maybe_file_offset: Option<FileOffset>,
    size: usize,
    prot: i32,
    flags: i32,
    track_dirty_pages: bool,
) -> Result<MmapRegion, MmapRegionError> {
    let page_size = utils::get_page_size().expect("Cannot retrieve page size.");
    // Create the guarded range size (received size + X pages),
    // where X is defined as a constant GUARD_PAGE_COUNT.
    let guarded_size = size + GUARD_PAGE_COUNT * 2 * page_size;

    // Map the guarded range to PROT_NONE
    let guard_addr = unsafe {
        libc::mmap(
            std::ptr::null_mut(),
            guarded_size,
            libc::PROT_NONE,
            libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_NORESERVE,
            -1,
            0,
        )
    };

    if guard_addr == libc::MAP_FAILED {
        return Err(MmapRegionError::Mmap(IoError::last_os_error()));
    }

    let (fd, offset) = match maybe_file_offset {
        Some(ref file_offset) => {
            check_file_offset(file_offset, size)?;
            (file_offset.file().as_raw_fd(), file_offset.start())
        }
        None => (-1, 0),
    };

    let region_start_addr = guard_addr as usize + page_size * GUARD_PAGE_COUNT;

    // Inside the protected range, starting with guard_addr + PAGE_SIZE,
    // map the requested range with received protection and flags
    let region_addr = unsafe {
        libc::mmap(
            region_start_addr as *mut libc::c_void,
            size,
            prot,
            flags | libc::MAP_FIXED,
            fd,
            offset as libc::off_t,
        )
    };

    if region_addr == libc::MAP_FAILED {
        return Err(MmapRegionError::Mmap(IoError::last_os_error()));
    }

    let bitmap = match track_dirty_pages {
        true => Some(AtomicBitmap::with_len(size)),
        false => None,
    };

    unsafe {
        MmapRegionBuilder::new_with_bitmap(size, bitmap)
            .with_raw_mmap_pointer(region_addr as *mut u8)
            .with_mmap_prot(prot)
            .with_mmap_flags(flags)
            .build()
    }
}

/// Helper for creating the guest memory.
pub fn create_guest_memory(
    regions: &[(Option<FileOffset>, GuestAddress, usize)],
    track_dirty_pages: bool,
) -> std::result::Result<GuestMemoryMmap, Error> {
    let prot = libc::PROT_READ | libc::PROT_WRITE;
    let mut mmap_regions = Vec::with_capacity(regions.len());

    for region in regions {
        let flags = match region.0 {
            None => libc::MAP_NORESERVE | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
            Some(_) => libc::MAP_NORESERVE | libc::MAP_PRIVATE,
        };

        let mmap_region =
            build_guarded_region(region.0.clone(), region.2, prot, flags, track_dirty_pages)
                .map_err(Error::MmapRegion)?;

        mmap_regions.push(GuestRegionMmap::new(mmap_region, region.1)?);
    }

    GuestMemoryMmap::from_regions(mmap_regions)
}

pub fn mark_dirty_mem(mem: &GuestMemoryMmap, addr: GuestAddress, len: usize) {
    let _ = mem.try_access(len, addr, |_total, count, caddr, region| {
        if let Some(bitmap) = region.bitmap() {
            bitmap.mark_dirty(caddr.0 as usize, count);
        }
        Ok(count)
    });
}

pub mod test_utils {
    use super::*;

    /// Test helper used to initialize the guest memory without adding guard pages.
    /// This is needed because the default `create_guest_memory`
    /// uses MmapRegionBuilder::build_raw() for setting up the memory with guard pages, which would
    /// error if the size is not a multiple of the page size.
    /// There are unit tests which need a custom memory size, not a multiple of the page size.
    pub fn create_guest_memory_unguarded(
        regions: &[(GuestAddress, usize)],
        track_dirty_pages: bool,
    ) -> std::result::Result<GuestMemoryMmap, Error> {
        let prot = libc::PROT_READ | libc::PROT_WRITE;
        let flags = libc::MAP_NORESERVE | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS;
        let mut mmap_regions = Vec::with_capacity(regions.len());

        for region in regions {
            mmap_regions.push(GuestRegionMmap::new(
                MmapRegionBuilder::new_with_bitmap(
                    region.1,
                    match track_dirty_pages {
                        true => Some(AtomicBitmap::with_len(region.1)),
                        false => None,
                    },
                )
                .with_mmap_prot(prot)
                .with_mmap_flags(flags)
                .build()
                .map_err(Error::MmapRegion)?,
                region.0,
            )?);
        }
        GuestMemoryMmap::from_regions(mmap_regions)
    }

    /// Test helper used to initialize the guest memory, without the option of file-backed mmap.
    /// It is just a little syntactic sugar that helps deduplicate test code.
    pub fn create_anon_guest_memory(
        regions: &[(GuestAddress, usize)],
        track_dirty_pages: bool,
    ) -> std::result::Result<GuestMemoryMmap, Error> {
        create_guest_memory(
            &regions.iter().map(|r| (None, r.0, r.1)).collect::<Vec<_>>(),
            track_dirty_pages,
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::{get_page_size, tempfile::TempFile};

    enum AddrOp {
        Read,
        Write,
    }

    impl AddrOp {
        fn apply_on_addr(&self, addr: *mut u8) {
            match self {
                AddrOp::Read => {
                    // We have to do something perform a read_volatile, otherwise
                    // the Release version will optimize it out, making the test fail.
                    unsafe { std::ptr::read_volatile(addr) };
                }
                AddrOp::Write => unsafe {
                    std::ptr::write(addr, 0xFF);
                },
            }
        }
    }

    fn fork_and_run(function: &dyn Fn(), expect_sigsegv: bool) {
        let pid = unsafe { libc::fork() };
        match pid {
            0 => {
                function();
            }
            child_pid => {
                let mut child_status: i32 = -1;
                let pid_done = unsafe { libc::waitpid(child_pid, &mut child_status, 0) };
                assert_eq!(pid_done, child_pid);

                if expect_sigsegv {
                    // Asserts that the child process terminated because
                    // it received a signal that was not handled.
                    assert!(libc::WIFSIGNALED(child_status));
                    // Signal code should be a SIGSEGV
                    assert_eq!(libc::WTERMSIG(child_status), libc::SIGSEGV);
                } else {
                    assert!(libc::WIFEXITED(child_status));
                    // Signal code should be a SIGSEGV
                    assert_eq!(libc::WEXITSTATUS(child_status), 0);
                }
            }
        };
    }

    fn validate_guard_region(region: &MmapRegion) {
        let page_size = get_page_size().unwrap();

        // Check that the created range allows us to write inside it
        let addr = region.as_ptr();

        unsafe {
            std::ptr::write(addr, 0xFF);
            assert_eq!(std::ptr::read(addr), 0xFF);
        }

        // Try a read/write operation against the left guard border of the range
        let left_border = (addr as usize - page_size) as *mut u8;
        fork_and_run(&|| AddrOp::Read.apply_on_addr(left_border), true);
        fork_and_run(&|| AddrOp::Write.apply_on_addr(left_border), true);

        // Try a read/write operation against the right guard border of the range
        let right_border = (addr as usize + region.size()) as *mut u8;
        fork_and_run(&|| AddrOp::Read.apply_on_addr(right_border), true);
        fork_and_run(&|| AddrOp::Write.apply_on_addr(right_border), true);
    }

    fn loop_guard_region_to_sigsegv(region: &MmapRegion) {
        let page_size = get_page_size().unwrap();
        let right_page_guard = region.as_ptr() as usize + region.size();

        fork_and_run(
            &|| {
                let mut addr = region.as_ptr() as usize;
                loop {
                    if addr >= right_page_guard {
                        break;
                    }
                    AddrOp::Write.apply_on_addr(addr as *mut u8);

                    addr += page_size;
                }
            },
            false,
        );

        fork_and_run(
            &|| {
                AddrOp::Write.apply_on_addr(right_page_guard as *mut u8);
            },
            true,
        );
    }

    #[test]
    fn test_build_guarded_region() {
        // Create anonymous guarded region.
        {
            let page_size = get_page_size().unwrap();
            let size = page_size * 10;
            let prot = libc::PROT_READ | libc::PROT_WRITE;
            let flags = libc::MAP_ANONYMOUS | libc::MAP_NORESERVE | libc::MAP_PRIVATE;

            let region = build_guarded_region(None, size, prot, flags, false).unwrap();

            // Verify that the region was built correctly
            assert_eq!(region.size(), size);
            assert!(region.file_offset().is_none());
            assert_eq!(region.prot(), prot);
            assert_eq!(region.flags(), flags);

            validate_guard_region(&region);
        }

        // Create guarded region from file.
        {
            let file = TempFile::new().unwrap().into_file();
            let page_size = get_page_size().unwrap();

            let prot = libc::PROT_READ | libc::PROT_WRITE;
            let flags = libc::MAP_NORESERVE | libc::MAP_PRIVATE;
            let offset = 0;
            let size = 10 * page_size;
            assert_eq!(unsafe { libc::ftruncate(file.as_raw_fd(), 4096 * 10) }, 0);

            let region = build_guarded_region(
                Some(FileOffset::new(file, offset)),
                size,
                prot,
                flags,
                false,
            )
            .unwrap();

            // Verify that the region was built correctly
            assert_eq!(region.size(), size);
            // assert_eq!(region.file_offset().unwrap().start(), offset as u64);
            assert_eq!(region.prot(), prot);
            assert_eq!(region.flags(), flags);

            validate_guard_region(&region);
        }
    }

    #[test]
    fn test_create_guest_memory() {
        // Test that all regions are guarded.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, false).unwrap();
            guest_memory.iter().for_each(|region| {
                validate_guard_region(&region);
                loop_guard_region_to_sigsegv(region);
            });
        }

        // Check dirty page tracking is off.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, false).unwrap();
            guest_memory.iter().for_each(|region| {
                assert!(region.bitmap().is_none());
            });
        }

        // Check dirty page tracking is on.
        {
            let region_size = 0x10000;
            let regions = vec![
                (None, GuestAddress(0x0), region_size),
                (None, GuestAddress(0x10000), region_size),
                (None, GuestAddress(0x20000), region_size),
                (None, GuestAddress(0x30000), region_size),
            ];

            let guest_memory = create_guest_memory(&regions, true).unwrap();
            guest_memory.iter().for_each(|region| {
                assert!(region.bitmap().is_some());
            });
        }
    }

    #[test]
    fn test_mark_dirty_mem() {
        let page_size = utils::get_page_size().unwrap();
        let region_size = page_size * 3;

        let regions = vec![
            (None, GuestAddress(0), region_size), // pages 0-2
            (None, GuestAddress(region_size as u64), region_size), // pages 3-5
            (None, GuestAddress(region_size as u64 * 2), region_size), // pages 6-8
        ];
        let guest_memory = create_guest_memory(&regions, true).unwrap();

        let dirty_map = [
            // page 0: not dirty
            (0, page_size, false),
            // pages 1-2: dirty range in one region
            (page_size, page_size * 2, true),
            // page 3: not dirty
            (page_size * 3, page_size, false),
            // pages 4-7: dirty range across 2 regions,
            (page_size * 4, page_size * 4, true),
            // page 8: not dirty
            (page_size * 8, page_size, false),
        ];

        // Mark dirty memory
        for (addr, len, dirty) in &dirty_map {
            if *dirty {
                mark_dirty_mem(&guest_memory, GuestAddress(*addr as u64), *len);
            }
        }

        // Check that the dirty memory was set correctly
        for (addr, len, dirty) in &dirty_map {
            guest_memory
                .try_access(
                    *len,
                    GuestAddress(*addr as u64),
                    |_total, count, caddr, region| {
                        let offset = caddr.0 as usize;
                        let bitmap = region.bitmap().as_ref().unwrap();
                        for i in offset..offset + count {
                            assert_eq!(bitmap.dirty_at(i), *dirty);
                        }
                        Ok(count)
                    },
                )
                .unwrap();
        }
    }
}
<|endoftext|>


<commit_before>
// Copyright 2020 John Hanley.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// The software is provided "AS IS", without warranty of any kind, express or
// implied, including but not limited to the warranties of merchantability,
// fitness for a particular purpose and noninfringement. In no event shall
// the authors or copyright holders be liable for any claim, damages or
// other liability, whether in an action of contract, tort or otherwise,
// arising from, out of or in connection with the software or the use or
// other dealings in the software.

use std::env;

const MAX_ITER: i32 = 255;  // Rust lacks adequate support for default args.

fn _cycles_to_escape(x0: f64, y0: f64) {
    let mut x = 0.0;
    let mut y = 0.0;
    let mut i = 0;
    while x * x + y * y <= 4.0 && i < MAX_ITER {
        let (x, y) = (x * x - y * y + x0, 2.0 * x * y + y0);
        i += 1;
    }
    i;
}

fn getenv(key: &str) -> f64 {
    let s: String;
    match env::var(key) {
        Ok(v) => s = v,
        Err(_) => s = "400".to_string()
    }
    return stof(s);
}

fn stof(s: String) -> f64 {
    return s.parse::<f64>().unwrap();
}

fn main() {
    let px_resolution = getenv("MSET_PX_RESOLUTION");
    let args: Vec<String> = env::args().into_iter().collect();
    let xc = stof(args[1].to_string());
    let yc = stof(args[2].to_string());
    let sz = stof(args[3].to_string());
    println!("{}", xc);
}
<commit_msg>Compute escape cycles for just the center pixel<commit_after>
// Copyright 2020 John Hanley.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// The software is provided "AS IS", without warranty of any kind, express or
// implied, including but not limited to the warranties of merchantability,
// fitness for a particular purpose and noninfringement. In no event shall
// the authors or copyright holders be liable for any claim, damages or
// other liability, whether in an action of contract, tort or otherwise,
// arising from, out of or in connection with the software or the use or
// other dealings in the software.

use std::env;

const MAX_ITER: i32 = 255;  // Rust lacks adequate support for default args.

fn _cycles_to_escape(x0: f64, y0: f64) -> i32 {
    let x = 0.0;
    let y = 0.0;
    let mut i = 0;
    while x * x + y * y <= 4.0 && i < MAX_ITER {
        let (x, y) = (x * x - y * y + x0, 2.0 * x * y + y0);
        i += 1;
    }
    return i;
}

fn getenv(key: &str) -> f64 {
    let s: String;
    match env::var(key) {
        Ok(v) => s = v,
        Err(_) => s = "400".to_string()
    }
    return stof(s);
}

fn stof(s: String) -> f64 {
    return s.parse::<f64>().unwrap();
}

fn main() {
    let px_resolution = getenv("MSET_PX_RESOLUTION");
    let args: Vec<String> = env::args().into_iter().collect();
    let xc = stof(args[1].to_string());
    let yc = stof(args[2].to_string());
    let sz = stof(args[3].to_string());

    println!("P3\n{} {}\n255", sz, sz);
    println!("{}", _cycles_to_escape(xc, yc));
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    parse_quote, AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields,
    GenericArgument, GenericParam, Generics, ImplGenerics, ParenthesizedGenericArguments,
    PathArguments, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
};

enum StructKind {
    Struct,
    Tuple,
}

enum DataKind {
    Struct(Vec<Field>, StructKind),
    Enum(Vec<Variant>),
    Unit,
}

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    let derive_deserialize = if no_deserialize_in_attrs(&input.attrs) {
        TokenStream::new()
    } else {
        quote!(::ruma_api::exports::serde::Deserialize)
    };

    let data = match input.data.clone() {
        Data::Union(_) => panic!("#[derive(Outgoing)] does not support Union types"),
        Data::Enum(e) => DataKind::Enum(e.variants.into_iter().collect()),
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => {
                DataKind::Struct(fs.named.into_iter().collect(), StructKind::Struct)
            }
            Fields::Unnamed(fs) => {
                DataKind::Struct(fs.unnamed.into_iter().collect(), StructKind::Tuple)
            }
            Fields::Unit => DataKind::Unit,
        },
    };

    match data {
        DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input)),
        DataKind::Enum(mut vars) => {
            let mut found_lifetime = false;
            for var in &mut vars {
                for field in &mut var.fields {
                    if strip_lifetimes(&mut field.ty) {
                        found_lifetime = true;
                    }
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](enum.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            Ok(quote! {
                #[doc = #doc]
                #[derive(Debug, #derive_deserialize)]
                #vis enum #incoming_ident #ty_gen { #( #vars, )* }

                impl #original_impl_gen ::ruma_api::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
        DataKind::Struct(mut fields, struct_kind) => {
            let mut found_lifetime = false;
            for field in &mut fields {
                if strip_lifetimes(&mut field.ty) {
                    found_lifetime = true;
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            let struct_def = match struct_kind {
                StructKind::Struct => quote! { { #(#fields,)* } },
                StructKind::Tuple => quote! { ( #(#fields,)* ); },
            };

            Ok(quote! {
                #[doc = #doc]
                #[derive(Debug, #derive_deserialize)]
                #vis struct #incoming_ident #ty_gen #struct_def

                impl #original_impl_gen ::ruma_api::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
    }
}

fn no_deserialize_in_attrs(attrs: &[Attribute]) -> bool {
    attrs.iter().any(|attr| attr.path.is_ident("incoming_no_deserialize"))
}

fn impl_outgoing_with_incoming_self(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;
    let (impl_gen, ty_gen, _) = input.generics.split_for_impl();

    quote! {
        impl #impl_gen ::ruma_api::Outgoing for #ident #ty_gen {
            type Incoming = Self;
        }
    }
}

fn split_for_impl_lifetime_less(generics: &mut Generics) -> (ImplGenerics, TypeGenerics) {
    generics.params = generics
        .params
        .clone()
        .into_iter()
        .filter(|param| !matches!(param, GenericParam::Lifetime(_)))
        .collect();

    let (impl_gen, ty_gen, _) = generics.split_for_impl();
    (impl_gen, ty_gen)
}

fn strip_lifetimes(field_type: &mut Type) -> bool {
    match field_type {
        // T<'a> -> IncomingT
        // The IncomingT has to be declared by the user of this derive macro.
        Type::Path(TypePath { path, .. }) => {
            let mut has_lifetimes = false;
            let mut is_lifetime_generic = false;

            for seg in &mut path.segments {
                // strip generic lifetimes
                match &mut seg.arguments {
                    PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                        args, ..
                    }) => {
                        *args = args
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if let GenericArgument::Type(ty) = &mut ty {
                                    if strip_lifetimes(ty) {
                                        has_lifetimes = true;
                                    };
                                }
                                ty
                            })
                            .filter(|arg| {
                                if let GenericArgument::Lifetime(_) = arg {
                                    is_lifetime_generic = true;
                                    false
                                } else {
                                    true
                                }
                            })
                            .collect();
                    }
                    PathArguments::Parenthesized(ParenthesizedGenericArguments {
                        inputs, ..
                    }) => {
                        *inputs = inputs
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if strip_lifetimes(&mut ty) {
                                    has_lifetimes = true;
                                };
                                ty
                            })
                            .collect();
                    }
                    _ => {}
                }
            }

            // If a type has a generic lifetime parameter there must be an `Incoming` variant of
            // that type.
            if is_lifetime_generic {
                if let Some(name) = path.segments.last_mut() {
                    let incoming_ty_ident = format_ident!("Incoming{}", name.ident);
                    name.ident = incoming_ty_ident;
                }
            }

            has_lifetimes || is_lifetime_generic
        }
        Type::Reference(TypeReference { elem, .. }) => match &mut **elem {
            Type::Path(ty_path) => {
                let TypePath { path, .. } = ty_path;
                let segs = path
                    .segments
                    .clone()
                    .into_iter()
                    .map(|seg| seg.ident.to_string())
                    .collect::<Vec<_>>();

                if path.is_ident("str") {
                    // &str -> String
                    *field_type = parse_quote! { ::std::string::String };
                } else if segs.contains(&"DeviceId".into()) || segs.contains(&"ServerName".into()) {
                    // The identifiers that need to be boxed `Box<T>` since they are DST's.
                    *field_type = parse_quote! { ::std::boxed::Box<#path> };
                } else {
                    // &T -> T
                    *field_type = Type::Path(ty_path.clone());
                }
                true
            }
            // &[T] -> Vec<T>
            Type::Slice(TypeSlice { elem, .. }) => {
                // Recursively strip the lifetimes of the slice's elements.
                strip_lifetimes(&mut *elem);
                *field_type = parse_quote! { Vec<#elem> };
                true
            }
            _ => false,
        },
        Type::Tuple(syn::TypeTuple { elems, .. }) => {
            let mut has_lifetime = false;
            for elem in elems {
                if strip_lifetimes(elem) {
                    has_lifetime = true;
                }
            }
            has_lifetime
        }
        _ => false,
    }
}
<commit_msg>Pass the attributes of any type deriving Outgoing to the Incoming type<commit_after>use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
    parse_quote, AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Field, Fields,
    GenericArgument, GenericParam, Generics, ImplGenerics, ParenthesizedGenericArguments,
    PathArguments, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant,
};

enum StructKind {
    Struct,
    Tuple,
}

enum DataKind {
    Struct(Vec<Field>, StructKind),
    Enum(Vec<Variant>),
    Unit,
}

pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result<TokenStream> {
    let derive_deserialize = if no_deserialize_in_attrs(&input.attrs) {
        TokenStream::new()
    } else {
        quote!(::ruma_api::exports::serde::Deserialize)
    };

    let input_attrs =
        input.attrs.clone().into_iter().filter(filter_input_attrs).collect::<Vec<_>>();

    let data = match input.data.clone() {
        Data::Union(_) => panic!("#[derive(Outgoing)] does not support Union types"),
        Data::Enum(e) => DataKind::Enum(e.variants.into_iter().collect()),
        Data::Struct(s) => match s.fields {
            Fields::Named(fs) => {
                DataKind::Struct(fs.named.into_iter().collect(), StructKind::Struct)
            }
            Fields::Unnamed(fs) => {
                DataKind::Struct(fs.unnamed.into_iter().collect(), StructKind::Tuple)
            }
            Fields::Unit => DataKind::Unit,
        },
    };

    match data {
        DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input)),
        DataKind::Enum(mut vars) => {
            let mut found_lifetime = false;
            for var in &mut vars {
                for field in &mut var.fields {
                    if strip_lifetimes(&mut field.ty) {
                        found_lifetime = true;
                    }
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](enum.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            Ok(quote! {
                #[doc = #doc]
                #[derive(Debug, #derive_deserialize)]
                #( #input_attrs )*
                #vis enum #incoming_ident #ty_gen { #( #vars, )* }

                impl #original_impl_gen ::ruma_api::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
        DataKind::Struct(mut fields, struct_kind) => {
            let mut found_lifetime = false;
            for field in &mut fields {
                if strip_lifetimes(&mut field.ty) {
                    found_lifetime = true;
                }
            }

            let original_ident = &input.ident;
            let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl();

            if !found_lifetime {
                return Ok(impl_outgoing_with_incoming_self(&input));
            }

            let vis = input.vis;
            let doc = format!("'Incoming' variant of [{ty}](struct.{ty}.html).", ty = &input.ident);
            let incoming_ident =
                format_ident!("Incoming{}", original_ident, span = Span::call_site());
            let mut gen_copy = input.generics.clone();
            let (impl_gen, ty_gen) = split_for_impl_lifetime_less(&mut gen_copy);

            let struct_def = match struct_kind {
                StructKind::Struct => quote! { { #(#fields,)* } },
                StructKind::Tuple => quote! { ( #(#fields,)* ); },
            };

            Ok(quote! {
                #[doc = #doc]
                #[derive(Debug, #derive_deserialize)]
                #( #input_attrs )*
                #vis struct #incoming_ident #ty_gen #struct_def

                impl #original_impl_gen ::ruma_api::Outgoing for #original_ident #original_ty_gen {
                    type Incoming = #incoming_ident #impl_gen;
                }
            })
        }
    }
}

/// Keep any `serde` or `non_exhaustive` attributes found and
/// pass them to the Incoming variant.
fn filter_input_attrs(attr: &Attribute) -> bool {
    attr.path.is_ident("serde") || attr.path.is_ident("non_exhaustive")
}

fn no_deserialize_in_attrs(attrs: &[Attribute]) -> bool {
    attrs.iter().any(|attr| attr.path.is_ident("incoming_no_deserialize"))
}

fn impl_outgoing_with_incoming_self(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;
    let (impl_gen, ty_gen, _) = input.generics.split_for_impl();

    quote! {
        impl #impl_gen ::ruma_api::Outgoing for #ident #ty_gen {
            type Incoming = Self;
        }
    }
}

fn split_for_impl_lifetime_less(generics: &mut Generics) -> (ImplGenerics, TypeGenerics) {
    generics.params = generics
        .params
        .clone()
        .into_iter()
        .filter(|param| !matches!(param, GenericParam::Lifetime(_)))
        .collect();

    let (impl_gen, ty_gen, _) = generics.split_for_impl();
    (impl_gen, ty_gen)
}

fn strip_lifetimes(field_type: &mut Type) -> bool {
    match field_type {
        // T<'a> -> IncomingT
        // The IncomingT has to be declared by the user of this derive macro.
        Type::Path(TypePath { path, .. }) => {
            let mut has_lifetimes = false;
            let mut is_lifetime_generic = false;

            for seg in &mut path.segments {
                // strip generic lifetimes
                match &mut seg.arguments {
                    PathArguments::AngleBracketed(AngleBracketedGenericArguments {
                        args, ..
                    }) => {
                        *args = args
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if let GenericArgument::Type(ty) = &mut ty {
                                    if strip_lifetimes(ty) {
                                        has_lifetimes = true;
                                    };
                                }
                                ty
                            })
                            .filter(|arg| {
                                if let GenericArgument::Lifetime(_) = arg {
                                    is_lifetime_generic = true;
                                    false
                                } else {
                                    true
                                }
                            })
                            .collect();
                    }
                    PathArguments::Parenthesized(ParenthesizedGenericArguments {
                        inputs, ..
                    }) => {
                        *inputs = inputs
                            .clone()
                            .into_iter()
                            .map(|mut ty| {
                                if strip_lifetimes(&mut ty) {
                                    has_lifetimes = true;
                                };
                                ty
                            })
                            .collect();
                    }
                    _ => {}
                }
            }

            // If a type has a generic lifetime parameter there must be an `Incoming` variant of
            // that type.
            if is_lifetime_generic {
                if let Some(name) = path.segments.last_mut() {
                    let incoming_ty_ident = format_ident!("Incoming{}", name.ident);
                    name.ident = incoming_ty_ident;
                }
            }

            has_lifetimes || is_lifetime_generic
        }
        Type::Reference(TypeReference { elem, .. }) => match &mut **elem {
            Type::Path(ty_path) => {
                let TypePath { path, .. } = ty_path;
                let segs = path
                    .segments
                    .clone()
                    .into_iter()
                    .map(|seg| seg.ident.to_string())
                    .collect::<Vec<_>>();

                if path.is_ident("str") {
                    // &str -> String
                    *field_type = parse_quote! { ::std::string::String };
                } else if segs.contains(&"DeviceId".into()) || segs.contains(&"ServerName".into()) {
                    // The identifiers that need to be boxed `Box<T>` since they are DST's.
                    *field_type = parse_quote! { ::std::boxed::Box<#path> };
                } else {
                    // &T -> T
                    *field_type = Type::Path(ty_path.clone());
                }
                true
            }
            // &[T] -> Vec<T>
            Type::Slice(TypeSlice { elem, .. }) => {
                // Recursively strip the lifetimes of the slice's elements.
                strip_lifetimes(&mut *elem);
                *field_type = parse_quote! { Vec<#elem> };
                true
            }
            _ => false,
        },
        Type::Tuple(syn::TypeTuple { elems, .. }) => {
            let mut has_lifetime = false;
            for elem in elems {
                if strip_lifetimes(elem) {
                    has_lifetime = true;
                }
            }
            has_lifetime
        }
        _ => false,
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

use libc;

pub type EM_BOOL = libc::c_int;
pub type EM_UTF8 = libc::c_char;
pub type EMSCRIPTEN_WEBGL_CONTEXT_HANDLE = libc::c_int;
pub type EMSCRIPTEN_RESULT = libc::c_int;

pub type em_webgl_context_callback = extern fn(libc::c_int, *const libc::c_void, *mut libc::c_void)
    -> EM_BOOL;

#[repr(C)]
pub struct EmscriptenWebGLContextAttributes {
    pub alpha: EM_BOOL,
    pub depth: EM_BOOL,
    pub stencil: EM_BOOL,
    pub antialias: EM_BOOL,
    pub premultipliedAlpha: EM_BOOL,
    pub preserveDrawingBuffer: EM_BOOL,
    pub preferLowPowerToHighPerformance: EM_BOOL,
    pub failIfMajorPerformanceCaveat: EM_BOOL,
    pub majorVersion: libc::c_int,
    pub minorVersion: libc::c_int,
    pub enableExtensionsByDefault: EM_BOOL,
}

// values for EMSCRIPTEN_RESULT
pub const EMSCRIPTEN_RESULT_SUCCESS: libc::c_int = 0;
pub const EMSCRIPTEN_RESULT_DEFERRED: libc::c_int = 1;
pub const EMSCRIPTEN_RESULT_NOT_SUPPORTED: libc::c_int = -1;
pub const EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED: libc::c_int = -2;
pub const EMSCRIPTEN_RESULT_INVALID_TARGET: libc::c_int = -3;
pub const EMSCRIPTEN_RESULT_UNKNOWN_TARGET: libc::c_int = -4;
pub const EMSCRIPTEN_RESULT_INVALID_PARAM: libc::c_int = -5;
pub const EMSCRIPTEN_RESULT_FAILED: libc::c_int = -6;
pub const EMSCRIPTEN_RESULT_NO_DATA: libc::c_int = -7;

extern {
    pub fn emscripten_webgl_init_context_attributes(attributes: *mut EmscriptenWebGLContextAttributes);
    pub fn emscripten_webgl_create_context(target: *const libc::c_char,
        attributes: *const EmscriptenWebGLContextAttributes) -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;

    pub fn emscripten_webgl_make_context_current(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
    -> EMSCRIPTEN_RESULT;

    pub fn emscripten_webgl_get_current_context() -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;

    pub fn emscripten_webgl_destroy_context(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
        -> EMSCRIPTEN_RESULT;

    pub fn emscripten_webgl_enable_extension(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE,
        extension: *const libc::c_char) -> EM_BOOL;

    pub fn emscripten_set_webglcontextlost_callback(target: *const libc::c_char,
        userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
        -> EMSCRIPTEN_RESULT;
    pub fn emscripten_set_webglcontextrestored_callback(target: *const libc::c_char,
        userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
        -> EMSCRIPTEN_RESULT;

    pub fn emscripten_is_webgl_context_lost(target: *const libc::c_char) -> EM_BOOL;

    // note: this function is not documented but is used by the ports of glfw, SDL and EGL
    pub fn emscripten_GetProcAddress(name: *const libc::c_char) -> *const libc::c_void;

    pub fn emscripten_request_fullscreen(target: *const libc::c_char,
        deferUntilInEventHandler: EM_BOOL) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;

    pub fn emscripten_set_element_css_size(target: *const libc::c_char, width: libc::c_double,
        height: libc::c_double) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_get_element_css_size(target: *const libc::c_char, width: *mut libc::c_double,
        height: *mut libc::c_double) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_sleep(delay: libc::c_uint);
}
<commit_msg>Add main_loop definition for emscripten<commit_after>#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

use libc;

pub type EM_BOOL = libc::c_int;
pub type EM_UTF8 = libc::c_char;
pub type EMSCRIPTEN_WEBGL_CONTEXT_HANDLE = libc::c_int;
pub type EMSCRIPTEN_RESULT = libc::c_int;

pub type em_webgl_context_callback = extern fn(libc::c_int, *const libc::c_void, *mut libc::c_void)
    -> EM_BOOL;

pub type em_callback_func = unsafe extern fn();

#[repr(C)]
pub struct EmscriptenWebGLContextAttributes {
    pub alpha: EM_BOOL,
    pub depth: EM_BOOL,
    pub stencil: EM_BOOL,
    pub antialias: EM_BOOL,
    pub premultipliedAlpha: EM_BOOL,
    pub preserveDrawingBuffer: EM_BOOL,
    pub preferLowPowerToHighPerformance: EM_BOOL,
    pub failIfMajorPerformanceCaveat: EM_BOOL,
    pub majorVersion: libc::c_int,
    pub minorVersion: libc::c_int,
    pub enableExtensionsByDefault: EM_BOOL,
}

// values for EMSCRIPTEN_RESULT
pub const EMSCRIPTEN_RESULT_SUCCESS: libc::c_int = 0;
pub const EMSCRIPTEN_RESULT_DEFERRED: libc::c_int = 1;
pub const EMSCRIPTEN_RESULT_NOT_SUPPORTED: libc::c_int = -1;
pub const EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED: libc::c_int = -2;
pub const EMSCRIPTEN_RESULT_INVALID_TARGET: libc::c_int = -3;
pub const EMSCRIPTEN_RESULT_UNKNOWN_TARGET: libc::c_int = -4;
pub const EMSCRIPTEN_RESULT_INVALID_PARAM: libc::c_int = -5;
pub const EMSCRIPTEN_RESULT_FAILED: libc::c_int = -6;
pub const EMSCRIPTEN_RESULT_NO_DATA: libc::c_int = -7;

extern {
    pub fn emscripten_webgl_init_context_attributes(attributes: *mut EmscriptenWebGLContextAttributes);
    pub fn emscripten_webgl_create_context(target: *const libc::c_char,
        attributes: *const EmscriptenWebGLContextAttributes) -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;

    pub fn emscripten_webgl_make_context_current(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
    -> EMSCRIPTEN_RESULT;

    pub fn emscripten_webgl_get_current_context() -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;

    pub fn emscripten_webgl_destroy_context(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
        -> EMSCRIPTEN_RESULT;

    pub fn emscripten_webgl_enable_extension(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE,
        extension: *const libc::c_char) -> EM_BOOL;

    pub fn emscripten_set_webglcontextlost_callback(target: *const libc::c_char,
        userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
        -> EMSCRIPTEN_RESULT;
    pub fn emscripten_set_webglcontextrestored_callback(target: *const libc::c_char,
        userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
        -> EMSCRIPTEN_RESULT;

    pub fn emscripten_is_webgl_context_lost(target: *const libc::c_char) -> EM_BOOL;

    // note: this function is not documented but is used by the ports of glfw, SDL and EGL
    pub fn emscripten_GetProcAddress(name: *const libc::c_char) -> *const libc::c_void;

    pub fn emscripten_request_fullscreen(target: *const libc::c_char,
        deferUntilInEventHandler: EM_BOOL) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;

    pub fn emscripten_set_element_css_size(target: *const libc::c_char, width: libc::c_double,
        height: libc::c_double) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_get_element_css_size(target: *const libc::c_char, width: *mut libc::c_double,
        height: *mut libc::c_double) -> EMSCRIPTEN_RESULT;

    pub fn emscripten_sleep(delay: libc::c_uint);

    pub fn emscripten_set_main_loop(func : em_callback_func, fps : libc::c_int, simulate_infinite_loop : libc::c_int);
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate num_cpus;
extern crate futures;
extern crate ruyi;

use std::env;
use std::io;
use std::mem;
use std::net::{Shutdown, SocketAddr};
use std::path::Path;
use std::process;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

use futures::{future, stream, Future, Sink, Stream};

use ruyi::buf::ByteBuf;
use ruyi::channel::spsc;
use ruyi::nio;
use ruyi::io::{self as rio, AsyncRead, AsyncWrite};
use ruyi::net;
use ruyi::reactor::{self, IntoTask, Task};
use ruyi::stream::IntoStream;
use ruyi::sink::IntoSink;

#[derive(Debug, Clone, Copy)]
struct Conf {
    threads: usize,
    bytes: usize,
    connections: usize,
    seconds: u64,
    addr: SocketAddr,
}

impl Default for Conf {
    fn default() -> Self {
        Conf {
            threads: num_cpus::get(),
            bytes: 16_384,
            connections: 100,
            seconds: 60,
            addr: "127.0.0.1:10007".parse().unwrap(),
        }
    }
}

fn print_usage(program: &str) {
    println!("Usage: {} [OPTION...] [HOST [PORT]]", program);
    println!();
    println!("    Ping-pong client");
    println!();
    println!("Host:");
    println!("    Server IP to connect to. Default to 127.0.0.1");
    println!();
    println!("Port:");
    println!("    Server port to connect to. Default to 10007");
    println!();
    println!("Options:");
    println!("    -h, --help                        Print this help and exit.");
    println!("    -t<num>, --threads=<num>          Number of threads.");
    println!("    -b<num>, --bytes=<num>            Number of bytes to send.");
    println!("    -c<num>, --connections=<num>      Concurrent connections per thread.");
    println!("    -s<secs>, --seconds=<secs>        Seconds to run.");
    println!();
}

fn process_command_line() -> Result<Option<Conf>, String> {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "");
    opts.optopt("t", "threads", "", "");
    opts.optopt("b", "bytes", "", "");
    opts.optopt("c", "connections", "", "");
    opts.optopt("s", "seconds", "", "");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..])
        .map_err(|e| format!("Failed to parse command options: {}", e))?;
    if matches.opt_present("h") {
        let path = Path::new(&args[0]);
        let program = path.file_stem().unwrap().to_string_lossy();
        print_usage(&program);
        return Ok(None);
    }

    let mut conf = Conf::default();
    if matches.free.len() > 0 {
        let ip = matches.free[0]
            .parse()
            .map_err(|e| format!("Failed to parse HOST: {}", e))?;
        conf.addr.set_ip(ip);
    }
    if matches.free.len() > 1 {
        let port = matches.free[1]
            .parse()
            .map_err(|e| format!("Failed to parse PORT: {}", e))?;
        conf.addr.set_port(port);
    }

    if let Some(t) = matches.opt_str("t") {
        let threads = t.parse().unwrap();
        if threads > 0 {
            conf.threads = threads;
        }
    }
    if let Some(b) = matches.opt_str("b") {
        let bytes = b.parse().unwrap();
        if bytes > 0 {
            conf.bytes = bytes;
        }
    }
    if let Some(c) = matches.opt_str("c") {
        let connections = c.parse().unwrap();
        if connections > 0 {
            conf.connections = connections;
        }
    }
    if let Some(s) = matches.opt_str("s") {
        let seconds = s.parse().unwrap();
        if seconds > 0 {
            conf.seconds = seconds;
        }
    }

    Ok(Some(conf))
}

struct TcpStream(net::TcpStream);

impl Drop for TcpStream {
    #[inline]
    fn drop(&mut self) {
        self.0.shutdown(Shutdown::Write).ok();
    }
}

impl io::Read for TcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl nio::ReadV for TcpStream {
    #[inline]
    fn readv(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.0.readv(iovs)
    }
}

impl AsyncRead for TcpStream {
    #[inline]
    fn need_read(&mut self) -> io::Result<()> {
        self.0.need_read()
    }

    #[inline]
    fn no_need_read(&mut self) -> io::Result<()> {
        self.0.no_need_read()
    }

    #[inline]
    fn is_readable(&self) -> bool {
        self.0.is_readable()
    }
}

impl io::Write for TcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl nio::WriteV for TcpStream {
    #[inline]
    fn writev(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.0.writev(iovs)
    }
}

impl AsyncWrite for TcpStream {
    #[inline]
    fn need_write(&mut self) -> io::Result<()> {
        self.0.need_write()
    }

    #[inline]
    fn no_need_write(&mut self) -> io::Result<()> {
        self.0.no_need_write()
    }

    #[inline]
    fn is_writable(&self) -> bool {
        self.0.is_writable()
    }
}

#[inline]
fn ping_pong(
    addr: &SocketAddr,
    len: usize,
    msgs: &'static mut usize,
    bytes: &'static mut usize,
) -> Task {
    net::TcpStream::connect(addr)
        .and_then(move |s| {
            future::result(s.set_nodelay(true)).and_then(move |_| {
                let (r, w) = rio::split(TcpStream(s));
                let mut data = Vec::<u8>::with_capacity(len);
                unsafe { data.set_len(len) };
                w.into_sink().send_all(
                    stream::once(Ok(ByteBuf::from(data))).chain(r.into_stream().filter(move |b| {
                        *msgs += 1;
                        *bytes += b.len();
                        true
                    })),
                )
            })
        })
        .map_err(|e| eprintln!("{}", e))
        .into_task()
}

#[inline]
fn run(conf: Conf) {
    println!("Pingpong client start: {:?}", conf);
    let sleep = reactor::sleep(conf.seconds);
    let mut threads = Vec::with_capacity(conf.threads);
    let total_msgs = Arc::new(AtomicUsize::new(0));
    let total_bytes = Arc::new(AtomicUsize::new(0));
    for _ in 0..conf.threads {
        let (tx, rx) = spsc::sync_channel::<Conf>(1).unwrap();
        let total_msgs = total_msgs.clone();
        let total_bytes = total_bytes.clone();
        let handle = thread::spawn(move || {
            let mut msgs = 0usize;
            let mut bytes = 0usize;
            {
                let task = rx.into_stream().for_each(|conf| {
                    for _ in 0..conf.connections {
                        let s_msgs: &'static mut usize = unsafe { mem::transmute(&mut msgs) };
                        let s_bytes: &'static mut usize = unsafe { mem::transmute(&mut bytes) };
                        reactor::spawn(ping_pong(&conf.addr, conf.bytes, s_msgs, s_bytes));
                    }
                    Ok(())
                });
                reactor::run(task).unwrap();
            }
            total_msgs.as_ref().fetch_add(msgs, Ordering::Relaxed);
            total_bytes.as_ref().fetch_add(bytes, Ordering::Relaxed);
        });
        tx.send(conf).unwrap();
        threads.push((Some(handle), Some(tx)));
    }
    reactor::run(sleep).unwrap();
    for thread in threads.iter_mut() {
        thread.1 = None;
    }
    for thread in threads.iter_mut() {
        thread.0.take().unwrap().join().unwrap();
    }
    let bytes = total_bytes.as_ref().load(Ordering::Relaxed);
    let msgs = total_msgs.as_ref().load(Ordering::Relaxed);
    println!("Total bytes read: {}", bytes);
    println!("Total messages read: {}", msgs);
    println!("Average message size: {}", bytes as f64 / msgs as f64);
    println!(
        "Throughput: {} MiB/s",
        bytes as f64 / (conf.seconds * 1024 * 1024) as f64
    );
    println!("Pingpong client end");
}

#[inline]
fn exit(err_msg: &str) -> ! {
    if !err_msg.is_empty() {
        eprintln!("{}", err_msg);
    }
    process::exit(1)
}

fn main() {
    match process_command_line() {
        Ok(Some(conf)) => run(conf),
        Ok(None) => {}
        Err(e) => exit(&e),
    }
}
<commit_msg>More log info<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;

extern crate getopts;
extern crate num_cpus;
extern crate chrono;
extern crate futures;
extern crate ruyi;

use std::env;
use std::io;
use std::mem;
use std::net::{Shutdown, SocketAddr};
use std::path::Path;
use std::process;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

use chrono::prelude::Utc;
use futures::{future, stream, Future, Sink, Stream};
use env_logger::LogBuilder;

use ruyi::buf::ByteBuf;
use ruyi::channel::spsc;
use ruyi::nio;
use ruyi::io::{self as rio, AsyncRead, AsyncWrite};
use ruyi::net;
use ruyi::reactor::{self, IntoTask, Task, Timer};
use ruyi::stream::IntoStream;
use ruyi::sink::IntoSink;

#[derive(Debug, Clone, Copy)]
struct Conf {
    threads: usize,
    bytes: usize,
    connections: usize,
    seconds: u64,
    addr: SocketAddr,
}

impl Default for Conf {
    fn default() -> Self {
        Conf {
            threads: num_cpus::get(),
            bytes: 16_384,
            connections: 100,
            seconds: 60,
            addr: "127.0.0.1:10007".parse().unwrap(),
        }
    }
}

fn print_usage(program: &str) {
    println!("Usage: {} [OPTION...] [HOST [PORT]]", program);
    println!();
    println!("    Ping-pong client");
    println!();
    println!("Host:");
    println!("    Server IP to connect to. Default to 127.0.0.1");
    println!();
    println!("Port:");
    println!("    Server port to connect to. Default to 10007");
    println!();
    println!("Options:");
    println!("    -h, --help                        Print this help and exit.");
    println!("    -t<num>, --threads=<num>          Number of threads.");
    println!("    -b<num>, --bytes=<num>            Number of bytes to send.");
    println!("    -c<num>, --connections=<num>      Concurrent connections per thread.");
    println!("    -s<secs>, --seconds=<secs>        Seconds to run.");
    println!();
}

fn process_command_line() -> Result<Option<Conf>, String> {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "");
    opts.optopt("t", "threads", "", "");
    opts.optopt("b", "bytes", "", "");
    opts.optopt("c", "connections", "", "");
    opts.optopt("s", "seconds", "", "");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..])
        .map_err(|e| format!("Failed to parse command options: {}", e))?;
    if matches.opt_present("h") {
        let path = Path::new(&args[0]);
        let program = path.file_stem().unwrap().to_string_lossy();
        print_usage(&program);
        return Ok(None);
    }

    let mut conf = Conf::default();
    if matches.free.len() > 0 {
        let ip = matches.free[0]
            .parse()
            .map_err(|e| format!("Failed to parse HOST: {}", e))?;
        conf.addr.set_ip(ip);
    }
    if matches.free.len() > 1 {
        let port = matches.free[1]
            .parse()
            .map_err(|e| format!("Failed to parse PORT: {}", e))?;
        conf.addr.set_port(port);
    }

    if let Some(t) = matches.opt_str("t") {
        let threads = t.parse().unwrap();
        if threads > 0 {
            conf.threads = threads;
        }
    }
    if let Some(b) = matches.opt_str("b") {
        let bytes = b.parse().unwrap();
        if bytes > 0 {
            conf.bytes = bytes;
        }
    }
    if let Some(c) = matches.opt_str("c") {
        let connections = c.parse().unwrap();
        if connections > 0 {
            conf.connections = connections;
        }
    }
    if let Some(s) = matches.opt_str("s") {
        let seconds = s.parse().unwrap();
        if seconds > 0 {
            conf.seconds = seconds;
        }
    }

    Ok(Some(conf))
}

struct TcpStream(net::TcpStream);

impl Drop for TcpStream {
    #[inline]
    fn drop(&mut self) {
        self.0.shutdown(Shutdown::Write).ok();
    }
}

impl io::Read for TcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl nio::ReadV for TcpStream {
    #[inline]
    fn readv(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.0.readv(iovs)
    }
}

impl AsyncRead for TcpStream {
    #[inline]
    fn need_read(&mut self) -> io::Result<()> {
        self.0.need_read()
    }

    #[inline]
    fn no_need_read(&mut self) -> io::Result<()> {
        self.0.no_need_read()
    }

    #[inline]
    fn is_readable(&self) -> bool {
        self.0.is_readable()
    }
}

impl io::Write for TcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl nio::WriteV for TcpStream {
    #[inline]
    fn writev(&mut self, iovs: &[nio::IoVec]) -> io::Result<usize> {
        self.0.writev(iovs)
    }
}

impl AsyncWrite for TcpStream {
    #[inline]
    fn need_write(&mut self) -> io::Result<()> {
        self.0.need_write()
    }

    #[inline]
    fn no_need_write(&mut self) -> io::Result<()> {
        self.0.no_need_write()
    }

    #[inline]
    fn is_writable(&self) -> bool {
        self.0.is_writable()
    }
}

struct Vars {
    msgs: usize,
    bytes: usize,
    conns: usize,
    count: Arc<AtomicUsize>,
}

#[inline]
fn ping_pong(addr: &SocketAddr, len: usize, vars: &'static mut Vars) -> Task {
    net::TcpStream::connect(addr)
        .and_then(move |s| {
            vars.conns -= 1;
            if vars.conns == 0 {
                if vars.count.as_ref().fetch_sub(1, Ordering::Relaxed) == 1 {
                    info!("All connected");
                }
            }
            future::result(s.set_nodelay(true)).and_then(move |_| {
                let (r, w) = rio::split(TcpStream(s));
                let mut data = Vec::<u8>::with_capacity(len);
                unsafe { data.set_len(len) };
                w.into_sink().send_all(
                    stream::once(Ok(ByteBuf::from(data))).chain(r.into_stream().filter(move |b| {
                        vars.msgs += 1;
                        vars.bytes += b.len();
                        true
                    })),
                )
            })
        })
        .map_err(|e| error!("{}", e))
        .into_task()
}

#[inline]
fn run(conf: Conf) {
    info!("Start - {:?}", conf);
    let timer = Timer::new(Duration::from_secs(conf.seconds));
    let mut threads = Vec::with_capacity(conf.threads);
    let total_msgs = Arc::new(AtomicUsize::new(0));
    let total_bytes = Arc::new(AtomicUsize::new(0));
    let n = Arc::new(AtomicUsize::new(conf.threads));
    for _ in 0..conf.threads {
        let (tx, rx) = spsc::sync_channel(1).unwrap();
        let total_msgs = total_msgs.clone();
        let total_bytes = total_bytes.clone();
        let conns = conf.connections;
        let n = n.clone();
        let handle = thread::spawn(move || {
            let mut vars = Vars {
                msgs: 0,
                bytes: 0,
                conns: conns,
                count: n,
            };
            {
                let task = rx.into_stream().for_each(|(addr, bytes)| {
                    for _ in 0..conns {
                        let s_vars: &'static mut Vars = unsafe { mem::transmute(&mut vars) };
                        reactor::spawn(ping_pong(&addr, bytes, s_vars));
                    }
                    Ok(())
                });
                reactor::run(task).unwrap();
            }
            total_msgs.as_ref().fetch_add(vars.msgs, Ordering::Relaxed);
            total_bytes
                .as_ref()
                .fetch_add(vars.bytes, Ordering::Relaxed);
        });
        tx.send((conf.addr, conf.bytes)).unwrap();
        threads.push((Some(handle), Some(tx)));
    }
    reactor::run(timer).unwrap();
    for thread in threads.iter_mut() {
        thread.1 = None;
    }
    for thread in threads.iter_mut() {
        thread.0.take().unwrap().join().unwrap();
    }
    let bytes = total_bytes.as_ref().load(Ordering::Relaxed);
    let msgs = total_msgs.as_ref().load(Ordering::Relaxed);
    info!("Total bytes read: {}", bytes);
    info!("Total messages read: {}", msgs);
    info!("Average message size: {}", bytes as f64 / msgs as f64);
    info!(
        "Throughput: {} MiB/s",
        bytes as f64 / (conf.seconds * 1024 * 1024) as f64
    );
}

#[inline]
fn exit(err_msg: &str) -> ! {
    if !err_msg.is_empty() {
        error!("{}", err_msg);
    }
    process::exit(1)
}

fn main() {
    let mut builder = LogBuilder::new();
    builder.format(|r| {
        format!(
            "{} {:<5} {}",
            Utc::now().format("%Y-%m-%d %H:%M:%S.%f"),
            r.level(),
            r.args()
        )
    });
    if let Ok(v) = env::var("RUST_LOG") {
        builder.parse(&v);
    }
    builder.init().unwrap();

    match process_command_line() {
        Ok(Some(conf)) => run(conf),
        Ok(None) => {}
        Err(e) => exit(&e),
    }
}
<|endoftext|>


<commit_before>extern crate systray;

//#[cfg(target_os = "windows")]
fn main() {
    let mut app;
    match systray::Application::new() {
        Ok(w) => app = w,
        Err(e) => panic!("Can't create window!")
    }
    // w.set_icon_from_file(&"C:\\Users\\qdot\\code\\git-projects\\systray-rs\\resources\\rust.ico".to_string());
    // w.set_tooltip(&"Whatever".to_string());
    app.set_icon_from_file(&"/usr/share/gxkb/flags/ua.png".to_string());
    app.add_menu_item(&"Print a thing".to_string(), |window| {
        println!("Printing a thing!");
    });
    app.add_menu_item(&"Add Menu Item".to_string(), |window| {
        window.add_menu_item(&"Interior item".to_string(), |window| {
            println!("what");
        });
        window.add_menu_separator();
    });
    app.add_menu_separator();
    app.add_menu_item(&"Quit".to_string(), |window| {
        window.quit();
    });
    println!("Waiting on message!");
    app.wait_for_message();
}

// #[cfg(not(target_os = "windows"))]
// fn main() {
//     panic!("Not implemented on this platform!");
// }
<commit_msg>chore: Clean up warnings in example<commit_after>extern crate systray;

//#[cfg(target_os = "windows")]
fn main() {
    let mut app;
    match systray::Application::new() {
        Ok(w) => app = w,
        Err(_) => panic!("Can't create window!")
    }
    // w.set_icon_from_file(&"C:\\Users\\qdot\\code\\git-projects\\systray-rs\\resources\\rust.ico".to_string());
    // w.set_tooltip(&"Whatever".to_string());
    app.set_icon_from_file(&"/usr/share/gxkb/flags/ua.png".to_string()).ok();
    app.add_menu_item(&"Print a thing".to_string(), |_| {
        println!("Printing a thing!");
    }).ok();
    app.add_menu_item(&"Add Menu Item".to_string(), |window| {
        window.add_menu_item(&"Interior item".to_string(), |_| {
            println!("what");
        }).ok();
        window.add_menu_separator().ok();
    }).ok();
    app.add_menu_separator().ok();
    app.add_menu_item(&"Quit".to_string(), |window| {
        window.quit();
    }).ok();
    println!("Waiting on message!");
    app.wait_for_message();
}

// #[cfg(not(target_os = "windows"))]
// fn main() {
//     panic!("Not implemented on this platform!");
// }
<|endoftext|>