<commit_before>#[macro_use]
extern crate serde_derive;

use serde_json;

use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write};
use std::path::Path;
use std::process::Command;

use clap::{App, Arg};
use inflector::Inflector;

mod json_schema;
use crate::json_schema::{JsonSchema, PropType};

mod generator;
use crate::generator::*;

const SCHEMA_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/slack-api-schemas");
const DEFAULT_OUT_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/../src");

fn generate_types(output_path: &Path) -> io::Result<()> {
    let codegen_filepath = output_path.join("types.rs");

    let mut types_file = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(&codegen_filepath)?;

    types_file.write_all(b"use std::collections::HashMap;\n\n")?;

    let schema_path = Path::new(SCHEMA_DIR);

    for entry in fs::read_dir(schema_path.join("objects"))? {
        if let Ok(e) = entry {
            let path = e.path();
            if path.is_file() {
                let mut schema_file = File::open(&path)?;
                let mut schema_contents = String::new();
                schema_file.read_to_string(&mut schema_contents)?;

                let schema = serde_json::from_str::<JsonSchema>(&schema_contents).expect(&format!(
                    "Could not parse object schema for {}",
                    path.display()
                ));

                let ty_name = path.file_stem().unwrap().to_str().unwrap().to_pascal_case();

                let ty = match PropType::from_schema(&schema, &ty_name) {
                    PropType::Obj(ref o) => o.to_code(),
                    PropType::Enum(ref e) => e.to_code(),
                    _ => panic!("Object schema is not an object."),
                };

                types_file.write_all(ty.as_bytes())?;
            }
        }
    }

    Command::new("rustfmt").arg(codegen_filepath).output()?;

    Ok(())
}

fn generate_modules(output_path: &Path) -> io::Result<()> {
    let mut mods = vec![];

    let schema_path = Path::new(SCHEMA_DIR);

    for entry in fs::read_dir(schema_path.join("web"))? {
        if let Ok(e) = entry {
            let path = e.path();
            if path.is_file() {
                let mut schema_file = File::open(&path)?;
                let mut schema_contents = String::new();
                schema_file.read_to_string(&mut schema_contents)?;

                let module = serde_json::from_str::<Module>(&schema_contents).expect(&format!(
                    "Could not parse module schema for {}",
                    path.display()
                ));
                mods.push(module.get_safe_name());

                let out_filepath = output_path.join(format!("{}.rs", module.get_safe_name()));

                {
                    let mut out_file = OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(&out_filepath)?;

                    out_file.write_all(module.generate().as_bytes())?;
                }

                Command::new("rustfmt").arg(out_filepath).output()?;
            }
        }
    }

    let mut mod_file = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(output_path.join("mod.rs"))?;

    mod_file.write_all(
        mods.iter()
            .map(|modname| format!("pub mod {};", modname))
            .collect::<Vec<_>>()
            .join("\n")
            .as_bytes(),
    )?;

    Ok(())
}

fn main() {
    let matches = App::new("slack-rs API Code Generator")
        .arg(
            Arg::with_name("out_dir")
                .short("o")
                .long("outdir")
                .value_name("DIR")
                .help("Sets the output directory for the generated code.")
                .default_value(DEFAULT_OUT_DIR)
                .validator_os(|dir| {
                    let outdir = Path::new(dir);
                    if outdir.exists() && !outdir.is_dir() {
                        return Err("must be a directory".into());
                    }
                    Ok(())
                }),
        )
        .get_matches();

    let outdir = Path::new(matches.value_of_os("out_dir").unwrap());
    if !outdir.exists() {
        let _ = fs::create_dir(outdir);
    }

    let moddir = outdir.join("mods");
    if !moddir.exists() {
        let _ = fs::create_dir(&moddir);
    }

    generate_modules(&moddir).unwrap();
    generate_types(outdir).unwrap();
}
<commit_msg>rustfmt requires --edition 2018 adding<commit_after>#[macro_use]
extern crate serde_derive;

use serde_json;

use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write};
use std::path::Path;
use std::process::Command;

use clap::{App, Arg};
use inflector::Inflector;

mod json_schema;
use crate::json_schema::{JsonSchema, PropType};

mod generator;
use crate::generator::*;

const SCHEMA_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/slack-api-schemas");
const DEFAULT_OUT_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/../src");

fn generate_types(output_path: &Path) -> io::Result<()> {
    let codegen_filepath = output_path.join("types.rs");

    let mut types_file = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(&codegen_filepath)?;

    types_file.write_all(b"use std::collections::HashMap;\n\n")?;

    let schema_path = Path::new(SCHEMA_DIR);

    for entry in fs::read_dir(schema_path.join("objects"))? {
        if let Ok(e) = entry {
            let path = e.path();
            if path.is_file() {
                let mut schema_file = File::open(&path)?;
                let mut schema_contents = String::new();
                schema_file.read_to_string(&mut schema_contents)?;

                let schema = serde_json::from_str::<JsonSchema>(&schema_contents).expect(&format!(
                    "Could not parse object schema for {}",
                    path.display()
                ));

                let ty_name = path.file_stem().unwrap().to_str().unwrap().to_pascal_case();

                let ty = match PropType::from_schema(&schema, &ty_name) {
                    PropType::Obj(ref o) => o.to_code(),
                    PropType::Enum(ref e) => e.to_code(),
                    _ => panic!("Object schema is not an object."),
                };

                types_file.write_all(ty.as_bytes())?;
            }
        }
    }

    Command::new("rustfmt")
        .args(&["--edition", "2018"])
        .arg(codegen_filepath)
        .output()?;

    Ok(())
}

fn generate_modules(output_path: &Path) -> io::Result<()> {
    let mut mods = vec![];

    let schema_path = Path::new(SCHEMA_DIR);

    for entry in fs::read_dir(schema_path.join("web"))? {
        if let Ok(e) = entry {
            let path = e.path();
            if path.is_file() {
                let mut schema_file = File::open(&path)?;
                let mut schema_contents = String::new();
                schema_file.read_to_string(&mut schema_contents)?;

                let module = serde_json::from_str::<Module>(&schema_contents).expect(&format!(
                    "Could not parse module schema for {}",
                    path.display()
                ));
                mods.push(module.get_safe_name());

                let out_filepath = output_path.join(format!("{}.rs", module.get_safe_name()));

                {
                    let mut out_file = OpenOptions::new()
                        .write(true)
                        .truncate(true)
                        .create(true)
                        .open(&out_filepath)?;

                    out_file.write_all(module.generate().as_bytes())?;
                }

                Command::new("rustfmt")
                    .args(&["--edition", "2018"])
                    .arg(out_filepath)
                    .output()?;
            }
        }
    }

    let mut mod_file = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(output_path.join("mod.rs"))?;

    mod_file.write_all(
        mods.iter()
            .map(|modname| format!("pub mod {};", modname))
            .collect::<Vec<_>>()
            .join("\n")
            .as_bytes(),
    )?;

    Ok(())
}

