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

// Coroutines represent nothing more than a context and a stack
// segment.

use std::default::Default;
use std::rt::util::min_stack;
use std::thunk::Thunk;
use std::mem::transmute;
use std::rt::unwind::try;
use std::boxed::BoxAny;
use std::ops::Deref;
use std::cell::RefCell;
use std::rc::Rc;

use context::Context;
use stack::{StackPool, Stack};

#[derive(Debug, Copy)]
pub enum State {
    Suspended,
    Running,
    Finished,
}

/// A coroutine is nothing more than a (register context, stack) pair.
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Coroutine {
    /// The segment of stack on which the task is currently running or
    /// if the task is blocked, on which the task will resume
    /// execution.
    current_stack_segment: Option<Stack>,

    /// Always valid if the task is alive and not running.
    saved_context: Context,

    /// Parent coroutine, may always be valid.
    parent: Option<Rc<RefCell<Coroutine>>>,

    /// State
    state: State
}

/// Destroy coroutine and try to reuse std::stack segment.
impl Drop for Coroutine {
    fn drop(&mut self) {
        match self.current_stack_segment.take() {
            Some(stack) => {
                COROUTINE_ENVIRONMENT.with(|env| {
                    env.borrow_mut().stack_pool.give_stack(stack);
                });
            },
            None => {}
        }
    }
}

/// Coroutine spawn options
#[derive(Debug)]
pub struct Options {
    stack_size: usize,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            stack_size: min_stack(),
        }
    }
}

/// Initialization function for make context
extern "C" fn coroutine_initialize(_: usize, f: *mut ()) -> ! {
    let func: Box<Thunk> = unsafe { transmute(f) };

    if let Err(cause) = unsafe { try(move|| func.invoke(())) } {
        error!("Panicked inside: {:?}", cause.downcast::<&str>());
    }

    COROUTINE_ENVIRONMENT.with(|env| {
        let mut env = env.borrow_mut();
        env.current_running.borrow_mut().state = State::Finished;
    });

    loop {
        Coroutine::sched();
    }
}

impl Coroutine {
    pub fn empty() -> Rc<RefCell<Coroutine>> {
        Rc::new(RefCell::new(Coroutine {
            current_stack_segment: None,
            saved_context: Context::empty(),
            parent: None,
            state: State::Running,
        }))
    }

    pub fn spawn_opts<F>(f: F, opts: Options) -> Rc<RefCell<Coroutine>>
            where F: FnOnce() + Send + 'static {
        let stack = RefCell::new(unsafe { Stack::dummy_stack() });
        COROUTINE_ENVIRONMENT.with(|env| {
            *stack.borrow_mut() = env.borrow_mut().stack_pool.take_stack(opts.stack_size);
        });

        let mut stack = stack.into_inner();
        let coro = Coroutine::empty();

        let ctx = Context::new(coroutine_initialize,
                               0,
                               f,
                               &mut stack);
        coro.borrow_mut().saved_context = ctx;
        coro.borrow_mut().current_stack_segment = Some(stack);

        Coroutine::resume(&coro);
        coro
    }

    /// Spawn a coroutine with default options
    pub fn spawn<F>(f: F) -> Rc<RefCell<Coroutine>>
            where F: FnOnce() + Send + 'static {
        Coroutine::spawn_opts(f, Default::default())
    }

    pub fn resume(coro: &Rc<RefCell<Coroutine>>) {
        match coro.borrow().state {
            State::Finished => return,
            _ => {}
        }

        COROUTINE_ENVIRONMENT.with(|env| {
            let current_running = env.borrow().current_running.clone();

            let to_coro: &mut Coroutine = unsafe { transmute(coro.borrow().deref()) };
            let from_coro: &mut Coroutine = unsafe { transmute(current_running.borrow().deref()) };

            to_coro.parent = Some(current_running.clone());
            env.borrow_mut().current_running = coro.clone();

            from_coro.state = State::Suspended;
            to_coro.state = State::Running;

            Context::swap(&mut from_coro.saved_context, &to_coro.saved_context);
        })
    }

    pub fn sched() {
        COROUTINE_ENVIRONMENT.with(|env| {
            let from_coro: &mut Coroutine = unsafe { transmute(env.borrow().current_running.deref()) };
            let to_coro: &mut Coroutine = match from_coro.parent {
                Some(ref parent) => unsafe {
                    env.borrow_mut().current_running = parent.clone();
                    transmute(parent.borrow().deref())
                },
                None => return,
            };

            match from_coro.state {
                State::Finished => {},
                _ => from_coro.state = State::Suspended,
            }
            to_coro.state = State::Running;

            Context::swap(&mut from_coro.saved_context, &to_coro.saved_context);
        });
    }

    pub fn state(&self) -> State {
        self.state
    }
}

thread_local!(static COROUTINE_ENVIRONMENT: RefCell<Environment> = RefCell::new(Environment::new()));

/// Coroutine managing environment
#[allow(raw_pointer_derive)]
#[derive(Debug)]
struct Environment {
    stack_pool: StackPool,
    current_running: Rc<RefCell<Coroutine>>,
    main_coroutine: Rc<RefCell<Coroutine>>,
}

impl Environment {
    /// Initialize a new environment
    fn new() -> Environment {
        let main_coro = Coroutine::empty();
        Environment {
            stack_pool: StackPool::new(),
            current_running: main_coro.clone(),
            main_coroutine: main_coro,
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;

    use test::Bencher;

    use coroutine::Coroutine;

    #[test]
    fn test_coroutine_basic() {
        let (tx, rx) = channel();
        Coroutine::spawn(move|| {
            tx.send(1).unwrap();
        });

        assert_eq!(rx.recv().unwrap(), 1);
    }

    #[test]
    fn test_coroutine_yield() {
        let (tx, rx) = channel();
        let coro = Coroutine::spawn(move|| {
            tx.send(1).unwrap();

            Coroutine::sched();

            tx.send(2).unwrap();
        });

        assert_eq!(rx.recv().unwrap(), 1);
        assert!(rx.try_recv().is_err());

        Coroutine::resume(&coro);

        assert_eq!(rx.recv().unwrap(), 2);
    }

    #[test]
    fn test_coroutine_spawn_inside() {
        let (tx, rx) = channel();
        Coroutine::spawn(move|| {
            tx.send(1).unwrap();

            Coroutine::spawn(move|| {
                tx.send(2).unwrap();
            });
        });

        assert_eq!(rx.recv().unwrap(), 1);
        assert_eq!(rx.recv().unwrap(), 2);
    }

    #[test]
    #[should_fail]
    fn test_coroutine_panic() {
        Coroutine::spawn(move|| {
            panic!("Panic inside a coroutine!!");
        });

        unreachable!();
    }

    #[test]
    #[should_fail]
    fn test_coroutine_child_panic() {
        Coroutine::spawn(move|| {

            Coroutine::spawn(move|| {
                panic!("Panic inside a coroutine's child!!");
            });

        });

        unreachable!();
    }

    #[test]
    fn test_coroutine_resume_after_finished() {
        let coro = Coroutine::spawn(move|| {});

        // It is already finished, but we try to resume it
        // Idealy it would come back immediately
        Coroutine::resume(&coro);

        // Again?
        Coroutine::resume(&coro);
    }

    #[bench]
    fn bench_coroutine_spawning_with_recycle(b: &mut Bencher) {
        b.iter(|| {
            Coroutine::spawn(move|| {});
        });
    }

    #[bench]
    fn bench_coroutine_counting(b: &mut Bencher) {
        b.iter(|| {
            const MAX_NUMBER: usize = 100;
            let (tx, rx) = channel();

            let coro = Coroutine::spawn(move|| {
                for _ in 0..MAX_NUMBER {
                    tx.send(1).unwrap();
                    Coroutine::sched();
                }
            });

            let result = rx.iter().fold(0, |a, b| {
                Coroutine::resume(&coro);
                a + b
            });
            assert_eq!(result, MAX_NUMBER);
        });
    }
}
<commit_msg>a current function may be useful<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Coroutines represent nothing more than a context and a stack
// segment.

use std::default::Default;
use std::rt::util::min_stack;
use std::thunk::Thunk;
use std::mem::transmute;
use std::rt::unwind::try;
use std::boxed::BoxAny;
use std::ops::Deref;
use std::cell::RefCell;
use std::rc::Rc;

use context::Context;
use stack::{StackPool, Stack};

#[derive(Debug, Copy)]
pub enum State {
    Suspended,
    Running,
    Finished,
}

/// A coroutine is nothing more than a (register context, stack) pair.
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Coroutine {
    /// The segment of stack on which the task is currently running or
    /// if the task is blocked, on which the task will resume
    /// execution.
    current_stack_segment: Option<Stack>,

    /// Always valid if the task is alive and not running.
    saved_context: Context,

    /// Parent coroutine, may always be valid.
    parent: Option<Rc<RefCell<Coroutine>>>,

    /// State
    state: State
}

/// Destroy coroutine and try to reuse std::stack segment.
impl Drop for Coroutine {
    fn drop(&mut self) {
        match self.current_stack_segment.take() {
            Some(stack) => {
                COROUTINE_ENVIRONMENT.with(|env| {
                    env.borrow_mut().stack_pool.give_stack(stack);
                });
            },
            None => {}
        }
    }
}

/// Coroutine spawn options
#[derive(Debug)]
pub struct Options {
    stack_size: usize,
}

impl Default for Options {
    fn default() -> Options {
        Options {
            stack_size: min_stack(),
        }
    }
}

/// Initialization function for make context
extern "C" fn coroutine_initialize(_: usize, f: *mut ()) -> ! {
    let func: Box<Thunk> = unsafe { transmute(f) };

    if let Err(cause) = unsafe { try(move|| func.invoke(())) } {
        error!("Panicked inside: {:?}", cause.downcast::<&str>());
    }

    COROUTINE_ENVIRONMENT.with(|env| {
        let mut env = env.borrow_mut();
        env.current_running.borrow_mut().state = State::Finished;
    });

    loop {
        Coroutine::sched();
    }
}

impl Coroutine {
    pub fn empty() -> Rc<RefCell<Coroutine>> {
        Rc::new(RefCell::new(Coroutine {
            current_stack_segment: None,
            saved_context: Context::empty(),
            parent: None,
            state: State::Running,
        }))
    }

    pub fn spawn_opts<F>(f: F, opts: Options) -> Rc<RefCell<Coroutine>>
            where F: FnOnce() + Send + 'static {
        let stack = RefCell::new(unsafe { Stack::dummy_stack() });
        COROUTINE_ENVIRONMENT.with(|env| {
            *stack.borrow_mut() = env.borrow_mut().stack_pool.take_stack(opts.stack_size);
        });

        let mut stack = stack.into_inner();
        let coro = Coroutine::empty();

        let ctx = Context::new(coroutine_initialize,
                               0,
                               f,
                               &mut stack);
        coro.borrow_mut().saved_context = ctx;
        coro.borrow_mut().current_stack_segment = Some(stack);

        Coroutine::resume(&coro);
        coro
    }

    /// Spawn a coroutine with default options
    pub fn spawn<F>(f: F) -> Rc<RefCell<Coroutine>>
            where F: FnOnce() + Send + 'static {
        Coroutine::spawn_opts(f, Default::default())
    }