fn main() {
    let matches = App::new("slack-rs API Code Generator")
        .arg(
            Arg::with_name("out_dir")
                .short("o")
                .long("outdir")
                .value_name("DIR")
                .help("Sets the output directory for the generated code.")
                .default_value(DEFAULT_OUT_DIR)
                .validator_os(|dir| {
                    let outdir = Path::new(dir);
                    if outdir.exists() && !outdir.is_dir() {
                        return Err("must be a directory".into());
                    }
                    Ok(())
                }),
        )
        .get_matches();

    let outdir = Path::new(matches.value_of_os("out_dir").unwrap());
    if !outdir.exists() {
        let _ = fs::create_dir(outdir);
    }

    let moddir = outdir.join("mods");
    if !moddir.exists() {
        let _ = fs::create_dir(&moddir);
    }

    generate_modules(&moddir).unwrap();
    generate_types(outdir).unwrap();
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::fmt;

#[cfg(feature = "bytes")]
use crate::bytes::Bytes;
#[cfg(feature = "bytes")]
use crate::chars::Chars;

use crate::reflect::runtime_types::RuntimeType;
use crate::reflect::runtime_types::RuntimeTypeBool;
#[cfg(feature = "bytes")]
use crate::reflect::runtime_types::RuntimeTypeCarllercheBytes;
#[cfg(feature = "bytes")]
use crate::reflect::runtime_types::RuntimeTypeCarllercheChars;
use crate::reflect::runtime_types::RuntimeTypeF32;
use crate::reflect::runtime_types::RuntimeTypeF64;
use crate::reflect::runtime_types::RuntimeTypeI32;
use crate::reflect::runtime_types::RuntimeTypeI64;
use crate::reflect::runtime_types::RuntimeTypeString;
use crate::reflect::runtime_types::RuntimeTypeU32;
use crate::reflect::runtime_types::RuntimeTypeU64;
use crate::reflect::runtime_types::RuntimeTypeVecU8;
use crate::reflect::value::value_box::ReflectValueBox;
use crate::reflect::value::value_ref::ReflectValueMut;
use crate::reflect::value::value_ref::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;

pub(crate) mod value_box;
pub(crate) mod value_ref;

/// Type implemented by all protobuf singular types
/// (primitives, string, messages, enums).
///
/// Used in reflection.
pub trait ProtobufValue:
    Any + Clone + Default + fmt::Debug + Send + Sync + Sized + 'static
{
    /// Actual implementation of type properties.
    type RuntimeType: RuntimeType<Value = Self>;

    // TODO: inline the rest

    /// Dynamic version of the type.
    fn runtime_type_box() -> RuntimeTypeBox {
        Self::RuntimeType::runtime_type_box()
    }

    /// Pointer to a dynamic reference.
    fn as_ref(value: &Self) -> ReflectValueRef {
        Self::RuntimeType::as_ref(value)
    }

    /// Mutable pointer to a dynamic mutable reference.
    fn as_mut(value: &mut Self) -> ReflectValueMut {
        Self::RuntimeType::as_mut(value)
    }

    /// Construct a value from given reflective value.
    ///
    /// # Panics
    ///
    /// If reflective value is of incompatible type.
    fn from_value_box(value_box: ReflectValueBox) -> Result<Self, ReflectValueBox> {
        Self::RuntimeType::from_value_box(value_box)
    }

    /// Write the value.
    fn set_from_value_box(target: &mut Self, value_box: ReflectValueBox) {
        Self::RuntimeType::set_from_value_box(target, value_box)
    }

    /// Default value for this type.
    fn default_value_ref() -> ReflectValueRef<'static> {
        Self::RuntimeType::default_value_ref()
    }

    /// Convert a value into a ref value if possible.
    ///
    /// # Panics
    ///
    /// For message and enum.
    fn into_static_value_ref(value: Self) -> ReflectValueRef<'static> {
        Self::RuntimeType::into_static_value_ref(value)
    }

    /// Value is non-default?
    fn is_non_zero(value: &Self) -> bool {
        Self::RuntimeType::is_non_zero(value)
    }
}

impl ProtobufValue for u32 {
    type RuntimeType = RuntimeTypeU32;
}

impl ProtobufValue for u64 {
    type RuntimeType = RuntimeTypeU64;
}

impl ProtobufValue for i32 {
    type RuntimeType = RuntimeTypeI32;
}

impl ProtobufValue for i64 {
    type RuntimeType = RuntimeTypeI64;
}

impl ProtobufValue for f32 {
    type RuntimeType = RuntimeTypeF32;
}

impl ProtobufValue for f64 {
    type RuntimeType = RuntimeTypeF64;
}

impl ProtobufValue for bool {
    type RuntimeType = RuntimeTypeBool;
}

impl ProtobufValue for String {
    type RuntimeType = RuntimeTypeString;
}

impl ProtobufValue for Vec<u8> {
    type RuntimeType = RuntimeTypeVecU8;
}

#[cfg(feature = "bytes")]
impl ProtobufValue for Bytes {
    type RuntimeType = RuntimeTypeCarllercheBytes;
}

#[cfg(feature = "bytes")]
impl ProtobufValue for Chars {
    type RuntimeType = RuntimeTypeCarllercheChars;
}

// conflicting implementations, so generated code is used instead
/*
impl<E : ProtobufEnum> ProtobufValue for E {
}

impl<M : Message> ProtobufValue for M {
}
*/

#[cfg(not(feature = "bytes"))]
type VecU8OrBytes = Vec<u8>;
#[cfg(feature = "bytes")]
type VecU8OrBytes = Vec<u8>;
#[cfg(not(feature = "bytes"))]
type StringOrChars = String;
#[cfg(feature = "bytes")]
type StringOrChars = Chars;
<commit_msg>Remove unused type aliases<commit_after>use std::any::Any;
use std::fmt;

#[cfg(feature = "bytes")]
use crate::bytes::Bytes;
#[cfg(feature = "bytes")]
use crate::chars::Chars;

use crate::reflect::runtime_types::RuntimeType;
use crate::reflect::runtime_types::RuntimeTypeBool;
#[cfg(feature = "bytes")]
use crate::reflect::runtime_types::RuntimeTypeCarllercheBytes;
#[cfg(feature = "bytes")]
use crate::reflect::runtime_types::RuntimeTypeCarllercheChars;
use crate::reflect::runtime_types::RuntimeTypeF32;
use crate::reflect::runtime_types::RuntimeTypeF64;
use crate::reflect::runtime_types::RuntimeTypeI32;
use crate::reflect::runtime_types::RuntimeTypeI64;
use crate::reflect::runtime_types::RuntimeTypeString;
use crate::reflect::runtime_types::RuntimeTypeU32;
use crate::reflect::runtime_types::RuntimeTypeU64;
use crate::reflect::runtime_types::RuntimeTypeVecU8;
use crate::reflect::value::value_box::ReflectValueBox;
use crate::reflect::value::value_ref::ReflectValueMut;
use crate::reflect::value::value_ref::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;

pub(crate) mod value_box;
pub(crate) mod value_ref;

/// Type implemented by all protobuf singular types
/// (primitives, string, messages, enums).
///
/// Used in reflection.
pub trait ProtobufValue:
    Any + Clone + Default + fmt::Debug + Send + Sync + Sized + 'static
{
    /// Actual implementation of type properties.
    type RuntimeType: RuntimeType<Value = Self>;

    // TODO: inline the rest

    /// Dynamic version of the type.
    fn runtime_type_box() -> RuntimeTypeBox {
        Self::RuntimeType::runtime_type_box()
    }

    /// Pointer to a dynamic reference.
    fn as_ref(value: &Self) -> ReflectValueRef {
        Self::RuntimeType::as_ref(value)
    }

    /// Mutable pointer to a dynamic mutable reference.
    fn as_mut(value: &mut Self) -> ReflectValueMut {
        Self::RuntimeType::as_mut(value)
    }

    /// Construct a value from given reflective value.
    ///
    /// # Panics
    ///
    /// If reflective value is of incompatible type.
    fn from_value_box(value_box: ReflectValueBox) -> Result<Self, ReflectValueBox> {
        Self::RuntimeType::from_value_box(value_box)
    }

    /// Write the value.
    fn set_from_value_box(target: &mut Self, value_box: ReflectValueBox) {
        Self::RuntimeType::set_from_value_box(target, value_box)
    }

    /// Default value for this type.
    fn default_value_ref() -> ReflectValueRef<'static> {
        Self::RuntimeType::default_value_ref()
    }

    /// Convert a value into a ref value if possible.
    ///
    /// # Panics
    ///
    /// For message and enum.
    fn into_static_value_ref(value: Self) -> ReflectValueRef<'static> {
        Self::RuntimeType::into_static_value_ref(value)
    }

    /// Value is non-default?
    fn is_non_zero(value: &Self) -> bool {
        Self::RuntimeType::is_non_zero(value)
    }
}

impl ProtobufValue for u32 {
    type RuntimeType = RuntimeTypeU32;
}

impl ProtobufValue for u64 {
    type RuntimeType = RuntimeTypeU64;
}

impl ProtobufValue for i32 {
    type RuntimeType = RuntimeTypeI32;
}

impl ProtobufValue for i64 {
    type RuntimeType = RuntimeTypeI64;
}

impl ProtobufValue for f32 {
    type RuntimeType = RuntimeTypeF32;
}

impl ProtobufValue for f64 {
    type RuntimeType = RuntimeTypeF64;
}

impl ProtobufValue for bool {
    type RuntimeType = RuntimeTypeBool;
}

impl ProtobufValue for String {
    type RuntimeType = RuntimeTypeString;
}

impl ProtobufValue for Vec<u8> {
    type RuntimeType = RuntimeTypeVecU8;
}

#[cfg(feature = "bytes")]
impl ProtobufValue for Bytes {
    type RuntimeType = RuntimeTypeCarllercheBytes;
}

#[cfg(feature = "bytes")]
impl ProtobufValue for Chars {
    type RuntimeType = RuntimeTypeCarllercheChars;
}

// conflicting implementations, so generated code is used instead
/*
impl<E : ProtobufEnum> ProtobufValue for E {
}

impl<M : Message> ProtobufValue for M {
}
*/
<|endoftext|>


<commit_before>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use std::{cmp, iter};
use std::fs::{OpenOptions};
use std::os::unix::io::AsRawFd;