    pub fn resume(coro: &Rc<RefCell<Coroutine>>) {
        match coro.borrow().state {
            State::Finished => return,
            _ => {}
        }

        COROUTINE_ENVIRONMENT.with(|env| {
            let current_running = env.borrow().current_running.clone();

            let to_coro: &mut Coroutine = unsafe { transmute(coro.borrow().deref()) };
            let from_coro: &mut Coroutine = unsafe { transmute(current_running.borrow().deref()) };

            to_coro.parent = Some(current_running.clone());
            env.borrow_mut().current_running = coro.clone();

            from_coro.state = State::Suspended;
            to_coro.state = State::Running;

            Context::swap(&mut from_coro.saved_context, &to_coro.saved_context);
        })
    }

    pub fn sched() {
        COROUTINE_ENVIRONMENT.with(|env| {
            let from_coro: &mut Coroutine = unsafe { transmute(env.borrow().current_running.deref()) };
            let to_coro: &mut Coroutine = match from_coro.parent {
                Some(ref parent) => unsafe {
                    env.borrow_mut().current_running = parent.clone();
                    transmute(parent.borrow().deref())
                },
                None => return,
            };

            match from_coro.state {
                State::Finished => {},
                _ => from_coro.state = State::Suspended,
            }
            to_coro.state = State::Running;

            Context::swap(&mut from_coro.saved_context, &to_coro.saved_context);
        });
    }

    pub fn current() -> Rc<RefCell<Coroutine>> {
        let opt = RefCell::new(None);
        COROUTINE_ENVIRONMENT.with(|env| {
            *opt.borrow_mut() = Some(env.borrow().current_running.clone());
        });
        opt.into_inner().unwrap()
    }

    pub fn state(&self) -> State {
        self.state
    }
}

thread_local!(static COROUTINE_ENVIRONMENT: RefCell<Environment> = RefCell::new(Environment::new()));

/// Coroutine managing environment
#[allow(raw_pointer_derive)]
#[derive(Debug)]
struct Environment {
    stack_pool: StackPool,
    current_running: Rc<RefCell<Coroutine>>,
    main_coroutine: Rc<RefCell<Coroutine>>,
}

impl Environment {
    /// Initialize a new environment
    fn new() -> Environment {
        let main_coro = Coroutine::empty();
        Environment {
            stack_pool: StackPool::new(),
            current_running: main_coro.clone(),
            main_coroutine: main_coro,
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;

    use test::Bencher;

    use coroutine::Coroutine;

    #[test]
    fn test_coroutine_basic() {
        let (tx, rx) = channel();
        Coroutine::spawn(move|| {
            tx.send(1).unwrap();
        });

        assert_eq!(rx.recv().unwrap(), 1);
    }

    #[test]
    fn test_coroutine_yield() {
        let (tx, rx) = channel();
        let coro = Coroutine::spawn(move|| {
            tx.send(1).unwrap();

            Coroutine::sched();

            tx.send(2).unwrap();
        });

        assert_eq!(rx.recv().unwrap(), 1);
        assert!(rx.try_recv().is_err());

        Coroutine::resume(&coro);

        assert_eq!(rx.recv().unwrap(), 2);
    }

    #[test]
    fn test_coroutine_spawn_inside() {
        let (tx, rx) = channel();
        Coroutine::spawn(move|| {
            tx.send(1).unwrap();

            Coroutine::spawn(move|| {
                tx.send(2).unwrap();
            });
        });

        assert_eq!(rx.recv().unwrap(), 1);
        assert_eq!(rx.recv().unwrap(), 2);
    }

    #[test]
    #[should_fail]
    fn test_coroutine_panic() {
        Coroutine::spawn(move|| {
            panic!("Panic inside a coroutine!!");
        });

        unreachable!();
    }

    #[test]
    #[should_fail]
    fn test_coroutine_child_panic() {
        Coroutine::spawn(move|| {

            Coroutine::spawn(move|| {
                panic!("Panic inside a coroutine's child!!");
            });

        });

        unreachable!();
    }

    #[test]
    fn test_coroutine_resume_after_finished() {
        let coro = Coroutine::spawn(move|| {});

        // It is already finished, but we try to resume it
        // Idealy it would come back immediately
        Coroutine::resume(&coro);

        // Again?
        Coroutine::resume(&coro);
    }

    #[bench]
    fn bench_coroutine_spawning_with_recycle(b: &mut Bencher) {
        b.iter(|| {
            Coroutine::spawn(move|| {});
        });
    }

    #[bench]
    fn bench_coroutine_counting(b: &mut Bencher) {
        b.iter(|| {
            const MAX_NUMBER: usize = 100;
            let (tx, rx) = channel();

            let coro = Coroutine::spawn(move|| {
                for _ in 0..MAX_NUMBER {
                    tx.send(1).unwrap();
                    Coroutine::sched();
                }
            });

            let result = rx.iter().fold(0, |a, b| {
                Coroutine::resume(&coro);
                a + b
            });
            assert_eq!(result, MAX_NUMBER);
        });
    }
}
<|endoftext|>


<commit_before>#![feature(asm,no_std,lang_items,core)]
#![no_std]
#![crate_name="kernel"]

#![allow(unused_must_use)]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

macro_rules! println {
    ($($arg:tt)*) => (unsafe { use ::core::fmt::Write; writeln!(::SP.as_mut().unwrap(), $($arg)*) })
}

mod lang;
pub mod io;
mod dev;
mod mem;

#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Eq)]
enum EfiMemoryType {
	EfiReservedMemoryType,
	EfiLoaderCode,
	EfiLoaderData,
	EfiBootServicesCode,
	EfiBootServicesData,
	EfiRuntimeServicesCode,
	EfiRuntimeServicesData,
	EfiConventionalMemory,
	EfiUnusableMemory,
	EfiACPIReclaimMemory,
	EfiACPIMemoryNVS,
	EfiMemoryMappedIO,
	EfiMemoryMappedIOPortSpace,
	EfiPalCode,
	EfiMaxMemoryType,
}

#[repr(C)]
struct EfiMemoryDescriptor {
    type_: EfiMemoryType,
    phys_start: u64,
    virt_start: u64,
    npages: u64,
    attrs: u64,
}

#[repr(C)]
pub struct BootProto {
    mem_map: *const EfiMemoryDescriptor,
    map_size: u64,
    map_ent_size: u64
}

struct BootProtoIter {
    map: *const EfiMemoryDescriptor,
    size: u64,
    ent_size: u64,
    idx: u64,
}

pub static mut SP: Option<dev::serial::SerialPort> = None;

impl Iterator for BootProtoIter {
    type Item = *const EfiMemoryDescriptor;
    fn next(&mut self) -> Option<*const EfiMemoryDescriptor> {
        if self.idx * self.ent_size >= self.size {
            None
        } else {
            let r = Some((self.map as u64 + (self.idx*self.ent_size)) as *const EfiMemoryDescriptor);
            self.idx += 1;
            r
        }
    }
}

#[no_mangle]
pub fn main(bootproto: *const BootProto) {
    let sp = dev::serial::SerialPort::init(0x3F8);
    unsafe {
        SP = Some(sp);
    }

    println!("KERNEL START");
    //panic!();

    let mut max_rg_sz = 0usize;
    let mut max_rg_ptr = 0usize;

    unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx: 0};

        for region in bpi {
            println!("{:?} from {:x} -> {:x} (sz {:x})", (*region).type_, (*region).phys_start, (*region).phys_start+((*region).npages*4096), (*region).npages*4096);
            if((*region).type_ == EfiMemoryType::EfiConventionalMemory && ((*region).npages*4096) as usize > max_rg_sz) {
                max_rg_sz = ((*region).npages*4096) as usize;
                max_rg_ptr = (*region).phys_start as usize;
            }
        }
    }