use tempdir::TempDir;
use tempfile::tempfile;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng().gen_ascii_chars().take(128).collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().map(|x| x.clone()));
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoVec::from_slice(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
fn test_readv() {
    let s:String = thread_rng().gen_ascii_chars().take(128).collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in storage.iter_mut() {
        iovecs.push(IoVec::from_mut_slice(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in iovecs.iter() {
        read_buf.extend(iovec.as_slice().iter().map(|x| x.clone()));
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
fn test_pwrite() {
    use std::io::Read;

    let mut file = tempfile().unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = TempDir::new("nix-test_pread").unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(target_os = "linux")]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoVec::from_slice(&to_write[0..17]),
        IoVec::from_slice(&to_write[17..64]),
        IoVec::from_slice(&to_write[64..128]),
    ];

    let tempdir = TempDir::new("nix-test_pwritev").unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(target_os = "linux")]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = TempDir::new("nix-test_preadv").unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}

#[test]
#[cfg(target_os = "linux")]
// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
fn test_process_vm_readv() {
    use nix::unistd::ForkResult::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;

    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Pre-allocate memory in the child, since allocation isn't safe
    // post-fork (~= async-signal-safe)
    let mut vector = vec![1u8, 2, 3, 4, 5];

    let (r, w) = pipe().unwrap();
    match fork() {
        Ok(Parent { child }) => {
            close(w).unwrap();
            // wait for child
            read(r, &mut [0u8]).unwrap();
            close(r).unwrap();

            let ptr = vector.as_ptr() as usize;
            let remote_iov = RemoteIoVec { base: ptr, len: 5 };
            let mut buf = vec![0u8; 5];

            let ret = process_vm_readv(child,
                                       &[IoVec::from_mut_slice(&mut buf)],
                                       &[remote_iov]);

            kill(child, SIGTERM).unwrap();
            waitpid(child, None).unwrap();

            assert_eq!(Ok(5), ret);
            assert_eq!(20u8, buf.iter().sum());
        },
        Ok(Child) => {
            let _ = close(r);
            for i in vector.iter_mut() {
                *i += 1;
            }
            let _ = write(w, b"\0");
            let _ = close(w);
            loop { let _ = pause(); }
        },
        Err(_) => panic!("fork failed")
    }
}
<commit_msg>Use iter::Cloned() instead of closure<commit_after>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use std::{cmp, iter};
use std::fs::{OpenOptions};
use std::os::unix::io::AsRawFd;

use tempdir::TempDir;
use tempfile::tempfile;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng().gen_ascii_chars().take(128).collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().cloned());
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoVec::from_slice(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
fn test_readv() {
    let s:String = thread_rng().gen_ascii_chars().take(128).collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in storage.iter_mut() {
        iovecs.push(IoVec::from_mut_slice(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in iovecs.iter() {
        read_buf.extend(iovec.as_slice().iter().cloned());
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
fn test_pwrite() {
    use std::io::Read;

    let mut file = tempfile().unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = TempDir::new("nix-test_pread").unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(target_os = "linux")]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoVec::from_slice(&to_write[0..17]),
        IoVec::from_slice(&to_write[17..64]),
        IoVec::from_slice(&to_write[64..128]),
    ];

    let tempdir = TempDir::new("nix-test_pwritev").unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(target_os = "linux")]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = TempDir::new("nix-test_preadv").unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}

#[test]
#[cfg(target_os = "linux")]
// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
fn test_process_vm_readv() {
    use nix::unistd::ForkResult::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;

    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Pre-allocate memory in the child, since allocation isn't safe
    // post-fork (~= async-signal-safe)
    let mut vector = vec![1u8, 2, 3, 4, 5];

    let (r, w) = pipe().unwrap();
    match fork() {
        Ok(Parent { child }) => {
            close(w).unwrap();
            // wait for child
            read(r, &mut [0u8]).unwrap();
            close(r).unwrap();

            let ptr = vector.as_ptr() as usize;
            let remote_iov = RemoteIoVec { base: ptr, len: 5 };
            let mut buf = vec![0u8; 5];

            let ret = process_vm_readv(child,
                                       &[IoVec::from_mut_slice(&mut buf)],
                                       &[remote_iov]);

            kill(child, SIGTERM).unwrap();
            waitpid(child, None).unwrap();

            assert_eq!(Ok(5), ret);
            assert_eq!(20u8, buf.iter().sum());
        },
        Ok(Child) => {
            let _ = close(r);
            for i in vector.iter_mut() {
                *i += 1;
            }
            let _ = write(w, b"\0");
            let _ = close(w);
            loop { let _ = pause(); }
        },
        Err(_) => panic!("fork failed")
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

use std;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{task, Stream, Poll, Async};

use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::Entry;

pub type MessageQueue = Mutex<HashMap<SocketAddr, VecDeque<String>>>;
pub type TaskNotificationQueue = Mutex<Vec<task::Task>>;

pub struct PeerMessageQueue<S: Stream> {
    up: S,
    queue: Arc<MessageQueue>,
    task: Arc<TaskNotificationQueue>,
    addr: SocketAddr,
}

impl<S: Stream> PeerMessageQueue<S> {
    pub fn new(response_stream: S,
        message_queue: Arc<MessageQueue>,
        task_notifications: Arc<TaskNotificationQueue>,
        addr: SocketAddr,
    ) -> Self {
        PeerMessageQueue {
            up: response_stream,
            queue: message_queue,
            task: task_notifications,
            addr: addr,
        }
    }
}

pub struct Dispatcher {
    message_queue: Arc<MessageQueue>,
    task: Arc<TaskNotificationQueue>,
}

impl Dispatcher {
    pub fn new(message_queue: Arc<MessageQueue>, task_notifications: Arc<TaskNotificationQueue>) -> Self {
        Dispatcher {
            message_queue: message_queue,
            task: task_notifications,
        }
    }

    pub fn push_message(&self, peer_addr: &SocketAddr, msg: String) {
        let mut queue = self.message_queue.lock().unwrap();
        match queue.entry(peer_addr.clone()) {
            Entry::Vacant(vacant) => {
                let mut deque = VecDeque::new();
                deque.push_back(msg);
                vacant.insert(deque);
            },
            Entry::Occupied(mut occupied) => {
                occupied.get_mut().push_back(msg);
            }
        };

        let mut task_lock = self.task.lock().unwrap();
        let tasks = task_lock.drain(..).collect::<Vec<task::Task>>();
        for task in tasks { task.unpark(); }
    }
}

impl<S: Stream<Item=String, Error=std::io::Error>> Stream for PeerMessageQueue<S> {

    type Item = String;
    type Error = std::io::Error;

    fn poll(&mut self) -> Poll<Option<String>, std::io::Error> {
        // check if we have response pending
        match self.up.poll() {
            Ok(Async::Ready(Some(val))) => {
                return Ok(Async::Ready(Some(val)));
            },
            _ => {}
        }

        // then try to send queued message
        let mut queue = match self.queue.try_lock() {
            Ok(lock) => lock,
            Err(_) => {
                self.task.lock().unwrap().push(task::park());
                return Ok(Async::NotReady);
            }
        };

        match queue.get_mut(&self.addr) {
            None => {
                self.task.lock().unwrap().push(task::park());
                return Ok(Async::NotReady)
            },
            Some(mut peer_deque) => {
                match peer_deque.pop_front() {
                    None => {
                        self.task.lock().unwrap().push(task::park());
                        return Ok(Async::NotReady);
                    },
                    Some(msg) => {
                        Ok(Async::Ready(Some(msg)))
                    }
                }
            }
        }
    }
}
<commit_msg>add stopping through<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

use std;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{task, Stream, Poll, Async};

use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::Entry;

pub type MessageQueue = Mutex<HashMap<SocketAddr, VecDeque<String>>>;
pub type TaskNotificationQueue = Mutex<Vec<task::Task>>;

pub struct PeerMessageQueue<S: Stream> {
    up: S,
    queue: Arc<MessageQueue>,
    task: Arc<TaskNotificationQueue>,
    addr: SocketAddr,
}

impl<S: Stream> PeerMessageQueue<S> {
    pub fn new(response_stream: S,
        message_queue: Arc<MessageQueue>,
        task_notifications: Arc<TaskNotificationQueue>,
        addr: SocketAddr,
    ) -> Self {
        PeerMessageQueue {
            up: response_stream,
            queue: message_queue,
            task: task_notifications,
            addr: addr,
        }
    }
}

pub struct Dispatcher {
    message_queue: Arc<MessageQueue>,
    task: Arc<TaskNotificationQueue>,
}

impl Dispatcher {
    pub fn new(message_queue: Arc<MessageQueue>, task_notifications: Arc<TaskNotificationQueue>) -> Self {
        Dispatcher {
            message_queue: message_queue,
            task: task_notifications,
        }
    }

    pub fn push_message(&self, peer_addr: &SocketAddr, msg: String) {
        let mut queue = self.message_queue.lock().unwrap();
        match queue.entry(peer_addr.clone()) {
            Entry::Vacant(vacant) => {
                let mut deque = VecDeque::new();
                deque.push_back(msg);
                vacant.insert(deque);
            },
            Entry::Occupied(mut occupied) => {
                occupied.get_mut().push_back(msg);
            }
        };

        let mut task_lock = self.task.lock().unwrap();
        let tasks = task_lock.drain(..).collect::<Vec<task::Task>>();
        for task in tasks { task.unpark(); }
    }
}

impl<S: Stream<Item=String, Error=std::io::Error>> Stream for PeerMessageQueue<S> {

    type Item = String;
    type Error = std::io::Error;

    fn poll(&mut self) -> Poll<Option<String>, std::io::Error> {
        // check if we have response pending
        match self.up.poll() {
            Ok(Async::Ready(Some(val))) => {
                return Ok(Async::Ready(Some(val)));
            },
            Ok(Async::Ready(None)) => {
                // todo: maybe try to send what is still pending
                return Ok(Async::Ready(None));
            },
            _ => {}
        }

        // then try to send queued message
        let mut queue = match self.queue.try_lock() {
            Ok(lock) => lock,
            Err(_) => {
                self.task.lock().unwrap().push(task::park());
                return Ok(Async::NotReady);
            }
        };

        match queue.get_mut(&self.addr) {
            None => {
                self.task.lock().unwrap().push(task::park());
                return Ok(Async::NotReady)
            },
            Some(mut peer_deque) => {
                match peer_deque.pop_front() {
                    None => {
                        self.task.lock().unwrap().push(task::park());
                        return Ok(Async::NotReady);
                    },
                    Some(msg) => {
                        Ok(Async::Ready(Some(msg)))
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::memory::io::PSGChannel;

use super::Gba;
use arm::Cycles;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum EventTag {
    // Use this tag for events that don't really need to be rescheduled
    // or inspected ever.
    None,

    HDraw,
    HBlank,

    Timer0,
    Timer1,
    Timer2,
    Timer3,

    DMA0,
    DMA1,
    DMA2,
    DMA3,

    IRQ,

    Stop,
    Halt,

    LengthEndPSG1,
    LengthEndPSG2,
    LengthEndPSG3,
    LengthEndPSG4,
    EnvelopeTickPSG1,
    EnvelopeTickPSG2,
    EnvelopeTickPSG4,
    SweepTickPSG1,
}

impl EventTag {
    pub fn timer(timer: usize) -> EventTag {
        match timer {
            0 => Self::Timer0,
            1 => Self::Timer1,
            2 => Self::Timer2,
            3 => Self::Timer3,
            _ => panic!("invalid timer for event tag"),
        }
    }

    pub fn psg_length_end(psg: PSGChannel) -> EventTag {
        match psg {
            PSGChannel::Sound1 => Self::LengthEndPSG1,
            PSGChannel::Sound2 => Self::LengthEndPSG2,
            PSGChannel::Sound3 => Self::LengthEndPSG3,
            PSGChannel::Sound4 => Self::LengthEndPSG4,
        }
    }

    pub fn psg_envelope_tick(psg: PSGChannel) -> EventTag {
        match psg {
            PSGChannel::Sound1 => Self::EnvelopeTickPSG1,
            PSGChannel::Sound2 => Self::EnvelopeTickPSG2,
            PSGChannel::Sound3 => panic!("invalid PSG for envelope tick"),
            PSGChannel::Sound4 => Self::EnvelopeTickPSG4,
        }
    }

    // pub fn dma(dma: usize) -> EventTag {
    //     match dma {
    //         0 => EventTag::DMA0,
    //         1 => EventTag::DMA1,
    //         2 => EventTag::DMA2,
    //         3 => EventTag::DMA3,
    //         _ => panic!("invalid DMA channel for event tag"),
    //     }
    // }
}

pub type EventFn = fn(gba: &mut Gba);

#[derive(Default, Clone)]
pub struct Scheduler {
    inner: Rc<RefCell<Inner>>,
}

impl Scheduler {
    pub fn schedule(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        self.inner
            .borrow_mut()
            .schedule(cycles.into(), callback, tag);
    }

    pub fn reschedule(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        let mut sched = self.inner.borrow_mut();
        sched.unschedule(tag);
        sched.schedule(cycles.into(), callback, tag);
    }

    pub fn reschedule_ealier(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        self.inner
            .borrow_mut()
            .reschedule_ealier(cycles.into(), callback, tag);
    }

    pub fn unschedule(&self, tag: EventTag) {
        self.inner.borrow_mut().unschedule(tag);
    }

    pub fn unschedule_matching<F>(&self, predicate: F)
    where
        F: FnMut(&Event) -> bool,
    {
        self.inner.borrow_mut().unschedule_matching(predicate);
    }

    pub fn next(&self, new_time: u64) -> Option<(EventFn, u64)> {
        self.inner.borrow_mut().next(new_time)
    }

    pub fn cycles_until_next_event(&self, now: u64) -> Option<Cycles> {
        self.inner.borrow().cycles_until_next_event(now)
    }

    pub fn time(&self) -> u64 {
        self.inner.borrow().time
    }

    pub(crate) fn clear(&self) {
        self.inner.borrow_mut().clear();
    }

    #[cfg(test)]
    pub fn dump(&self) {
        for (idx, event) in self.inner.borrow().events.iter().enumerate() {
            println!("EVENT{idx}: {}", event.when);
        }
    }
}

pub struct Event {
    pub when: u64,
    callback: EventFn,
    pub tag: EventTag,
}

#[derive(Default)]
struct Inner {
    events: VecDeque<Event>,
    time: u64,
}

impl Inner {
    fn schedule(&mut self, cycles: arm::Cycles, cb: EventFn, tag: EventTag) {
        let when = self.time + u32::from(cycles) as u64;

        let mut insert_idx = self.events.len();
        for (idx, event) in self.events.iter().enumerate() {
            if event.when <= when {
                continue;
            }
            insert_idx = idx;
            break;
        }

        let event = Event {
            when,
            callback: cb,
            tag,
        };
        self.events.insert(insert_idx, event);
    }

    fn reschedule_ealier(&mut self, cycles: arm::Cycles, cb: EventFn, tag: EventTag) {
        let when = self.time + u32::from(cycles) as u64;
        let removed = self.unschedule_matching(|event| event.tag == tag && event.when > when);
        if removed > 0 {
            self.schedule(cycles, cb, tag);
        }
    }

    fn unschedule_matching<F>(&mut self, mut predicate: F) -> usize
    where
        F: FnMut(&Event) -> bool,
    {
        let mut removed = 0;
        self.events.retain(|event| {
            if predicate(event) {
                removed += 1;
                false
            } else {
                true
            }
        });
        removed
    }

    fn unschedule(&mut self, tag: EventTag) {
        self.events.retain(|event| event.tag != tag);
    }

    fn next(&mut self, new_time: u64) -> Option<(EventFn, u64)> {
        if let Some(event) = self.events.front() {
            if event.when > new_time {
                self.time = new_time;
                return None;
            }
        } else {
            self.time = new_time;
            return None;
        }

        let event = self.events.pop_front().unwrap();
        self.time = event.when;
        Some((event.callback, event.when))
    }

    fn cycles_until_next_event(&self, now: u64) -> Option<Cycles> {
        if let Some(event) = self.events.front() {
            if event.when > now {
                Some(Cycles::from((event.when - now) as u32))
            } else {
                Some(Cycles::ZERO)
            }
        } else {
            None
        }
    }

    fn clear(&mut self) {
        self.events.clear();
    }
}

#[cfg(test)]
mod test {
    use crate::{scheduler::EventTag, Gba};

    use super::Scheduler;

    #[test]
    fn basic_scheduling() {
        let mut gba = Gba::default();
        let scheduler = Scheduler::default();

        scheduler.schedule(|_| data()[0] = 1, 10u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[3] = 1, 17u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[1] = 1, 13u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[2] = 1, 13u32, EventTag::HBlank);
        scheduler.dump();

        assert!(scheduler.next(6).is_none());
        assert_eq!(data()[0], 0);

        let (cb, now) = scheduler.next(10).expect("expected event");
        assert_eq!(now, 10);
        cb(&mut gba);
        assert!(scheduler.next(10).is_none());
        assert_eq!(*data(), [1, 0, 0, 0]);

        let (cb, now) = scheduler.next(13).expect("expected event");
        assert_eq!(now, 13);
        cb(&mut gba);
        assert_eq!(*data(), [1, 1, 0, 0]);
        let (cb, now) = scheduler.next(13).expect("expected event");
        assert_eq!(now, 13);
        cb(&mut gba);
        assert_eq!(*data(), [1, 1, 1, 0]);
        assert!(scheduler.next(13).is_none());

        let (cb, now) = scheduler.next(20).expect("expected event");
        assert_eq!(now, 17);
        cb(&mut gba);
        assert!(scheduler.next(20).is_none());
        assert_eq!(scheduler.time(), 20);
        assert_eq!(*data(), [1, 1, 1, 1]);

        static mut DATA: [u32; 4] = [0; 4];
        fn data() -> &'static mut [u32; 4] {
            unsafe { &mut DATA }
        }
    }
}
<commit_msg>Fix `Scheduler::reschedule_ealier`.<commit_after>use crate::memory::io::PSGChannel;

use super::Gba;
use arm::Cycles;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum EventTag {
    // Use this tag for events that don't really need to be rescheduled
    // or inspected ever.
    None,

    HDraw,
    HBlank,

    Timer0,
    Timer1,
    Timer2,
    Timer3,

    DMA0,
    DMA1,
    DMA2,
    DMA3,

    IRQ,

    Stop,
    Halt,

    LengthEndPSG1,
    LengthEndPSG2,
    LengthEndPSG3,
    LengthEndPSG4,
    EnvelopeTickPSG1,
    EnvelopeTickPSG2,
    EnvelopeTickPSG4,
    SweepTickPSG1,
    SamplePSG3,
}

impl EventTag {
    pub fn timer(timer: usize) -> EventTag {
        match timer {
            0 => Self::Timer0,
            1 => Self::Timer1,
            2 => Self::Timer2,
            3 => Self::Timer3,
            _ => panic!("invalid timer for event tag"),
        }
    }

    pub fn psg_length_end(psg: PSGChannel) -> EventTag {
        match psg {
            PSGChannel::Sound1 => Self::LengthEndPSG1,
            PSGChannel::Sound2 => Self::LengthEndPSG2,
            PSGChannel::Sound3 => Self::LengthEndPSG3,
            PSGChannel::Sound4 => Self::LengthEndPSG4,
        }
    }

    pub fn psg_envelope_tick(psg: PSGChannel) -> EventTag {
        match psg {
            PSGChannel::Sound1 => Self::EnvelopeTickPSG1,
            PSGChannel::Sound2 => Self::EnvelopeTickPSG2,
            PSGChannel::Sound3 => panic!("invalid PSG for envelope tick"),
            PSGChannel::Sound4 => Self::EnvelopeTickPSG4,
        }
    }

    // pub fn dma(dma: usize) -> EventTag {
    //     match dma {
    //         0 => EventTag::DMA0,
    //         1 => EventTag::DMA1,
    //         2 => EventTag::DMA2,
    //         3 => EventTag::DMA3,
    //         _ => panic!("invalid DMA channel for event tag"),
    //     }
    // }
}

pub type EventFn = fn(gba: &mut Gba);

#[derive(Default, Clone)]
pub struct Scheduler {
    inner: Rc<RefCell<Inner>>,
}

impl Scheduler {
    pub fn schedule(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        self.inner
            .borrow_mut()
            .schedule(cycles.into(), callback, tag);
    }

    pub fn contains_tag(&self, tag: EventTag) -> bool {
        self.inner
            .borrow()
            .contains_matching(|event| event.tag == tag)
    }

    pub fn reschedule(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        let mut sched = self.inner.borrow_mut();
        sched.unschedule(tag);
        sched.schedule(cycles.into(), callback, tag);
    }

    pub fn reschedule_ealier(&self, callback: EventFn, cycles: impl Into<Cycles>, tag: EventTag) {
        self.inner
            .borrow_mut()
            .reschedule_ealier(cycles.into(), callback, tag);
    }

    pub fn unschedule(&self, tag: EventTag) {
        self.inner.borrow_mut().unschedule(tag);
    }

    pub fn unschedule_matching<F>(&self, predicate: F)
    where
        F: FnMut(&Event) -> bool,
    {
        self.inner.borrow_mut().unschedule_matching(predicate);
    }

    pub fn next(&self, new_time: u64) -> Option<(EventFn, u64)> {
        self.inner.borrow_mut().next(new_time)
    }

    pub fn cycles_until_next_event(&self, now: u64) -> Option<Cycles> {
        self.inner.borrow().cycles_until_next_event(now)
    }

    pub fn time(&self) -> u64 {
        self.inner.borrow().time
    }

    pub(crate) fn clear(&self) {
        self.inner.borrow_mut().clear();
    }

    #[cfg(test)]
    pub fn dump(&self) {
        for (idx, event) in self.inner.borrow().events.iter().enumerate() {
            println!("EVENT{idx}: {}", event.when);
        }
    }
}

pub struct Event {
    pub when: u64,
    callback: EventFn,
    pub tag: EventTag,
}

#[derive(Default)]
struct Inner {
    events: VecDeque<Event>,
    time: u64,
}

impl Inner {
    fn schedule(&mut self, cycles: arm::Cycles, cb: EventFn, tag: EventTag) {
        let when = self.time + u32::from(cycles) as u64;

        let mut insert_idx = self.events.len();
        for (idx, event) in self.events.iter().enumerate() {
            if event.when <= when {
                continue;
            }
            insert_idx = idx;
            break;
        }

        let event = Event {
            when,
            callback: cb,
            tag,
        };
        self.events.insert(insert_idx, event);
    }

    fn reschedule_ealier(&mut self, cycles: arm::Cycles, cb: EventFn, tag: EventTag) {
        let when = self.time + u32::from(cycles) as u64;

        let mut found_matching_tag = false;
        let mut unscheduled_matching = false;
        self.unschedule_matching(|event| {
            let matching_tag = event.tag == tag;
            let remove = matching_tag && event.when > when;
            found_matching_tag |= matching_tag;
            unscheduled_matching |= remove;
            remove
        });

        if unscheduled_matching || !found_matching_tag {
            self.schedule(cycles, cb, tag);
        }
    }

    fn contains_matching<F>(&self, predicate: F) -> bool
    where
        F: FnMut(&Event) -> bool,
    {
        self.events.iter().any(predicate)
    }

    fn unschedule_matching<F>(&mut self, mut predicate: F)
    where
        F: FnMut(&Event) -> bool,
    {
        self.events.retain(|event| !predicate(event));
    }

    fn unschedule(&mut self, tag: EventTag) {
        self.events.retain(|event| event.tag != tag);
    }

    fn next(&mut self, new_time: u64) -> Option<(EventFn, u64)> {
        if let Some(event) = self.events.front() {
            if event.when > new_time {
                self.time = new_time;
                return None;
            }
        } else {
            self.time = new_time;
            return None;
        }

        let event = self.events.pop_front().unwrap();
        self.time = event.when;
        Some((event.callback, event.when))
    }

    fn cycles_until_next_event(&self, now: u64) -> Option<Cycles> {
        if let Some(event) = self.events.front() {
            if event.when > now {
                Some(Cycles::from((event.when - now) as u32))
            } else {
                Some(Cycles::ZERO)
            }
        } else {
            None
        }
    }

    fn clear(&mut self) {
        self.events.clear();
    }
}

#[cfg(test)]
mod test {
    use crate::{scheduler::EventTag, Gba};

    use super::Scheduler;

    #[test]
    fn basic_scheduling() {
        let mut gba = Gba::default();
        let scheduler = Scheduler::default();

        scheduler.schedule(|_| data()[0] = 1, 10u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[3] = 1, 17u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[1] = 1, 13u32, EventTag::HBlank);
        scheduler.schedule(|_| data()[2] = 1, 13u32, EventTag::HBlank);
        scheduler.dump();

        assert!(scheduler.next(6).is_none());
        assert_eq!(data()[0], 0);

        let (cb, now) = scheduler.next(10).expect("expected event");
        assert_eq!(now, 10);
        cb(&mut gba);
        assert!(scheduler.next(10).is_none());
        assert_eq!(*data(), [1, 0, 0, 0]);

        let (cb, now) = scheduler.next(13).expect("expected event");
        assert_eq!(now, 13);
        cb(&mut gba);
        assert_eq!(*data(), [1, 1, 0, 0]);
        let (cb, now) = scheduler.next(13).expect("expected event");
        assert_eq!(now, 13);
        cb(&mut gba);
        assert_eq!(*data(), [1, 1, 1, 0]);
        assert!(scheduler.next(13).is_none());

        let (cb, now) = scheduler.next(20).expect("expected event");
        assert_eq!(now, 17);
        cb(&mut gba);
        assert!(scheduler.next(20).is_none());
        assert_eq!(scheduler.time(), 20);
        assert_eq!(*data(), [1, 1, 1, 1]);

        static mut DATA: [u32; 4] = [0; 4];
        fn data() -> &'static mut [u32; 4] {
            unsafe { &mut DATA }
        }
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

extern crate libc;

#[macro_use]
extern crate uucore;

use std::ffi::CStr;

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SYNTAX: &str = "";
static SUMMARY: &str = "Print user's login name";
static LONG_HELP: &str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    app!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    exec();

    0
}

fn exec() {
    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }
}
<commit_msg>refactor(logname): simplify the code<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

extern crate libc;

#[macro_use]
extern crate uucore;

use std::ffi::CStr;

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SYNTAX: &str = "";
static SUMMARY: &str = "Print user's login name";
static LONG_HELP: &str = "";

pub fn uumain(args: Vec<String>) -> i32 {
    app!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }

    0
}
<|endoftext|>


<commit_before>#[derive(PartialEq)]
pub enum Condition {
    EQ, // Equal
    NE, // Not Equal
    CS, // Carry Set
    CC, // Carry clear
    MI, // Minus, negative
    PL, // Plus, positive or zero
    VS, // Overflow
    VC, // No overflow
    HI, // Unsigned higher
    LS, // Unsigned lower or same
    GE, // Signer greater than or equal
    LT, // Signed less than
    GT, // Signed greater than
    LE, // Signed less than or equal
    AL, // None or (AL = optional mnemonic extension for always)
}

impl Condition {
    pub fn value(&self) -> usize {
        match *self {
            Condition::EQ => 0b0000,
            Condition::NE => 0b0001,
            Condition::CS => 0b0010,
            Condition::CC => 0b0011,
            Condition::MI => 0b0100,
            Condition::PL => 0b0101,
            Condition::VS => 0b0110,
            Condition::VC => 0b0111,
            Condition::HI => 0b1000,
            Condition::LS => 0b1001,
            Condition::GE => 0b1010,
            Condition::LT => 0b1011,
            Condition::GT => 0b1100,
            Condition::LE => 0b1101,
            Condition::AL => 0b1110,
        }
    }

    pub fn from_u16(n: u16) -> Option<Condition> {
        match n {
            0 => Some(Condition::EQ),
            1 => Some(Condition::NE),
            2 => Some(Condition::CS),
            3 => Some(Condition::CC),
            4 => Some(Condition::MI),
            5 => Some(Condition::PL),
            6 => Some(Condition::VS),
            7 => Some(Condition::VC),
            8 => Some(Condition::HI),
            9 => Some(Condition::LS),
            10 => Some(Condition::GE),
            11 => Some(Condition::LT),
            12 => Some(Condition::GT),
            13 => Some(Condition::LE),
            14 => Some(Condition::AL),
            _ => None,
        }
    }
}
<commit_msg>Derive debug for conditions<commit_after>#[derive(PartialEq, Debug)]
pub enum Condition {
    EQ, // Equal
    NE, // Not Equal
    CS, // Carry Set
    CC, // Carry clear
    MI, // Minus, negative
    PL, // Plus, positive or zero
    VS, // Overflow
    VC, // No overflow
    HI, // Unsigned higher
    LS, // Unsigned lower or same
    GE, // Signer greater than or equal
    LT, // Signed less than
    GT, // Signed greater than
    LE, // Signed less than or equal
    AL, // None or (AL = optional mnemonic extension for always)
}

impl Condition {
    pub fn value(&self) -> usize {
        match *self {
            Condition::EQ => 0b0000,
            Condition::NE => 0b0001,
            Condition::CS => 0b0010,
            Condition::CC => 0b0011,
            Condition::MI => 0b0100,
            Condition::PL => 0b0101,
            Condition::VS => 0b0110,
            Condition::VC => 0b0111,
            Condition::HI => 0b1000,
            Condition::LS => 0b1001,
            Condition::GE => 0b1010,
            Condition::LT => 0b1011,
            Condition::GT => 0b1100,
            Condition::LE => 0b1101,
            Condition::AL => 0b1110,
        }
    }

    pub fn from_u16(n: u16) -> Option<Condition> {
        match n {
            0 => Some(Condition::EQ),
            1 => Some(Condition::NE),
            2 => Some(Condition::CS),
            3 => Some(Condition::CC),
            4 => Some(Condition::MI),
            5 => Some(Condition::PL),
            6 => Some(Condition::VS),
            7 => Some(Condition::VC),
            8 => Some(Condition::HI),
            9 => Some(Condition::LS),
            10 => Some(Condition::GE),
            11 => Some(Condition::LT),
            12 => Some(Condition::GT),
            13 => Some(Condition::LE),
            14 => Some(Condition::AL),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

extern mod grust (name="grust", vers="0.1");
extern mod gio (name="grust-Gio", vers="2.0");

use std::result::{Result,Ok};
use std::comm::{Port,stream};
use std::libc;
use std::task::*;
use std::util;
// use std::timer::recv_timeout;
// use std::uv_global_loop;
use grust::eventloop::EventLoop;

// Test timeout in milliseconds
static TEST_TIMEOUT: uint = 3000u;

fn spawn_with_future(func: ~fn()) -> Port<TaskResult> {
    let mut (port, _) = stream::<TaskResult>();
    let mut task = task();
    do task.future_result |p| { port = p; };
    task.spawn(func);
    port
}

fn tcase(test: ~fn()) {
    grust::init();

    let port = spawn_with_future(test);

    // recv_timeout is broken, see https://github.com/mozilla/rust/issues/6089
    match Some(port.recv()) /* recv_timeout(&uv_global_loop::get(), TEST_TIMEOUT, &port) */ {
        Some(Success) => {}
        Some(Failure) => {
            fail!(~"test failed");
        }
        None => {
            error!("test timed out");
            unsafe { libc::abort(); }
        }
    }
}

fn tcase_result(test: ~fn() -> Result<(),()>) {
    do tcase {
        let result = test();
        assert!(result == Ok(()));
    }
}

#[test]
fn simple() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        assert!(f.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn as_interface() {
    do tcase {
        do gio::file_new_for_path("/dev/null").as_interface |fobj| {
            let f = fobj as &gio::File;
            assert!(f.get_path().to_str() == ~"/dev/null");
        };
    }
}

#[test]
fn new_ref() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let gobj = fobj.interface().new_ref();
        let g = gobj.interface() as &gio::File;
        assert!(g.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn clone() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        do fobj.clone().as_interface |gobj| {
            let g = gobj as &gio::File;
            assert!(g.get_path().to_str() == ~"/dev/null");
        };
    }
}

#[test]
fn off_task() {
    do tcase_result {
        let f = ~gio::file_new_for_path("/dev/null");
        do try {
            let f = f.interface() as &gio::File;
            let p = f.get_path();
            assert!(p.to_str() == ~"/dev/null");
        }
    }
}

#[test]
fn off_task_as_interface() {
    do tcase_result {
        let fobj = ~gio::file_new_for_path("/dev/null");
        do try {
            do fobj.as_interface |fifa| {
                let f = fifa as &gio::File;
                let p = f.get_path();
                assert!(p.to_str() == ~"/dev/null");
            };
        }
    }
}

#[test]
fn async() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        let el = EventLoop::new();
        let elo = ~el.clone();
        do f.read_async(0, None) |obj, res| {
            let f: &gio::File = obj.cast::<gio::raw::GFile>()
                                as &gio::File;
            let in = f.read_finish(res);
            util::ignore(in);
            elo.quit();
        };
        unsafe {
            el.run();
        }
    }
}

#[test]
#[ignore]  // See https://github.com/mzabaluev/grust/issues/4
fn async_off_task() {
    do tcase {
        let fobj = ~gio::file_new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        do spawn {
            let f = fobj.interface() as &gio::File;
            let elo2 = ~elo.clone();
            do f.read_async(0, None) |obj, res| {
                let fifa: &gio::interfaces::File = obj.cast();
                let f = fifa as &gio::File;
                f.read_finish(res);
                elo2.quit();
            };
        }
        unsafe {
            el.run();
        }
    }
}

#[test]
fn async_off_stack() {
    do tcase {
        let fobj = ~gio::file_new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        do spawn_sched(SingleThreaded) {
            let f = fobj.interface() as &gio::File;
            let elo2 = ~elo.clone();
            do f.read_async(0, None) |obj, res| {
                let f = obj.cast::<gio::raw::GFile>() as &gio::File;
                f.read_finish(res);
                elo2.quit();
            };
        };
        unsafe {
            el.run();
        }
    }
}
<commit_msg>test/grust-proof.rs: No need to explicitly cast to the trait<commit_after>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

extern mod grust (name="grust", vers="0.1");
extern mod gio (name="grust-Gio", vers="2.0");

use gio::File;

use std::result::{Result,Ok};
use std::comm::{Port,stream};
use std::libc;
use std::task::*;
use std::util;
// use std::timer::recv_timeout;
// use std::uv_global_loop;
use grust::eventloop::EventLoop;

// Test timeout in milliseconds
static TEST_TIMEOUT: uint = 3000u;

fn spawn_with_future(func: ~fn()) -> Port<TaskResult> {
    let mut (port, _) = stream::<TaskResult>();
    let mut task = task();
    do task.future_result |p| { port = p; };
    task.spawn(func);
    port
}

fn tcase(test: ~fn()) {
    grust::init();

    let port = spawn_with_future(test);

    // recv_timeout is broken, see https://github.com/mozilla/rust/issues/6089
    match Some(port.recv()) /* recv_timeout(&uv_global_loop::get(), TEST_TIMEOUT, &port) */ {
        Some(Success) => {}
        Some(Failure) => {
            fail!(~"test failed");
        }
        None => {
            error!("test timed out");
            unsafe { libc::abort(); }
        }
    }
}

fn tcase_result(test: ~fn() -> Result<(),()>) {
    do tcase {
        let result = test();
        assert!(result == Ok(()));
    }
}

#[test]
fn simple() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let f = fobj.interface();
        assert!(f.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn as_interface() {
    do tcase {
        do gio::file_new_for_path("/dev/null").as_interface |f| {
            assert!(f.get_path().to_str() == ~"/dev/null");
        };
    }
}

#[test]
fn new_ref() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let gobj = fobj.interface().new_ref();
        let g = gobj.interface();
        assert!(g.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn clone() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        do fobj.clone().as_interface |g| {
            assert!(g.get_path().to_str() == ~"/dev/null");
        };
    }
}

#[test]
fn off_task() {
    do tcase_result {
        let f = ~gio::file_new_for_path("/dev/null");
        do try {
            let f = f.interface();
            let p = f.get_path();
            assert!(p.to_str() == ~"/dev/null");
        }
    }
}

#[test]
fn off_task_as_interface() {
    do tcase_result {
        let fobj = ~gio::file_new_for_path("/dev/null");
        do try {
            do fobj.as_interface |f| {
                let p = f.get_path();
                assert!(p.to_str() == ~"/dev/null");
            };
        }
    }
}

#[test]
fn async() {
    do tcase {
        let fobj = gio::file_new_for_path("/dev/null");
        let f = fobj.interface();
        let el = EventLoop::new();
        let elo = ~el.clone();
        do f.read_async(0, None) |obj, res| {
            let f: &gio::interfaces::File = obj.cast();
            let in = f.read_finish(res);
            util::ignore(in);
            elo.quit();
        };
        unsafe {
            el.run();
        }
    }
}

#[test]
#[ignore]  // See https://github.com/mzabaluev/grust/issues/4
fn async_off_task() {
    do tcase {
        let fobj = ~gio::file_new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        do spawn {
            let f = fobj.interface();
            let elo2 = ~elo.clone();
            do f.read_async(0, None) |obj, res| {
                let f: &gio::interfaces::File = obj.cast();
                f.read_finish(res);
                elo2.quit();
            };
        }
        unsafe {
            el.run();
        }
    }
}

#[test]
fn async_off_stack() {
    do tcase {
        let fobj = ~gio::file_new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        do spawn_sched(SingleThreaded) {
            let f = fobj.interface();
            let elo2 = ~elo.clone();
            do f.read_async(0, None) |obj, res| {
                let f: &gio::interfaces::File = obj.cast();
                f.read_finish(res);
                elo2.quit();
            };
        };
        unsafe {
            el.run();
        }
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use async_trait::async_trait;

use crate::{build::BuildStep, bundle::KbdgenBundle};

pub struct GenerateAndroid;

#[async_trait(?Send)]
impl BuildStep for GenerateAndroid {
    async fn build(&self, bundle: &KbdgenBundle, output_path: &Path) {}
}
<commit_msg>musings<commit_after>use std::path::Path;

use async_trait::async_trait;

use crate::{build::BuildStep, bundle::KbdgenBundle};

pub struct GenerateAndroid;

#[async_trait(?Send)]
impl BuildStep for GenerateAndroid {
    async fn build(&self, bundle: &KbdgenBundle, output_path: &Path) {
        // Files added for kbd-sme (confirm)

        /*
          (use "git add <file>..." to include in what will be committed)
            app/src/main/assets/
            app/src/main/jniLibs/arm64-v8a/
            app/src/main/jniLibs/armeabi-v7a/
            app/src/main/res/values-en/strings-appname.xml
            app/src/main/res/values-nb/strings-appname.xml
            app/src/main/res/values-nn/
            app/src/main/res/values-no/
            app/src/main/res/values-se/
            app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard1.xml
            app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard2.xml
            app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard3.xml
            app/src/main/res/xml-sw600dp/rows_northern_sami_keyboard.xml
            app/src/main/res/xml/kbd_northern_sami_keyboard.xml
            app/src/main/res/xml/keyboard_layout_set_northern_sami_keyboard.xml
            app/src/main/res/xml/rowkeys_northern_sami_keyboard1.xml
            app/src/main/res/xml/rowkeys_northern_sami_keyboard2.xml
            app/src/main/res/xml/rowkeys_northern_sami_keyboard3.xml
            app/src/main/res/xml/rows_northern_sami_keyboard.xml
        */

        // Musings

        // there are a lot of different folders, some of which seem to contain similar files

        // Modified
        // app/src/main/res/values/strings.xml
        // app/src/main/res/values-da/strings.xml
        // app/src/main/res/values-fi/strings.xml
	    // app/src/main/res/values-nb/strings.xml
	    // app/src/main/res/values-sv/strings.xml -> these seem to be based on display name
        // entries
        // subtle changes

        // modified app/src/main/res/values/strings-appname.xml

        // added
        // app/src/main/res/values-en/strings-appname.xml
	    // app/src/main/res/values-nb/strings-appname.xml

        // seem to be per major folder?
        // just seem like names for things. probably derived from project.yaml
        // since only en and nb got added

        // modified:
        // modified:   app/src/main/res/xml/method.xml
        // may just be comment removal

        // modified:   app/src/main/res/xml/spellchecker.xml
        // may just be comment removal

        // added: app/src/main/assets/
        // main thing added here seems to be a layouts.json inside of assets
        // no info here just link to the bhdfst and pahkat sme stuff

        // added app/src/main/jniLibs/arm64-v8a/
        // 2 .so files... oi...

        // added app/src/main/jniLibs/armeabi-v7a/
        // 2 .so files... oi...

        // added app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard1.xml
        // added app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard2.xml
	    // added app/src/main/res/xml-sw600dp/rowkeys_northern_sami_keyboard3.xml
        // wonder why 3 keyboards
        // looks like an actual keyboard, as in, keys, and what seems to be modifiers
        // difference between keyboards unclear

        // added app/src/main/res/xml-sw600dp/rows_northern_sami_keyboard.xml
        // seems to link these keyboards up into one thing
        // maybe the above are literal rows of keys?

        // added app/src/main/res/xml/rowkeys_northern_sami_keyboard1.xml
	    // added app/src/main/res/xml/rowkeys_northern_sami_keyboard2.xml
	    // added app/src/main/res/xml/rowkeys_northern_sami_keyboard3.xml
        /// 3 keebs again, this time without the "-sw600dp" folder name
        /// seems at least different sizing (i.e., value of latin:keyWidth differs)
        // probably same keyboards but for different screen (or default screen)

        // added app/src/main/res/xml/rows_northern_sami_keyboard.xml
        // same as above but for the non "-sw600dp" version

        // added app/src/main/res/xml/kbd_northern_sami_keyboard.xml

        // just seems to point to app/src/main/res/xml/rows_northern_sami_keyboard.xml

	    // added app/src/main/res/xml/keyboard_layout_set_northern_sami_keyboard.xml

        // modifiers????
    }
}
<|endoftext|>