    let maxmem = unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx:0 };
        let last = bpi.last().unwrap();
        ((*last).phys_start+((*last).npages*4096)) as usize
    };

    println!("maxmem is {:x}", maxmem);

    let mut heap = mem::Heap::new(maxmem, max_rg_ptr, max_rg_sz);
    let mut pg5 = 0;
    println!("Heap testing: ");
    for i in (0..15) {
        println!("Allocating span of 1024 pages (4M)...");
        match heap.alloc_pages(1024) {
            Some(page) => {
                println!("...success, allocated page {:x} at {:x}", page, page << 12);
                if i == 5 {
                    pg5 = page;
                };
            },
            None => {
                println!("...failed (out of memory?)");
            }
        };
    }

    println!("Deallocating allocation 5 (page {:x} at {:x})...", pg5, pg5 << 12);

    heap.clear_used_range(pg5, 1024);

    println!("Allocating a 2048 (8M) span (order 11)...");

    match heap.alloc_pages(2048) {
        Some(page) => println!("...success, allocated page {:x} at {:x}", page, page << 12),
        None => println!("...failed."),
    };

    println!("Allocating one more 1024 (4M) span (order 10)...");

    match heap.alloc_pages(1024) {
        Some(page) => println!("...success, allocated page {:x} at {:x}", page, page << 12),
        None => println!("...failed."),
    };

    panic!("\n\nReached end of main - HALT");
    loop {
        unsafe {
            asm!("hlt");
        }
    }
}
<commit_msg>fix excessive printing, halting<commit_after>#![feature(asm,no_std,lang_items,core)]
#![no_std]
#![crate_name="kernel"]

#![allow(unused_must_use)]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

macro_rules! println {
    ($($arg:tt)*) => (unsafe { use ::core::fmt::Write; writeln!(::SP.as_mut().unwrap(), $($arg)*) })
}

mod lang;
pub mod io;
mod dev;
mod mem;

#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Eq)]
enum EfiMemoryType {
	EfiReservedMemoryType,
	EfiLoaderCode,
	EfiLoaderData,
	EfiBootServicesCode,
	EfiBootServicesData,
	EfiRuntimeServicesCode,
	EfiRuntimeServicesData,
	EfiConventionalMemory,
	EfiUnusableMemory,
	EfiACPIReclaimMemory,
	EfiACPIMemoryNVS,
	EfiMemoryMappedIO,
	EfiMemoryMappedIOPortSpace,
	EfiPalCode,
	EfiMaxMemoryType,
}

#[repr(C)]
struct EfiMemoryDescriptor {
    type_: EfiMemoryType,
    phys_start: u64,
    virt_start: u64,
    npages: u64,
    attrs: u64,
}

#[repr(C)]
pub struct BootProto {
    mem_map: *const EfiMemoryDescriptor,
    map_size: u64,
    map_ent_size: u64
}

struct BootProtoIter {
    map: *const EfiMemoryDescriptor,
    size: u64,
    ent_size: u64,
    idx: u64,
}

pub static mut SP: Option<dev::serial::SerialPort> = None;

impl Iterator for BootProtoIter {
    type Item = *const EfiMemoryDescriptor;
    fn next(&mut self) -> Option<*const EfiMemoryDescriptor> {
        if self.idx * self.ent_size >= self.size {
            None
        } else {
            let r = Some((self.map as u64 + (self.idx*self.ent_size)) as *const EfiMemoryDescriptor);
            self.idx += 1;
            r
        }
    }
}

#[no_mangle]
pub fn main(bootproto: *const BootProto) {
    let sp = dev::serial::SerialPort::init(0x3F8);
    unsafe {
        SP = Some(sp);
    }

    println!("KERNEL START");

    let mut max_rg_sz = 0usize;
    let mut max_rg_ptr = 0usize;

    unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx: 0};

        for region in bpi {
            println!("{:?} from {:x} -> {:x} (sz {:x})", (*region).type_, (*region).phys_start, (*region).phys_start+((*region).npages*4096), (*region).npages*4096);
            if((*region).type_ == EfiMemoryType::EfiConventionalMemory && ((*region).npages*4096) as usize > max_rg_sz) {
                max_rg_sz = ((*region).npages*4096) as usize;
                max_rg_ptr = (*region).phys_start as usize;
            }
        }
    }

    let maxmem = unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx:0 };
        let last = bpi.last().unwrap();
        ((*last).phys_start+((*last).npages*4096)) as usize
    };

    println!("maxmem is {:x}", maxmem);

    let mut heap = mem::Heap::new(maxmem, max_rg_ptr, max_rg_sz);
    let mut pg5 = 0;
    println!("Heap testing: ");
    for i in (0..15) {
        println!("Allocating span of 1024 pages (4M)...");
        match heap.alloc_pages(1024) {
            Some(page) => {
                println!("...success, allocated page {:x} at {:x}", page, page << 12);
                if i == 5 {
                    pg5 = page;
                };
            },
            None => {
                println!("...failed (out of memory?)");
            }
        };
    }

    println!("Deallocating allocation 5 (page {:x} at {:x})...", pg5, pg5 << 12);

    heap.clear_used_range(pg5, 1024);

    println!("Allocating a 2048 (8M) span (order 11)...");

    match heap.alloc_pages(2048) {
        Some(page) => println!("...success, allocated page {:x} at {:x}", page, page << 12),
        None => println!("...failed."),
    };

    println!("Allocating one more 1024 (4M) span (order 10)...");

    match heap.alloc_pages(1024) {
        Some(page) => println!("...success, allocated page {:x} at {:x}", page, page << 12),
        None => println!("...failed."),
    };

    panic!("Reached end of main");
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate time;
extern crate libc;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};

struct JsonFilesystem;

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(JsonFilesystem, &mountpoint, &[]);
}
<commit_msg>Dummy readdir.<commit_after>extern crate fuse;
extern crate time;
extern crate libc;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};

struct JsonFilesystem;

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        reply.error(ENOSYS);
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(JsonFilesystem, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>//! Types for the *m.room.encrypted* event.

use std::collections::BTreeMap;

use js_int::UInt;
use ruma_events_macros::EventContent;
use ruma_identifiers::DeviceIdBox;
use serde::{Deserialize, Serialize};

use crate::{
    room::relationships::{relation_serde, Relation},
    MessageEvent,
};

/// An event that has been encrypted.
pub type EncryptedEvent = MessageEvent<EncryptedEventContent>;

/// The encryption scheme for `EncryptedEventContent`
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "algorithm")]
pub enum EncryptedEventScheme {
    /// An event encrypted with *m.olm.v1.curve25519-aes-sha2*.
    #[serde(rename = "m.olm.v1.curve25519-aes-sha2")]
    OlmV1Curve25519AesSha2(OlmV1Curve25519AesSha2Content),

    /// An event encrypted with *m.megolm.v1.aes-sha2*.
    #[serde(rename = "m.megolm.v1.aes-sha2")]
    MegolmV1AesSha2(MegolmV1AesSha2Content),
}

/// The content payload for `EncryptedEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.encrypted", kind = Message, kind = ToDevice)]
pub struct EncryptedEventContent {
    /// Encrypted event content
    #[serde(flatten)]
    pub scheme: EncryptedEventScheme,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies
    #[serde(flatten, with = "relation_serde", skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

impl EncryptedEventContent {
    /// Creates a new `EncryptedEventContent` with the given scheme and relation.
    pub fn new(scheme: EncryptedEventScheme, relates_to: Option<Relation>) -> Self {
        Self { scheme, relates_to }
    }
}

impl From<EncryptedEventScheme> for EncryptedEventContent {
    fn from(scheme: EncryptedEventScheme) -> Self {
        Self { scheme, relates_to: None }
    }
}

/// The to-device version of the payload for the `EncryptedEvent`.
pub type EncryptedToDeviceEventContent = EncryptedEventContent;

/// The payload for `EncryptedEvent` using the *m.olm.v1.curve25519-aes-sha2* algorithm.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct OlmV1Curve25519AesSha2Content {
    /// A map from the recipient Curve25519 identity key to ciphertext information.
    pub ciphertext: BTreeMap<String, CiphertextInfo>,

    /// The Curve25519 key of the sender.
    pub sender_key: String,
}

impl OlmV1Curve25519AesSha2Content {
    /// Creates a new `OlmV1Curve25519AesSha2Content` with the given ciphertext and sender key.
    pub fn new(ciphertext: BTreeMap<String, CiphertextInfo>, sender_key: String) -> Self {
        Self { ciphertext, sender_key }
    }
}

/// Ciphertext information holding the ciphertext and message type.
///
/// Used for messages encrypted with the *m.olm.v1.curve25519-aes-sha2* algorithm.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CiphertextInfo {
    /// The encrypted payload.
    pub body: String,

    /// The Olm message type.
    #[serde(rename = "type")]
    pub message_type: UInt,
}

impl CiphertextInfo {
    /// Creates a new `CiphertextInfo` with the given body and type.
    pub fn new(body: String, message_type: UInt) -> Self {
        Self { body, message_type }
    }
}

/// The payload for `EncryptedEvent` using the *m.megolm.v1.aes-sha2* algorithm.
///
/// To create an instance of this type, first create a `MegolmV1AesSha2ContentInit` and convert it
/// via `MegolmV1AesSha2Content::from` / `.into()`.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct MegolmV1AesSha2Content {
    /// The encrypted content of the event.
    pub ciphertext: String,

    /// The Curve25519 key of the sender.
    pub sender_key: String,

    /// The ID of the sending device.
    pub device_id: DeviceIdBox,

    /// The ID of the session used to encrypt the message.
    pub session_id: String,
}

/// Mandatory initial set of fields of `MegolmV1AesSha2Content`.
///
/// This struct will not be updated even if additional fields are added to `MegolmV1AesSha2Content`
/// in a new (non-breaking) release of the Matrix specification.
#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct MegolmV1AesSha2ContentInit {
    /// The encrypted content of the event.
    pub ciphertext: String,

    /// The Curve25519 key of the sender.
    pub sender_key: String,

    /// The ID of the sending device.
    pub device_id: DeviceIdBox,

    /// The ID of the session used to encrypt the message.
    pub session_id: String,
}

impl From<MegolmV1AesSha2ContentInit> for MegolmV1AesSha2Content {
    /// Creates a new `MegolmV1AesSha2Content` from the given init struct.
    fn from(init: MegolmV1AesSha2ContentInit) -> Self {
        let MegolmV1AesSha2ContentInit { ciphertext, sender_key, device_id, session_id } = init;
        Self { ciphertext, sender_key, device_id, session_id }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_serde::Raw;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{EncryptedEventContent, EncryptedEventScheme, MegolmV1AesSha2Content};
    use crate::room::relationships::{InReplyTo, Relation};
    use ruma_identifiers::event_id;

    #[test]
    fn serialization() {
        let key_verification_start_content = EncryptedEventContent {
            scheme: EncryptedEventScheme::MegolmV1AesSha2(MegolmV1AesSha2Content {
                ciphertext: "ciphertext".into(),
                sender_key: "sender_key".into(),
                device_id: "device_id".into(),
                session_id: "session_id".into(),
            }),
            relates_to: Some(Relation::Reply {
                in_reply_to: InReplyTo { event_id: event_id!("$h29iv0s8:example.com") },
            }),
        };

        let json_data = json!({
            "algorithm": "m.megolm.v1.aes-sha2",
            "ciphertext": "ciphertext",
            "sender_key": "sender_key",
            "device_id": "device_id",
            "session_id": "session_id",
            "m.relates_to": {
                "m.in_reply_to": {
                    "event_id": "$h29iv0s8:example.com"
                }
            },
        });

        assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
    }

    #[test]
    fn deserialization() {
        let json_data = json!({
            "algorithm": "m.megolm.v1.aes-sha2",
            "ciphertext": "ciphertext",
            "sender_key": "sender_key",
            "device_id": "device_id",
            "session_id": "session_id",
            "m.relates_to": {
                "m.in_reply_to": {
                    "event_id": "$h29iv0s8:example.com"
                }
            },
        });

        let content: EncryptedEventContent =
            from_json_value::<Raw<EncryptedEventContent>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap();

        assert_matches!(
            content.scheme,
            EncryptedEventScheme::MegolmV1AesSha2(MegolmV1AesSha2Content {
                ciphertext,
                sender_key,
                device_id,
                session_id,
            }) if ciphertext == "ciphertext"
                && sender_key == "sender_key"
                && device_id == "device_id"
                && session_id == "session_id"
        );

        assert_matches!(
            content.relates_to,
            Some(Relation::Reply { in_reply_to })
                if in_reply_to.event_id == event_id!("$h29iv0s8:example.com")
        );
    }

    #[test]
    fn deserialization_olm() {
        let json_data = json!({
            "sender_key": "test_key",
            "ciphertext": {
                "test_curve_key": {
                    "body": "encrypted_body",
                    "type": 1
                }
            },
            "algorithm": "m.olm.v1.curve25519-aes-sha2"
        });
        let content = from_json_value::<Raw<EncryptedEventContent>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap();

        match content.scheme {
            EncryptedEventScheme::OlmV1Curve25519AesSha2(c) => {
                assert_eq!(c.sender_key, "test_key");
                assert_eq!(c.ciphertext.len(), 1);
                assert_eq!(c.ciphertext["test_curve_key"].body, "encrypted_body");
                assert_eq!(c.ciphertext["test_curve_key"].message_type, 1_u16.into());
            }
            _ => panic!("Wrong content type, expected a OlmV1 content"),
        }
    }

    #[test]
    fn deserialization_failure() {
        assert!(from_json_value::<Raw<EncryptedEventContent>>(
            json!({ "algorithm": "m.megolm.v1.aes-sha2" })
        )
        .unwrap()
        .deserialize()
        .is_err());
    }
}
<commit_msg>events: More consistent item ordering for room::encrypted<commit_after>//! Types for the *m.room.encrypted* event.

use std::collections::BTreeMap;

use js_int::UInt;
use ruma_events_macros::EventContent;
use ruma_identifiers::DeviceIdBox;
use serde::{Deserialize, Serialize};

use crate::{
    room::relationships::{relation_serde, Relation},
    MessageEvent,
};

/// An event that has been encrypted.
pub type EncryptedEvent = MessageEvent<EncryptedEventContent>;

/// The content payload for `EncryptedEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.encrypted", kind = Message, kind = ToDevice)]
pub struct EncryptedEventContent {
    /// Encrypted event content
    #[serde(flatten)]
    pub scheme: EncryptedEventScheme,

    /// Information about related messages for [rich replies].
    ///
    /// [rich replies]: https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies
    #[serde(flatten, with = "relation_serde", skip_serializing_if = "Option::is_none")]
    pub relates_to: Option<Relation>,
}

/// The to-device version of the payload for the `EncryptedEvent`.
pub type EncryptedToDeviceEventContent = EncryptedEventContent;

impl EncryptedEventContent {
    /// Creates a new `EncryptedEventContent` with the given scheme and relation.
    pub fn new(scheme: EncryptedEventScheme, relates_to: Option<Relation>) -> Self {
        Self { scheme, relates_to }
    }
}

impl From<EncryptedEventScheme> for EncryptedEventContent {
    fn from(scheme: EncryptedEventScheme) -> Self {
        Self { scheme, relates_to: None }
    }
}

/// The encryption scheme for `EncryptedEventContent`
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "algorithm")]
pub enum EncryptedEventScheme {
    /// An event encrypted with *m.olm.v1.curve25519-aes-sha2*.
    #[serde(rename = "m.olm.v1.curve25519-aes-sha2")]
    OlmV1Curve25519AesSha2(OlmV1Curve25519AesSha2Content),

    /// An event encrypted with *m.megolm.v1.aes-sha2*.
    #[serde(rename = "m.megolm.v1.aes-sha2")]
    MegolmV1AesSha2(MegolmV1AesSha2Content),
}

/// The payload for `EncryptedEvent` using the *m.olm.v1.curve25519-aes-sha2* algorithm.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct OlmV1Curve25519AesSha2Content {
    /// A map from the recipient Curve25519 identity key to ciphertext information.
    pub ciphertext: BTreeMap<String, CiphertextInfo>,

    /// The Curve25519 key of the sender.
    pub sender_key: String,
}

impl OlmV1Curve25519AesSha2Content {
    /// Creates a new `OlmV1Curve25519AesSha2Content` with the given ciphertext and sender key.
    pub fn new(ciphertext: BTreeMap<String, CiphertextInfo>, sender_key: String) -> Self {
        Self { ciphertext, sender_key }
    }
}

/// Ciphertext information holding the ciphertext and message type.
///
/// Used for messages encrypted with the *m.olm.v1.curve25519-aes-sha2* algorithm.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CiphertextInfo {
    /// The encrypted payload.
    pub body: String,

    /// The Olm message type.
    #[serde(rename = "type")]
    pub message_type: UInt,
}

impl CiphertextInfo {
    /// Creates a new `CiphertextInfo` with the given body and type.
    pub fn new(body: String, message_type: UInt) -> Self {
        Self { body, message_type }
    }
}

/// The payload for `EncryptedEvent` using the *m.megolm.v1.aes-sha2* algorithm.
///
/// To create an instance of this type, first create a `MegolmV1AesSha2ContentInit` and convert it
/// via `MegolmV1AesSha2Content::from` / `.into()`.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct MegolmV1AesSha2Content {
    /// The encrypted content of the event.
    pub ciphertext: String,

    /// The Curve25519 key of the sender.
    pub sender_key: String,

    /// The ID of the sending device.
    pub device_id: DeviceIdBox,

    /// The ID of the session used to encrypt the message.
    pub session_id: String,
}

/// Mandatory initial set of fields of `MegolmV1AesSha2Content`.
///
/// This struct will not be updated even if additional fields are added to `MegolmV1AesSha2Content`
/// in a new (non-breaking) release of the Matrix specification.
#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct MegolmV1AesSha2ContentInit {
    /// The encrypted content of the event.
    pub ciphertext: String,

    /// The Curve25519 key of the sender.
    pub sender_key: String,

    /// The ID of the sending device.
    pub device_id: DeviceIdBox,

    /// The ID of the session used to encrypt the message.
    pub session_id: String,
}

impl From<MegolmV1AesSha2ContentInit> for MegolmV1AesSha2Content {
    /// Creates a new `MegolmV1AesSha2Content` from the given init struct.
    fn from(init: MegolmV1AesSha2ContentInit) -> Self {
        let MegolmV1AesSha2ContentInit { ciphertext, sender_key, device_id, session_id } = init;
        Self { ciphertext, sender_key, device_id, session_id }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use ruma_serde::Raw;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{EncryptedEventContent, EncryptedEventScheme, MegolmV1AesSha2Content};
    use crate::room::relationships::{InReplyTo, Relation};
    use ruma_identifiers::event_id;

    #[test]
    fn serialization() {
        let key_verification_start_content = EncryptedEventContent {
            scheme: EncryptedEventScheme::MegolmV1AesSha2(MegolmV1AesSha2Content {
                ciphertext: "ciphertext".into(),
                sender_key: "sender_key".into(),
                device_id: "device_id".into(),
                session_id: "session_id".into(),
            }),
            relates_to: Some(Relation::Reply {
                in_reply_to: InReplyTo { event_id: event_id!("$h29iv0s8:example.com") },
            }),
        };

        let json_data = json!({
            "algorithm": "m.megolm.v1.aes-sha2",
            "ciphertext": "ciphertext",
            "sender_key": "sender_key",
            "device_id": "device_id",
            "session_id": "session_id",
            "m.relates_to": {
                "m.in_reply_to": {
                    "event_id": "$h29iv0s8:example.com"
                }
            },
        });

        assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
    }

    #[test]
    fn deserialization() {
        let json_data = json!({
            "algorithm": "m.megolm.v1.aes-sha2",
            "ciphertext": "ciphertext",
            "sender_key": "sender_key",
            "device_id": "device_id",
            "session_id": "session_id",
            "m.relates_to": {
                "m.in_reply_to": {
                    "event_id": "$h29iv0s8:example.com"
                }
            },
        });

        let content: EncryptedEventContent =
            from_json_value::<Raw<EncryptedEventContent>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap();

        assert_matches!(
            content.scheme,
            EncryptedEventScheme::MegolmV1AesSha2(MegolmV1AesSha2Content {
                ciphertext,
                sender_key,
                device_id,
                session_id,
            }) if ciphertext == "ciphertext"
                && sender_key == "sender_key"
                && device_id == "device_id"
                && session_id == "session_id"
        );

        assert_matches!(
            content.relates_to,
            Some(Relation::Reply { in_reply_to })
                if in_reply_to.event_id == event_id!("$h29iv0s8:example.com")
        );
    }

    #[test]
    fn deserialization_olm() {
        let json_data = json!({
            "sender_key": "test_key",
            "ciphertext": {
                "test_curve_key": {
                    "body": "encrypted_body",
                    "type": 1
                }
            },
            "algorithm": "m.olm.v1.curve25519-aes-sha2"
        });
        let content = from_json_value::<Raw<EncryptedEventContent>>(json_data)
            .unwrap()
            .deserialize()
            .unwrap();

        match content.scheme {
            EncryptedEventScheme::OlmV1Curve25519AesSha2(c) => {
                assert_eq!(c.sender_key, "test_key");
                assert_eq!(c.ciphertext.len(), 1);
                assert_eq!(c.ciphertext["test_curve_key"].body, "encrypted_body");
                assert_eq!(c.ciphertext["test_curve_key"].message_type, 1_u16.into());
            }
            _ => panic!("Wrong content type, expected a OlmV1 content"),
        }
    }

    #[test]
    fn deserialization_failure() {
        assert!(from_json_value::<Raw<EncryptedEventContent>>(
            json!({ "algorithm": "m.megolm.v1.aes-sha2" })
        )
        .unwrap()
        .deserialize()
        .is_err());
    }
}
<|endoftext|>


<commit_before>use std::io::{self};

use core::convert::TryInto;
use std::mem;
use lz4_flex::{compress_into, decompress_into};

#[inline]
#[allow(clippy::uninit_vec)]
pub fn compress(uncompressed: &[u8], compressed: &mut Vec<u8>) -> io::Result<()> {
    compressed.clear();
    let maximum_ouput_size = mem::size_of::<u32>() + lz4_flex::block::get_maximum_output_size(uncompressed.len());
    compressed.reserve(maximum_ouput_size);
    unsafe {
        compressed.set_len(maximum_ouput_size);
    }
    let bytes_written = compress_into(uncompressed, &mut compressed[4..])
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    let num_bytes = uncompressed.len() as u32;
    compressed[0..4].copy_from_slice(&num_bytes.to_le_bytes());
    unsafe {
        compressed.set_len(bytes_written + mem::size_of::<u32>());
    }
    Ok(())
}

#[inline]
#[allow(clippy::uninit_vec)]
pub fn decompress(compressed: &[u8], decompressed: &mut Vec<u8>) -> io::Result<()> {
    decompressed.clear();
    let uncompressed_size_bytes: &[u8; 4] = compressed
        .get(..4)
        .ok_or(io::ErrorKind::InvalidData)?
        .try_into()
        .unwrap();
    let uncompressed_size = u32::from_le_bytes(*uncompressed_size_bytes) as usize;
    decompressed.reserve(uncompressed_size);
    unsafe {
        decompressed.set_len(uncompressed_size);
    }
    let bytes_written = decompress_into(&compressed[4..], decompressed)
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    if bytes_written != uncompressed_size {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "doc store block not completely decompressed, data corruption".to_string(),
        ));
    }
    Ok(())
}
<commit_msg>Cargo fmt<commit_after>use std::io::{self};

use core::convert::TryInto;
use lz4_flex::{compress_into, decompress_into};
use std::mem;

#[inline]
#[allow(clippy::uninit_vec)]
pub fn compress(uncompressed: &[u8], compressed: &mut Vec<u8>) -> io::Result<()> {
    compressed.clear();
    let maximum_ouput_size =
        mem::size_of::<u32>() + lz4_flex::block::get_maximum_output_size(uncompressed.len());
    compressed.reserve(maximum_ouput_size);
    unsafe {
        compressed.set_len(maximum_ouput_size);
    }
    let bytes_written = compress_into(uncompressed, &mut compressed[4..])
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    let num_bytes = uncompressed.len() as u32;
    compressed[0..4].copy_from_slice(&num_bytes.to_le_bytes());
    unsafe {
        compressed.set_len(bytes_written + mem::size_of::<u32>());
    }
    Ok(())
}

#[inline]
#[allow(clippy::uninit_vec)]
pub fn decompress(compressed: &[u8], decompressed: &mut Vec<u8>) -> io::Result<()> {
    decompressed.clear();
    let uncompressed_size_bytes: &[u8; 4] = compressed
        .get(..4)
        .ok_or(io::ErrorKind::InvalidData)?
        .try_into()
        .unwrap();
    let uncompressed_size = u32::from_le_bytes(*uncompressed_size_bytes) as usize;
    decompressed.reserve(uncompressed_size);
    unsafe {
        decompressed.set_len(uncompressed_size);
    }
    let bytes_written = decompress_into(&compressed[4..], decompressed)
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    if bytes_written != uncompressed_size {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "doc store block not completely decompressed, data corruption".to_string(),
        ));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::transmute;
    use std::rand::random;
    use std::fmt;

    #[allow(dead_code,non_camel_case_types)]
    #[deriving(PartialEq,Eq)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    impl fmt::Show for UtpPacketType {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let s = match *self {
                ST_DATA  => "ST_DATA",
                ST_FIN   => "ST_FIN",
                ST_STATE => "ST_STATE",
                ST_RESET => "ST_RESET",
                ST_SYN   => "ST_SYN",
            };
            write!(f, "{}", s)
        }
    }

    #[allow(dead_code)]
    #[packed]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.type_ver;
            self.type_ver = t as u8 << 4 | version;
        }

        fn get_type(self) -> UtpPacketType {
            let t: UtpPacketType = unsafe { transmute(self.type_ver >> 4) };
            t
        }

        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }

        fn decode(buf: &[u8]) -> UtpPacketHeader {
            UtpPacketHeader {
                type_ver: buf[0],
                extension: buf[1],
                connection_id: buf[2] as u16 << 8 | buf[3] as u16,
                timestamp_microseconds: buf[4] as u32 << 24 | buf[5] as u32 << 16 | buf[6] as u32 << 8 | buf[7] as u32,
                timestamp_difference_microseconds: buf[8] as u32 << 24 | buf[9] as u32 << 16 | buf[10] as u32 << 8 | buf[11] as u32,
                wnd_size: buf[12] as u32 << 24 | buf[13] as u32 << 16 | buf[14] as u32 << 8 | buf[15] as u32,
                seq_nr: buf[16] as u16 << 8 | buf[17] as u16,
                ack_nr: buf[18] as u16 << 8 | buf[19] as u16,
            }
        }
    }

    impl fmt::Show for UtpPacketHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let t: UtpPacketType = self.get_type();
            write!(f, "(type: {}, version: {}, extension: {}, connection_id: {}, timestamp_microseconds: {}, timestamp_difference_microseconds: {}, wnd_size: {}, seq_nr: {}, ack_nr: {})", t, self.type_ver & 0x0F, self.extension, self.connection_id, self.timestamp_microseconds, self.timestamp_difference_microseconds, self.wnd_size, self.seq_nr, self.ack_nr)
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            self.header.set_type(t);
        }

        fn get_type(self) -> UtpPacketType {
            self.header.get_type()
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }

        fn decode(buf: &[u8]) -> UtpPacket {
            let header = UtpPacketHeader::decode(buf);
            UtpPacket { header: header, payload: Vec::from_slice(buf.slice(20, buf.len())) }
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            let stream = UtpStream::new(self.socket, other);
            stream.connect()
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        connection_id: u16,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            let r: u16 = random();
            UtpStream {
                socket: socket,
                connected_to: conn,
                connection_id: r.to_be(),
                seq_nr: 1,
                ack_nr: 0,
            }
        }

        pub fn connect(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_SYN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn terminate(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_FIN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::UtpSocket;
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            let stream = stream.terminate();
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Push low-level details to Socket, ignore Stream for now.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::transmute;
    use std::rand::random;
    use std::fmt;

    #[allow(dead_code,non_camel_case_types)]
    #[deriving(PartialEq,Eq)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    impl fmt::Show for UtpPacketType {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let s = match *self {
                ST_DATA  => "ST_DATA",
                ST_FIN   => "ST_FIN",
                ST_STATE => "ST_STATE",
                ST_RESET => "ST_RESET",
                ST_SYN   => "ST_SYN",
            };
            write!(f, "{}", s)
        }
    }

    #[allow(dead_code)]
    #[packed]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.type_ver;
            self.type_ver = t as u8 << 4 | version;
        }

        fn get_type(self) -> UtpPacketType {
            let t: UtpPacketType = unsafe { transmute(self.type_ver >> 4) };
            t
        }

        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }

        fn decode(buf: &[u8]) -> UtpPacketHeader {
            UtpPacketHeader {
                type_ver: buf[0],
                extension: buf[1],
                connection_id: buf[2] as u16 << 8 | buf[3] as u16,
                timestamp_microseconds: buf[4] as u32 << 24 | buf[5] as u32 << 16 | buf[6] as u32 << 8 | buf[7] as u32,
                timestamp_difference_microseconds: buf[8] as u32 << 24 | buf[9] as u32 << 16 | buf[10] as u32 << 8 | buf[11] as u32,
                wnd_size: buf[12] as u32 << 24 | buf[13] as u32 << 16 | buf[14] as u32 << 8 | buf[15] as u32,
                seq_nr: buf[16] as u16 << 8 | buf[17] as u16,
                ack_nr: buf[18] as u16 << 8 | buf[19] as u16,
            }
        }
    }

    impl fmt::Show for UtpPacketHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let t: UtpPacketType = self.get_type();
            write!(f, "(type: {}, version: {}, extension: {}, connection_id: {}, timestamp_microseconds: {}, timestamp_difference_microseconds: {}, wnd_size: {}, seq_nr: {}, ack_nr: {})", t, self.type_ver & 0x0F, self.extension, self.connection_id, self.timestamp_microseconds, self.timestamp_difference_microseconds, self.wnd_size, self.seq_nr, self.ack_nr)
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            self.header.set_type(t);
        }

        fn get_type(self) -> UtpPacketType {
            self.header.get_type()
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }

        fn decode(buf: &[u8]) -> UtpPacket {
            let header = UtpPacketHeader::decode(buf);
            UtpPacket { header: header, payload: Vec::from_slice(buf.slice(20, buf.len())) }
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
        connected_to: SocketAddr,
        connection_id: u16,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            let r: u16 = random();
            match skt {
                Ok(x)  => Ok(UtpSocket {
                    socket: x,
                    connected_to: addr,
                    connection_id: r.to_be(),
                    seq_nr: 1,
                    ack_nr: 0,
                }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(mut self, other: SocketAddr) -> UtpSocket {
            self.connected_to = other;
            /*
            let stream = UtpStream::new(s, other);
            stream.connect()
            */
            let mut packet = UtpPacket::new();
            packet.set_type(ST_SYN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let dst = self.connected_to;
            let _result = self.sendto(packet.bytes().as_slice(), dst);

            let mut buf = [0, ..512];
            let (len, addr) = self.socket.recvfrom(buf).unwrap();
            println!("{} {}", addr, self.connected_to);
            assert!(addr == self.connected_to);
            let packet = UtpPacket::decode(buf.slice(0, len));
            //assert!(packet.get_type() == ST_STATE);
            println!("{}", packet.header);

            self.seq_nr += 1;
            self
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            let mut b = [0, ..512];
            let response = self.socket.recvfrom(b);

            let _src: SocketAddr;
            let read;
            match response {
                Ok((nread, src)) => { read = nread; _src = src },
                Err(e) => return Err(e),
            };

            let packet = UtpPacket::decode(b);
            let x = packet.header;
            println!("{}", packet.header);
            match packet.get_type() {
                ST_SYN => {
                    let mut resp = UtpPacket::new();
                    resp.set_type(ST_STATE);
                    let t = time::get_time();
                    let self_t_micro: u32 = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);
                    let other_t_micro: u32 = x.timestamp_microseconds;
                    resp.header.timestamp_microseconds = self_t_micro.to_be();
                    resp.header.timestamp_difference_microseconds = (self_t_micro.to_le() - other_t_micro.to_le()).to_be();
                    resp.header.connection_id = self.connection_id;
                    self.socket.sendto(resp.bytes().as_slice(), _src);
                }
                _ => {}
            };

            for i in range(0u, ::std::cmp::min(buf.len(), read-20)) {
                buf[i] = b[i+20];
            }

            println!("{}", Vec::from_slice(buf.slice(0,read-20)));

            response
        }

        pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
            self.socket.sendto(buf, dst)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            let r: u16 = random();
            UtpSocket {
                socket: self.socket.clone(),
                connected_to: self.connected_to,
                connection_id: r.to_be(),
                seq_nr: 1,
                ack_nr: 0,
            }
        }
    }

    /*
    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UtpSocket,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UtpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
            }
        }

        pub fn connect(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_SYN);
            packet.header.connection_id = self.socket.connection_id;
            packet.header.seq_nr = self.socket.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let dst = self.socket.connected_to;
            let _result = self.socket.sendto(packet.bytes().as_slice(), dst);

            let mut buf = [0, ..512];
            let (len, addr) = self.socket.recvfrom(buf).unwrap();
            println!("{} {}", addr, self.socket.connected_to);
            assert!(addr == self.socket.connected_to);
            let packet = UtpPacket::decode(buf.slice(0, len));
            //assert!(packet.get_type() == ST_STATE);
            println!("{}", packet.header);

            self.socket.seq_nr += 1;

            self
        }

        pub fn terminate(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_FIN);
            packet.header.connection_id = self.socket.connection_id;
            packet.header.seq_nr = self.socket.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let dst = self.socket.connected_to;
            let _result = self.socket.sendto(packet.bytes().as_slice(), dst);

            self.socket.seq_nr += 1;

            self
        }

        pub fn disconnect(self) -> UtpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.socket.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e)
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.connection_id = self.socket.connection_id;
            packet.header.seq_nr = self.socket.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let dst = self.socket.connected_to;
            let result = self.socket.sendto(packet.bytes().as_slice(), dst);

            self.socket.seq_nr += 1;
            result
        }
    }
    */
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::UtpSocket;
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            //let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            //let _ = stream.write([0]);
            //let mut buf = [0, ..512];
            //stream.read(buf);
            //let stream = stream.terminate();
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fs::{DirEntry, Metadata};
use std::path::{Components, Path, PathBuf};

use chrono::{DateTime, Local};
use walkdir;
use walkdir::WalkDir;

use error::*;
use times::system_time_to_date_time;

#[derive(Debug, Eq, PartialEq, Serialize)]
pub struct FsNode {
  path: PathBuf,
  basename: String,
  entry: FsEntryType,
  mtime: DateTime<Local>,
}

#[derive(Debug, Serialize)]
pub struct FsRootNode(FsNode);

impl FsRootNode {
  pub fn new() -> Self {
    FsRootNode(FsNode {
      path: PathBuf::from(""),
      basename: String::new(),
      entry: FsEntryType::Directory { children: BTreeMap::new(), },
      mtime: Local::now(),
    })
  }

  pub fn add_root(&mut self, path: &Path) -> FomoResult<()> {

    for entry in WalkDir::new(path) {
      let entry = entry?;
      let mut parent = {
        let components = entry.path().components();
        let path_buffer = PathBuf::new();

        self.0.ensure_and_return_parent(path_buffer, components)?
      };

      {

        let new_node = FsNode::try_from_node_source(entry)?;
        let basename = new_node.basename.to_owned();

        match parent.entry {
          FsEntryType::Directory { ref mut children } => {
            children.insert(basename, new_node);
          }
          _ => panic!("Found a non-directory as the parent of a node."),
        }
      }
    }

    Ok(())
  }
}

impl FsNode {
  /// This should only be called if the node is a root node.
  fn ensure_and_return_parent<'a, 'b>(
    &'a mut self,
    mut path_so_far: PathBuf,
    mut components: Components<'b>
  ) -> FomoResult<&'a mut FsNode> {

    let component = components.next();

    if let Some(c) = component {

      let comp_str = match c.as_os_str().to_str() {
        Some(s) => s,
        None => return Err(FomoError::Internal("non unicode filename found")),
      };
      path_so_far.push(comp_str);

      match self.entry {
        FsEntryType::Directory { ref mut children } => {
          children.entry(comp_str.to_owned())
            .or_insert_with(|| FsNode::empty_dir(path_so_far.clone(), comp_str.to_owned()))
            .ensure_and_return_parent(path_so_far, components)
        }
        _ => panic!("Files should not exist in the middle of a path component."),
      }
    } else {
      return Ok(self);
    }
  }

  pub fn empty_dir(path: PathBuf, dirname: String) -> Self {
    FsNode {
      path: path,
      basename: dirname,
      entry: FsEntryType::Directory { children: BTreeMap::new(), },
      mtime: Local::now(),
    }
  }

  pub fn try_from_node_source<S: NodeSource>(entry: S) -> FomoResult<Self> {

    let basename = match entry.path().file_name() {
      Some(n) => {
        match n.to_str() {
          Some(b) => b.to_owned(),
          None => return Err(FomoError::Internal("non-unicode filename")),
        }
      }
      None => return Err(FomoError::Internal("walkdir gave us a relative path")),
    };

    let metadata = entry.metadata()?;

    let entry_ty = if metadata.is_dir() {
      FsEntryType::Directory { children: BTreeMap::new(), }
    } else if metadata.is_file() {
      FsEntryType::File { len: metadata.len(), }
    } else {
      // FIXME(dikaiosune) this doesn't handle links or other entry types
      unreachable!()
    };

    Ok(FsNode {
      path: entry.path(),
      basename: basename,
      entry: entry_ty,
      mtime: system_time_to_date_time(metadata.modified()?),
    })
  }
}

#[derive(Debug, Eq, PartialEq, Serialize)]
pub enum FsEntryType {
  Directory { children: BTreeMap<String, FsNode>, },
  File { len: u64, },
}

pub trait NodeSource {
  fn path(&self) -> PathBuf;
  fn metadata(&self) -> FomoResult<Metadata>;
}

impl NodeSource for walkdir::DirEntry {
  fn path(&self) -> PathBuf {
    self.path().to_path_buf()
  }

  fn metadata(&self) -> FomoResult<Metadata> {
    Ok(self.metadata()?)
  }
}

impl NodeSource for DirEntry {
  fn path(&self) -> PathBuf {
    self.path()
  }

  fn metadata(&self) -> FomoResult<Metadata> {
    Ok(self.metadata()?)
  }
}

#[cfg(test)]
mod test {
  use std::fs::File;
  use std::io::prelude::*;
  use tempdir::TempDir;
  use walkdir::WalkDir;

  use super::{FsEntryType, FsNode};

  #[test]
  fn single_file_tmp_dir() {
    let tmp = TempDir::new("single").expect("unable to create temp directory");
    let tmp_path = tmp.path().join("test-file");
    let mut tmp_file = File::create(&tmp_path).expect("unable to create test file");

    let mut traversed = 0;
    for entry in WalkDir::new(&tmp_path) {
      let entry = entry.expect("walking directory");
      let node = FsNode::try_from_node_source(entry).expect("creating node");
      assert_eq!(node.basename, "test-file");
      assert_eq!(node.path, tmp_path);
      assert_eq!(node.entry, FsEntryType::File { len: 0, });
      traversed += 1;
    }
    assert_eq!(traversed, 1);

    write!(tmp_file, "7 bytes").expect("writing to temp file");

    traversed = 0;
    for entry in WalkDir::new(&tmp_path) {
      let entry = entry.expect("walking directory");
      let node = FsNode::try_from_node_source(entry).expect("creating node");
      assert_eq!(node.basename, "test-file");
      assert_eq!(node.path, tmp_path);
      assert_eq!(node.entry, FsEntryType::File { len: 7, });
      traversed += 1;
    }
    assert_eq!(traversed, 1);
  }
}
<commit_msg>[fomo] Put the `.next_back()` call back.<commit_after>use std::collections::BTreeMap;
use std::fs::{DirEntry, Metadata};
use std::path::{Components, Path, PathBuf};

use chrono::{DateTime, Local};
use walkdir;
use walkdir::WalkDir;

use error::*;
use times::system_time_to_date_time;

#[derive(Debug, Eq, PartialEq, Serialize)]
pub struct FsNode {
  path: PathBuf,
  basename: String,
  entry: FsEntryType,
  mtime: DateTime<Local>,
}

#[derive(Debug, Serialize)]
pub struct FsRootNode(FsNode);

impl FsRootNode {
  pub fn new() -> Self {
    FsRootNode(FsNode {
      path: PathBuf::from(""),
      basename: String::new(),
      entry: FsEntryType::Directory { children: BTreeMap::new(), },
      mtime: Local::now(),
    })
  }

  pub fn add_root(&mut self, path: &Path) -> FomoResult<()> {

    for entry in WalkDir::new(path) {
      let entry = entry?;
      let mut parent = {
        let mut components = entry.path().components();
        // we need to remove the final element from the path, as it corresponds to the DirEntry
        components.next_back();
        let path_buffer = PathBuf::new();

        self.0.ensure_and_return_parent(path_buffer, components)?
      };

      {

        let new_node = FsNode::try_from_node_source(entry)?;
        let basename = new_node.basename.to_owned();

        match parent.entry {
          FsEntryType::Directory { ref mut children } => {
            children.insert(basename, new_node);
          }
          _ => panic!("Found a non-directory as the parent of a node."),
        }
      }
    }

    Ok(())
  }
}

impl FsNode {
  /// This should only be called if the node is a root node.
  fn ensure_and_return_parent<'a, 'b>(
    &'a mut self,
    mut path_so_far: PathBuf,
    mut components: Components<'b>
  ) -> FomoResult<&'a mut FsNode> {

    let component = components.next();

    if let Some(c) = component {

      let comp_str = match c.as_os_str().to_str() {
        Some(s) => s,
        None => return Err(FomoError::Internal("non unicode filename found")),
      };
      path_so_far.push(comp_str);

      match self.entry {
        FsEntryType::Directory { ref mut children } => {
          children.entry(comp_str.to_owned())
            .or_insert_with(|| FsNode::empty_dir(path_so_far.clone(), comp_str.to_owned()))
            .ensure_and_return_parent(path_so_far, components)
        }
        _ => panic!("Files should not exist in the middle of a path component."),
      }
    } else {
      Ok(self)
    }
  }

  pub fn empty_dir(path: PathBuf, dirname: String) -> Self {
    FsNode {
      path: path,
      basename: dirname,
      entry: FsEntryType::Directory { children: BTreeMap::new(), },
      mtime: Local::now(),
    }
  }

  pub fn try_from_node_source<S: NodeSource>(entry: S) -> FomoResult<Self> {

    let basename = match entry.path().file_name() {
      Some(n) => {
        match n.to_str() {
          Some(b) => b.to_owned(),
          None => return Err(FomoError::Internal("non-unicode filename")),
        }
      }
      None => return Err(FomoError::Internal("walkdir gave us a relative path")),
    };

    let metadata = entry.metadata()?;

    let entry_ty = if metadata.is_dir() {
      FsEntryType::Directory { children: BTreeMap::new(), }
    } else if metadata.is_file() {
      FsEntryType::File { len: metadata.len(), }
    } else {
      // FIXME(dikaiosune) this doesn't handle links or other entry types
      unreachable!()
    };

    Ok(FsNode {
      path: entry.path(),
      basename: basename,
      entry: entry_ty,
      mtime: system_time_to_date_time(metadata.modified()?),
    })
  }
}

#[derive(Debug, Eq, PartialEq, Serialize)]
pub enum FsEntryType {
  Directory { children: BTreeMap<String, FsNode>, },
  File { len: u64, },
}

pub trait NodeSource {
  fn path(&self) -> PathBuf;
  fn metadata(&self) -> FomoResult<Metadata>;
}

impl NodeSource for walkdir::DirEntry {
  fn path(&self) -> PathBuf {
    self.path().to_path_buf()
  }

  fn metadata(&self) -> FomoResult<Metadata> {
    Ok(self.metadata()?)
  }
}

impl NodeSource for DirEntry {
  fn path(&self) -> PathBuf {
    self.path()
  }

  fn metadata(&self) -> FomoResult<Metadata> {
    Ok(self.metadata()?)
  }
}

#[cfg(test)]
mod test {
  use std::fs::File;
  use std::io::prelude::*;
  use tempdir::TempDir;
  use walkdir::WalkDir;

  use super::{FsEntryType, FsNode};

  #[test]
  fn single_file_tmp_dir() {
    let tmp = TempDir::new("single").expect("unable to create temp directory");
    let tmp_path = tmp.path().join("test-file");
    let mut tmp_file = File::create(&tmp_path).expect("unable to create test file");

    let mut traversed = 0;
    for entry in WalkDir::new(&tmp_path) {
      let entry = entry.expect("walking directory");
      let node = FsNode::try_from_node_source(entry).expect("creating node");
      assert_eq!(node.basename, "test-file");
      assert_eq!(node.path, tmp_path);
      assert_eq!(node.entry, FsEntryType::File { len: 0, });
      traversed += 1;
    }
    assert_eq!(traversed, 1);

    write!(tmp_file, "7 bytes").expect("writing to temp file");

    traversed = 0;
    for entry in WalkDir::new(&tmp_path) {
      let entry = entry.expect("walking directory");
      let node = FsNode::try_from_node_source(entry).expect("creating node");
      assert_eq!(node.basename, "test-file");
      assert_eq!(node.path, tmp_path);
      assert_eq!(node.entry, FsEntryType::File { len: 7, });
      traversed += 1;
    }
    assert_eq!(traversed, 1);
  }
}
<|endoftext|>


<commit_before>use crate::ffi::c_void;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;

// The implementation is inspired by Andrew D. Birrell's paper
// "Implementing Condition Variables with Semaphores"

pub struct Condvar {
    counter: AtomicUsize,
    sem1: *const c_void,
    sem2: *const c_void,
}

pub type MovableCondvar = Condvar;

unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
    }

    pub unsafe fn init(&mut self) {
        let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
        let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
    }

    pub unsafe fn notify_one(&self) {
        if self.counter.load(SeqCst) > 0 {
            self.counter.fetch_sub(1, SeqCst);
            abi::sem_post(self.sem1);
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn notify_all(&self) {
        let counter = self.counter.swap(0, SeqCst);
        for _ in 0..counter {
            abi::sem_post(self.sem1);
        }
        for _ in 0..counter {
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn wait(&self, mutex: &Mutex) {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        abi::sem_timedwait(self.sem1, 0);
        abi::sem_post(self.sem2);
        mutex.lock();
    }

    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
        panic!("wait_timeout not supported on hermit");
    }

    pub unsafe fn destroy(&self) {
        let _ = abi::sem_destroy(self.sem1);
        let _ = abi::sem_destroy(self.sem2);
    }
}
<commit_msg>hermit: Implement Condvar::wait_timeout<commit_after>use crate::ffi::c_void;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;

// The implementation is inspired by Andrew D. Birrell's paper
// "Implementing Condition Variables with Semaphores"

pub struct Condvar {
    counter: AtomicUsize,
    sem1: *const c_void,
    sem2: *const c_void,
}

pub type MovableCondvar = Condvar;

unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

impl Condvar {
    pub const fn new() -> Condvar {
        Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
    }

    pub unsafe fn init(&mut self) {
        let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
        let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
    }

    pub unsafe fn notify_one(&self) {
        if self.counter.load(SeqCst) > 0 {
            self.counter.fetch_sub(1, SeqCst);
            abi::sem_post(self.sem1);
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn notify_all(&self) {
        let counter = self.counter.swap(0, SeqCst);
        for _ in 0..counter {
            abi::sem_post(self.sem1);
        }
        for _ in 0..counter {
            abi::sem_timedwait(self.sem2, 0);
        }
    }

    pub unsafe fn wait(&self, mutex: &Mutex) {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        abi::sem_timedwait(self.sem1, 0);
        abi::sem_post(self.sem2);
        mutex.lock();
    }

    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
        self.counter.fetch_add(1, SeqCst);
        mutex.unlock();
        let millis = dur.as_millis().min(u32::MAX as u128) as u32;

        let res = if millis > 0 {
            abi::sem_timedwait(self.sem1, millis)
        } else {
            abi::sem_trywait(self.sem1)
        };

        abi::sem_post(self.sem2);
        mutex.lock();
        res == 0
    }

    pub unsafe fn destroy(&self) {
        let _ = abi::sem_destroy(self.sem1);
        let _ = abi::sem_destroy(self.sem2);
    }
}
<|endoftext|>


<commit_before><commit_msg>Private method made public fix<commit_after><|endoftext|>


<commit_before><commit_msg>Fix processing alleles without a genotype<commit_after><|endoftext|>


<commit_before>use chrono::{DateTime, Utc};

use super::resource::{ResourceKind, CResourceUpdate, SResourceUpdate};
use super::criterion::Criterion;

/// Client -> server messages, deserialize only
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[serde(tag = "type")]
#[serde(deny_unknown_fields)]
pub enum CMessage {
    // Standard messages
    GetResources { serial: u64, ids: Vec<String> },
    Subscribe { serial: u64, ids: Vec<String> },
    Unsubscribe { serial: u64, ids: Vec<String> },
    UpdateResource {
        serial: u64,
        resource: CResourceUpdate,
    },
    RemoveResource { serial: u64, id: String },
    FilterSubscribe {
        serial: u64,
        #[serde(default)]
        kind: ResourceKind,
        criteria: Vec<Criterion>,
    },
    FilterUnsubscribe { serial: u64, filter_serial: u64 },

    // Special messages
    UploadTorrent {
        serial: u64,
        size: u64,
        path: Option<String>,
    },
    UploadMagnet {
        serial: u64,
        uri: String,
        path: Option<String>,
    },
    UploadFiles {
        serial: u64,
        size: u64,
        path: String,
    },
    DownloadFile { serial: u64, id: String },
}

/// Server -> client message, serialize only
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[serde(tag = "type")]
#[serde(deny_unknown_fields)]
pub enum SMessage<'a> {
    // Standard messages
    #[serde(skip_deserializing)]
    ResourcesExtant { serial: u64, ids: Vec<&'a str> },
    #[serde(skip_serializing)]
    #[serde(rename = "RESOURCES_EXTANT")]
    OResourcesExtant { serial: u64, ids: Vec<String> },
    ResourcesRemoved { serial: u64, ids: Vec<String> },
    UpdateResources { resources: Vec<SResourceUpdate<'a>> },

    // Special messages
    TransferOffer {
        serial: u64,
        expires: DateTime<Utc>,
        token: String,
        size: u64,
    },

    // Error messages
    UnknownResource(Error),
    InvalidResource(Error),
    // InvalidMessage(Error),
    InvalidSchema(Error),
    // InvalidRequest(Error),
    PermissionDenied(Error),
    TransferFailed(Error),
    // ServerError(Error),
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Error {
    pub serial: Option<u64>,
    pub reason: String,
}

#[cfg(test)]
mod tests {
    extern crate serde_json;
    use super::*;
    use super::super::{resource, criterion};

    #[test]
    fn test_json_repr() {
        let data = r#"
            {
                "type": "FILTER_SUBSCRIBE",
                "serial": 0,
                "criteria": [
                    { "field": "id", "op": "in", "value": [1,2,3] }
                ]
            }
            "#;
        let m = serde_json::from_str(data).unwrap();
        if let CMessage::FilterSubscribe {
            kind: resource::ResourceKind::Torrent,
            serial: 0,
            criteria: c,
        } = m
        {
            assert_eq!(c[0].field, "id");
            assert_eq!(c[0].op, criterion::Operation::In);
            assert_eq!(c[0].value, criterion::Value::AN(vec![1, 2, 3]));
        } else {
            unreachable!();
        }
    }
}
<commit_msg>Default criteria list to empty<commit_after>use chrono::{DateTime, Utc};

use super::resource::{ResourceKind, CResourceUpdate, SResourceUpdate};
use super::criterion::Criterion;

/// Client -> server messages, deserialize only
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[serde(tag = "type")]
#[serde(deny_unknown_fields)]
pub enum CMessage {
    // Standard messages
    GetResources { serial: u64, ids: Vec<String> },
    Subscribe { serial: u64, ids: Vec<String> },
    Unsubscribe { serial: u64, ids: Vec<String> },
    UpdateResource {
        serial: u64,
        resource: CResourceUpdate,
    },
    RemoveResource { serial: u64, id: String },
    FilterSubscribe {
        serial: u64,
        #[serde(default)]
        kind: ResourceKind,
        #[serde(default)]
        criteria: Vec<Criterion>,
    },
    FilterUnsubscribe { serial: u64, filter_serial: u64 },

    // Special messages
    UploadTorrent {
        serial: u64,
        size: u64,
        path: Option<String>,
    },
    UploadMagnet {
        serial: u64,
        uri: String,
        path: Option<String>,
    },
    UploadFiles {
        serial: u64,
        size: u64,
        path: String,
    },
    DownloadFile { serial: u64, id: String },
}

/// Server -> client message, serialize only
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[serde(tag = "type")]
#[serde(deny_unknown_fields)]
pub enum SMessage<'a> {
    // Standard messages
    #[serde(skip_deserializing)]
    ResourcesExtant { serial: u64, ids: Vec<&'a str> },
    #[serde(skip_serializing)]
    #[serde(rename = "RESOURCES_EXTANT")]
    OResourcesExtant { serial: u64, ids: Vec<String> },
    ResourcesRemoved { serial: u64, ids: Vec<String> },
    UpdateResources { resources: Vec<SResourceUpdate<'a>> },

    // Special messages
    TransferOffer {
        serial: u64,
        expires: DateTime<Utc>,
        token: String,
        size: u64,
    },

    // Error messages
    UnknownResource(Error),
    InvalidResource(Error),
    // InvalidMessage(Error),
    InvalidSchema(Error),
    // InvalidRequest(Error),
    PermissionDenied(Error),
    TransferFailed(Error),
    // ServerError(Error),
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Error {
    pub serial: Option<u64>,
    pub reason: String,
}

#[cfg(test)]
mod tests {
    extern crate serde_json;
    use super::*;
    use super::super::{resource, criterion};

    #[test]
    fn test_json_repr() {
        let data = r#"
            {
                "type": "FILTER_SUBSCRIBE",
                "serial": 0,
                "criteria": [
                    { "field": "id", "op": "in", "value": [1,2,3] }
                ]
            }
            "#;
        let m = serde_json::from_str(data).unwrap();
        if let CMessage::FilterSubscribe {
            kind: resource::ResourceKind::Torrent,
            serial: 0,
            criteria: c,
        } = m
        {
            assert_eq!(c[0].field, "id");
            assert_eq!(c[0].op, criterion::Operation::In);
            assert_eq!(c[0].value, criterion::Value::AN(vec![1, 2, 3]));
        } else {
            unreachable!();
        }
    }
}
<|endoftext|>


<commit_before>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide][arm_comp_ref]
//!
//! [arm_comp_ref]: https://developer.arm.com/docs/100067/0610

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Inserts a breakpoint instruction.
///
/// `val` is a compile-time constant integer in range `[0, 255]`.
///
/// The breakpoint instruction inserted is:
///
/// * `BKPT` when compiling as T32,
/// * `BRK` when compiling as A32 or A64.
///
/// # Safety
///
/// If `val` is out-of-range the behavior is **undefined**.
///
/// # Note
///
/// [ARM's documentation][arm_docs] defines that `__breakpoint` accepts the
/// following values for `val`:
///
/// - `0...65535` when compiling as A32 or A64,
/// - `0...255` when compiling as T32.
///
/// The current implementation only accepts values in range `[0, 255]` - if the
/// value is out-of-range the behavior is **undefined**.
///
/// [arm_docs]: https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    #[cfg(target_arch = "arm")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    #[cfg(target_arch = "aarch64")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
        }
    }

    // We can't `panic!` inside this intrinsic, so we can't really validate the
    // arguments here. If `val` is out-of-range this macro uses `val == 255`:
    constify_imm8!(val, call);
}
<commit_msg>Fix build of documentation in libstd<commit_after>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide][arm_comp_ref]
//!
//! [arm_comp_ref]: https://developer.arm.com/docs/100067/0610

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Inserts a breakpoint instruction.
///
/// `val` is a compile-time constant integer in range `[0, 255]`.
///
/// The breakpoint instruction inserted is:
///
/// * `BKPT` when compiling as T32,
/// * `BRK` when compiling as A32 or A64.
///
/// # Safety
///
/// If `val` is out-of-range the behavior is **undefined**.
///
/// # Note
///
/// [ARM's documentation][arm_docs] defines that `__breakpoint` accepts the
/// following values for `val`:
///
/// - `0...65535` when compiling as A32 or A64,
/// - `0...255` when compiling as T32.
///
/// The current implementation only accepts values in range `[0, 255]` - if the
/// value is out-of-range the behavior is **undefined**.
///
/// [arm_docs]: https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    // Ensure that this compiles correctly on non-arm architectures, so libstd
    // doc builds work. The proper macro will shadow this definition below.
    #[allow(unused_macros)]
    macro_rules! call {
        ($e:expr) => {()}
    }

    #[cfg(target_arch = "arm")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    #[cfg(target_arch = "aarch64")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
        }
    }

    // We can't `panic!` inside this intrinsic, so we can't really validate the
    // arguments here. If `val` is out-of-range this macro uses `val == 255`:
    constify_imm8!(val, call);
}
<|endoftext|>