<commit_before>//! Allocating pages of memory from the OS and carving them into individual
//! allocations.

use bit_vec::BitVec;
use heap::{GcHeap, HeapSessionId};
use marking::MarkingTracer;
use ptr::{Pointer, UntypedPointer};
use std::{cmp, mem, ptr};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use traits::{IntoHeapAllocation, Tracer};

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'h, T>(addr: UntypedPointer, tracer: &mut MarkingTracer)
where
    T: IntoHeapAllocation<'h>,
{
    let addr = addr.as_typed_ptr::<T::In>();

    if GcHeap::get_mark_bit::<T>(addr) {
        // If the mark bit is set, then this object is gray in the classic
        // tri-color sense: seen but we just popped it off the mark stack and
        // have't finished enumerating its outgoing edges.
        T::trace(addr.as_ref(), tracer);
    } else {
        // If the mark bit is not set, then this object is white in the classic
        // tri-color sense: freshly discovered to be live, and we now need to
        // set its mark bit and then process its edges or push it onto the mark
        // stack for later edge processing.
        tracer.visit::<T>(addr);
    }
}

/// A unique id for each type that implements `IntoHeapAllocation`.
///
/// Implementation note: function types don't support Eq, so we cast to a
/// meaningless pointer type.
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct TypeId(*const ());

pub fn heap_type_id<'h, T: IntoHeapAllocation<'h>>() -> TypeId {
    TypeId(mark_entry_point::<T> as *const ())
}

pub(crate) const PAGE_SIZE: usize = 0x1000;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// TypedPage instances.
pub(crate) const PAGE_ALIGN: usize = 0x1000;

fn is_aligned(ptr: *const ()) -> bool {
    ptr as usize & (PAGE_ALIGN - 1) == 0
}

pub struct PageHeader {
    pub heap: *mut GcHeap,
    next_page: *mut PageHeader,
    mark_bits: BitVec,
    allocated_bits: BitVec,
    mark_fn: unsafe fn(UntypedPointer, &mut MarkingTracer),
    freelist: *mut (),
}

impl PageHeader {
    pub fn find(ptr: UntypedPointer) -> *mut PageHeader {
        let header_addr = ptr.as_usize() & !(PAGE_ALIGN - 1);
        assert!(header_addr != 0);
        header_addr as *mut PageHeader
    }

    pub fn clear_mark_bits(&mut self) {
        self.mark_bits.clear();
    }

    /// True if nothing on this page is allocated.
    pub fn is_empty(&self) -> bool {
        self.allocated_bits.none()
    }

    pub unsafe fn mark(&self, ptr: UntypedPointer, tracer: &mut MarkingTracer) {
        (self.mark_fn)(ptr, tracer);
    }

    pub fn type_id(&self) -> TypeId {
        TypeId(self.mark_fn as *const ())
    }

    pub fn downcast_mut<'h, T>(&mut self) -> Option<&mut TypedPage<T::In>>
    where
        T: IntoHeapAllocation<'h>,
    {
        if heap_type_id::<T>() == self.type_id() {
            let ptr = self as *mut PageHeader as *mut TypedPage<T::In>;
            Some(unsafe { &mut *ptr })
        } else {
            None
        }
    }
}

pub struct TypedPage<U> {
    pub header: PageHeader,
    pub allocations: PhantomData<U>,
}

impl<U> Deref for TypedPage<U> {
    type Target = PageHeader;

    fn deref(&self) -> &PageHeader {
        &self.header
    }
}

impl<U> DerefMut for TypedPage<U> {
    fn deref_mut(&mut self) -> &mut PageHeader {
        &mut self.header
    }
}

/// Returns the smallest multiple of `k` that is at least `n`.
///
/// Panics if the answer is too big to fit in a `usize`.
fn round_up(n: usize, k: usize) -> usize {
    let a = n / k * k;
    if a == n {
        n
    } else {
        n + k
    }
}

impl<U> TypedPage<U> {
    /// The actual size of an allocation can't be smaller than the size of a
    /// pointer, due to the way we store the freelist by stealing a pointer
    /// from the allocation itself.
    fn allocation_size() -> usize {
        cmp::max(mem::size_of::<U>(), mem::size_of::<*mut U>())
    }

    fn allocation_align() -> usize {
        cmp::max(mem::align_of::<U>(), mem::align_of::<*mut U>())
    }

    /// Offset, in bytes, of the first allocation from the start of the page.
    pub(crate) fn first_allocation_offset() -> usize {
        round_up(mem::size_of::<PageHeader>(), Self::allocation_align())
    }

    /// Number of allocations that fit in a page.
    pub fn capacity() -> usize {
        (PAGE_SIZE - Self::first_allocation_offset()) / Self::allocation_size()
    }

    fn first_object_addr(&self) -> usize {
        (self as *const Self as usize) + Self::first_allocation_offset()
    }

    unsafe fn init_freelist(&mut self) {
        let mut addr = self.first_object_addr();
        for _ in 0..Self::capacity() {
            self.add_to_free_list(addr as *mut U);

            // This can't use `ptr = ptr.offset(1)` because if U is smaller
            // than a pointer, allocations are padded to pointer size.
            // `.offset(1)` doesn't know about the padding and therefore
            // wouldn't advance to the next allocation.
            addr += Self::allocation_size();
        }
    }

    /// Return the page containing the object `ptr` points to.
    pub fn find(ptr: Pointer<U>) -> *mut TypedPage<U> {
        let ptr: usize = ptr.into();
        let page_addr = ptr & !(PAGE_ALIGN - 1);
        page_addr as *mut TypedPage<U>
    }

    unsafe fn add_to_free_list(&mut self, p: *mut U) {
        let listp = p as *mut *mut ();
        *listp = self.header.freelist;
        assert_eq!(*listp, self.header.freelist);
        self.header.freelist = p as *mut ();
    }

    unsafe fn allocation_index(&self, ptr: Pointer<U>) -> usize {
        let base = self.first_object_addr();

        // Check that ptr is in range.
        assert!(ptr.as_void() >= base as _);
        assert!(ptr.as_void() < (base + (Self::capacity() * Self::allocation_size())) as _);

        let index = (ptr.as_usize() - base as usize) / Self::allocation_size();
        assert_eq!(
            (base + index * Self::allocation_size()) as *const (),
            ptr.as_void()
        );
        index
    }

    pub unsafe fn get_mark_bit(&mut self, ptr: Pointer<U>) -> bool {
        let index = self.allocation_index(ptr);
        self.header.mark_bits[index]
    }

    pub unsafe fn set_mark_bit(&mut self, ptr: Pointer<U>) {
        let index = self.allocation_index(ptr);
        assert!(self.header.allocated_bits.get(index).unwrap(),
                "marking memory that isn't allocated (dangling pointer?)");
        self.header.mark_bits.set(index, true);
    }

    /// Allocate a `U`-sized-and-aligned region of uninitialized memory
    /// from this page.
    ///
    /// # Safety
    ///
    /// This is safe unless GC is happening.
    pub unsafe fn try_alloc(&mut self) -> Option<Pointer<U>> {
        let p = self.header.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut ();
            self.header.freelist = *listp;
            let ap = Pointer::new(p as *mut U);
            let index = self.allocation_index(ap);
            assert!(!self.header.allocated_bits[index]);
            self.header.allocated_bits.set(index, true);
            Some(ap)
        }
    }

    unsafe fn sweep(&mut self) {
        let mut addr = self.first_object_addr();
        for i in 0..Self::capacity() {
            if self.header.allocated_bits[i] && !self.header.mark_bits[i] {
                ptr::drop_in_place(addr as *mut U);
                if cfg!(debug_assertions) || cfg!(test) {
                    // Paint the unused memory with a known-bad value.
                    const SWEPT_BYTE: u8 = 0xf4;
                    ptr::write_bytes(addr as *mut U, SWEPT_BYTE, 1);
                }
                self.header.allocated_bits.set(i, false);
                self.add_to_free_list(addr as *mut U);
            }
            addr += Self::allocation_size();
        }
    }
}

/// Sweep a page.
///
/// # Safety
///
/// This must be called only after a full mark phase, to avoid sweeping objects
/// that are still reachable.
unsafe fn sweep_entry_point<'h, T: IntoHeapAllocation<'h>>(header: &mut PageHeader) {
    header.downcast_mut::<T>().expect("page header corrupted").sweep();
}

/// An unordered collection of memory pages that all share an allocation type.
pub struct PageSet {
    heap: *mut GcHeap,

    sweep_fn: unsafe fn(&mut PageHeader),

    /// The collection of pages.
    ///
    /// All pages in this collection have matching `.heap`, `.mark_fn`, and
    /// `.sweep_fn` fields.
    pages: *mut PageHeader,

    /// The maximum number of pages, or None for no limit.
    limit: Option<usize>,
}

impl Drop for PageSet {
    fn drop(&mut self) {
        unsafe {
            let mut p = self.pages;
            while !p.is_null() {
                let next = (*p).next_page;
                ptr::drop_in_place(p); // drop the header
                Vec::from_raw_parts(p as *mut u8, 0, PAGE_SIZE); // free the page
                p = next;
            }
        }
    }
}

impl PageSet {
    /// Create a new PageSet.
    ///
    /// # Safety
    ///
    /// Safe as long as `heap` is a valid pointer.
    pub unsafe fn new<'h, T: IntoHeapAllocation<'h>>(heap: *mut GcHeap) -> PageSet {
        PageSet {
            heap,
            sweep_fn: sweep_entry_point::<T>,
            pages: ptr::null_mut(),
            limit: None,
        }
    }

    /// Downcast to a typed PageSetRef.
    ///
    /// # Panics
    ///
    /// If T is not the actual allocation type for this page set.
    pub fn downcast_mut<'a, 'h, T>(&'a mut self) -> PageSetRef<'a, 'h, T>
    where
        T: IntoHeapAllocation<'h> + 'a,
    {
        assert_eq!(
            self.sweep_fn as *const (),
            sweep_entry_point::<T> as *const ()
        );

        PageSetRef {
            page_set: self,
            id: PhantomData,
            also: PhantomData,
        }
    }

    /// Clear mark bits from each page in this set.
    ///
    /// # Safety
    ///
    /// This must be called only at the beginning of a GC cycle.
    pub unsafe fn clear_mark_bits(&mut self) {
        let mut page = self.pages;
        while !page.is_null() {
            (*page).clear_mark_bits();
            page = (*page).next_page;
        }
    }

    /// Sweep all unmarked objects from all pages.
    ///
    /// # Safety
    ///
    /// Safe to call only as the final part of GC.
    pub unsafe fn sweep(&mut self) {
        let mut page = self.pages;
        while !page.is_null() {
            (self.sweep_fn)(&mut *page);
            page = (*page).next_page;
        }
    }

    /// Assert that nothing is allocated in this set of pages.
    pub fn all_pages_are_empty(&self) -> bool {
        unsafe {
            let mut page = self.pages;
            while !page.is_null() {
                if !(*page).is_empty() {
                    return false;
                }
                page = (*page).next_page;
            }
        }
        true
    }
}

pub struct PageSetRef<'a, 'h, T: IntoHeapAllocation<'h> + 'a> {
    page_set: &'a mut PageSet,
    id: HeapSessionId<'h>,
    also: PhantomData<&'a mut T>,
}

impl<'a, 'h, T: IntoHeapAllocation<'h> + 'a> PageSetRef<'a, 'h, T> {
    pub fn set_page_limit(&mut self, limit: Option<usize>) {
        self.page_set.limit = limit;
    }

    /// Allocate memory for a value of type `T::In`.
    ///
    /// # Safety
    ///
    /// Safe to call as long as GC is not happening.
    pub unsafe fn try_alloc(&mut self) -> Option<Pointer<T::In>> {
        // First, try to allocate from each existing page. (Obviously slow.)
        let mut page = self.page_set.pages;
        let mut page_count = 0;
        while !page.is_null() {
            let t_page = (*page).downcast_mut::<T>().unwrap();
            if let Some(ptr) = t_page.try_alloc() {
                return Some(ptr);
            }

            page_count += 1;
            page = (*page).next_page;
        }

        // If there is a limit and we already have at least that many pages, fail.
        match self.page_set.limit {
            Some(limit) if page_count >= limit => None,
            _ => self.new_page().try_alloc(),
        }
    }

    /// Allocate a page from the operating system.
    ///
    /// Initialize its header and freelist and link it into this page set's
    /// linked list of pages.
    fn new_page(&mut self) -> &mut TypedPage<T::In> {
        assert!({
            let size_of_page = mem::size_of::<TypedPage<T::In>>();
            let alloc_offset = TypedPage::<T::In>::first_allocation_offset();
            size_of_page <= alloc_offset
        });
        assert!({
            let alloc_offset = TypedPage::<T::In>::first_allocation_offset();
            let alloc_size = TypedPage::<T::In>::allocation_size();
            let capacity = TypedPage::<T::In>::capacity();
            alloc_offset + capacity * alloc_size <= PAGE_SIZE
        });

        let mut vec: Vec<u8> = Vec::with_capacity(PAGE_SIZE);
        let raw_page = vec.as_mut_ptr() as *mut ();

        // Rust makes no guarantee whatsoever that this will work.
        // If it doesn't, panic.
        assert!(is_aligned(raw_page));

        let page_ptr: *mut TypedPage<T::In> = raw_page as *mut TypedPage<T::In>;
        let capacity = TypedPage::<T::In>::capacity();
        unsafe {
            ptr::write(
                page_ptr,
                TypedPage {
                    header: PageHeader {
                        heap: self.page_set.heap,
                        next_page: self.page_set.pages,
                        mark_bits: BitVec::from_elem(capacity, false),
                        allocated_bits: BitVec::from_elem(capacity, false),
                        mark_fn: mark_entry_point::<T>,
                        freelist: ptr::null_mut(),
                    },
                    allocations: PhantomData,
                },
            );

            let page = &mut *page_ptr;
            page.init_freelist();

            // Remove the memory from the vector and link it into
            // the PageSet's linked list.
            mem::forget(vec);
            self.page_set.pages = &mut page.header;

            page
        }
    }
}
<commit_msg>Delegate TypedPage::find() to PageHeader::find().<commit_after>//! Allocating pages of memory from the OS and carving them into individual
//! allocations.

use bit_vec::BitVec;
use heap::{GcHeap, HeapSessionId};
use marking::MarkingTracer;
use ptr::{Pointer, UntypedPointer};
use std::{cmp, mem, ptr};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use traits::{IntoHeapAllocation, Tracer};

/// Non-inlined function that serves as an entry point to marking. This is used
/// for marking root set entries.
unsafe fn mark_entry_point<'h, T>(addr: UntypedPointer, tracer: &mut MarkingTracer)
where
    T: IntoHeapAllocation<'h>,
{
    let addr = addr.as_typed_ptr::<T::In>();

    if GcHeap::get_mark_bit::<T>(addr) {
        // If the mark bit is set, then this object is gray in the classic
        // tri-color sense: seen but we just popped it off the mark stack and
        // have't finished enumerating its outgoing edges.
        T::trace(addr.as_ref(), tracer);
    } else {
        // If the mark bit is not set, then this object is white in the classic
        // tri-color sense: freshly discovered to be live, and we now need to
        // set its mark bit and then process its edges or push it onto the mark
        // stack for later edge processing.
        tracer.visit::<T>(addr);
    }
}

/// A unique id for each type that implements `IntoHeapAllocation`.
///
/// Implementation note: function types don't support Eq, so we cast to a
/// meaningless pointer type.
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct TypeId(*const ());

pub fn heap_type_id<'h, T: IntoHeapAllocation<'h>>() -> TypeId {
    TypeId(mark_entry_point::<T> as *const ())
}

pub(crate) const PAGE_SIZE: usize = 0x1000;

/// We rely on all bits to the right of this bit being 0 in addresses of
/// TypedPage instances.
pub(crate) const PAGE_ALIGN: usize = 0x1000;

fn is_aligned(ptr: *const ()) -> bool {
    ptr as usize & (PAGE_ALIGN - 1) == 0
}

pub struct PageHeader {
    pub heap: *mut GcHeap,
    next_page: *mut PageHeader,
    mark_bits: BitVec,
    allocated_bits: BitVec,
    mark_fn: unsafe fn(UntypedPointer, &mut MarkingTracer),
    freelist: *mut (),
}

impl PageHeader {
    pub fn find(ptr: UntypedPointer) -> *mut PageHeader {
        let header_addr = ptr.as_usize() & !(PAGE_ALIGN - 1);
        assert!(header_addr != 0);
        header_addr as *mut PageHeader
    }

    pub fn clear_mark_bits(&mut self) {
        self.mark_bits.clear();
    }

    /// True if nothing on this page is allocated.
    pub fn is_empty(&self) -> bool {
        self.allocated_bits.none()
    }

    pub unsafe fn mark(&self, ptr: UntypedPointer, tracer: &mut MarkingTracer) {
        (self.mark_fn)(ptr, tracer);
    }

    pub fn type_id(&self) -> TypeId {
        TypeId(self.mark_fn as *const ())
    }

    pub fn downcast_mut<'h, T>(&mut self) -> Option<&mut TypedPage<T::In>>
    where
        T: IntoHeapAllocation<'h>,
    {
        if heap_type_id::<T>() == self.type_id() {
            let ptr = self as *mut PageHeader as *mut TypedPage<T::In>;
            Some(unsafe { &mut *ptr })
        } else {
            None
        }
    }
}

pub struct TypedPage<U> {
    pub header: PageHeader,
    pub allocations: PhantomData<U>,
}

impl<U> Deref for TypedPage<U> {
    type Target = PageHeader;

    fn deref(&self) -> &PageHeader {
        &self.header
    }
}

impl<U> DerefMut for TypedPage<U> {
    fn deref_mut(&mut self) -> &mut PageHeader {
        &mut self.header
    }
}

/// Returns the smallest multiple of `k` that is at least `n`.
///
/// Panics if the answer is too big to fit in a `usize`.
fn round_up(n: usize, k: usize) -> usize {
    let a = n / k * k;
    if a == n {
        n
    } else {
        n + k
    }
}

impl<U> TypedPage<U> {
    /// The actual size of an allocation can't be smaller than the size of a
    /// pointer, due to the way we store the freelist by stealing a pointer
    /// from the allocation itself.
    fn allocation_size() -> usize {
        cmp::max(mem::size_of::<U>(), mem::size_of::<*mut U>())
    }

    fn allocation_align() -> usize {
        cmp::max(mem::align_of::<U>(), mem::align_of::<*mut U>())
    }

    /// Offset, in bytes, of the first allocation from the start of the page.
    pub(crate) fn first_allocation_offset() -> usize {
        round_up(mem::size_of::<PageHeader>(), Self::allocation_align())
    }

    /// Number of allocations that fit in a page.
    pub fn capacity() -> usize {
        (PAGE_SIZE - Self::first_allocation_offset()) / Self::allocation_size()
    }

    fn first_object_addr(&self) -> usize {
        (self as *const Self as usize) + Self::first_allocation_offset()
    }

    unsafe fn init_freelist(&mut self) {
        let mut addr = self.first_object_addr();
        for _ in 0..Self::capacity() {
            self.add_to_free_list(addr as *mut U);

            // This can't use `ptr = ptr.offset(1)` because if U is smaller
            // than a pointer, allocations are padded to pointer size.
            // `.offset(1)` doesn't know about the padding and therefore
            // wouldn't advance to the next allocation.
            addr += Self::allocation_size();
        }
    }

    /// Return the page containing the object `ptr` points to.
    pub fn find(ptr: Pointer<U>) -> *mut TypedPage<U> {
        PageHeader::find(ptr.into()) as *mut TypedPage<U>
    }

    unsafe fn add_to_free_list(&mut self, p: *mut U) {
        let listp = p as *mut *mut ();
        *listp = self.header.freelist;
        assert_eq!(*listp, self.header.freelist);
        self.header.freelist = p as *mut ();
    }

    unsafe fn allocation_index(&self, ptr: Pointer<U>) -> usize {
        let base = self.first_object_addr();

        // Check that ptr is in range.
        assert!(ptr.as_void() >= base as _);
        assert!(ptr.as_void() < (base + (Self::capacity() * Self::allocation_size())) as _);

        let index = (ptr.as_usize() - base as usize) / Self::allocation_size();
        assert_eq!(
            (base + index * Self::allocation_size()) as *const (),
            ptr.as_void()
        );
        index
    }

    pub unsafe fn get_mark_bit(&mut self, ptr: Pointer<U>) -> bool {
        let index = self.allocation_index(ptr);
        self.header.mark_bits[index]
    }

    pub unsafe fn set_mark_bit(&mut self, ptr: Pointer<U>) {
        let index = self.allocation_index(ptr);
        assert!(self.header.allocated_bits.get(index).unwrap(),
                "marking memory that isn't allocated (dangling pointer?)");
        self.header.mark_bits.set(index, true);
    }

    /// Allocate a `U`-sized-and-aligned region of uninitialized memory
    /// from this page.
    ///
    /// # Safety
    ///
    /// This is safe unless GC is happening.
    pub unsafe fn try_alloc(&mut self) -> Option<Pointer<U>> {
        let p = self.header.freelist;
        if p.is_null() {
            None
        } else {
            let listp = p as *mut *mut ();
            self.header.freelist = *listp;
            let ap = Pointer::new(p as *mut U);
            let index = self.allocation_index(ap);
            assert!(!self.header.allocated_bits[index]);
            self.header.allocated_bits.set(index, true);
            Some(ap)
        }
    }

    unsafe fn sweep(&mut self) {
        let mut addr = self.first_object_addr();
        for i in 0..Self::capacity() {
            if self.header.allocated_bits[i] && !self.header.mark_bits[i] {
                ptr::drop_in_place(addr as *mut U);
                if cfg!(debug_assertions) || cfg!(test) {
                    // Paint the unused memory with a known-bad value.
                    const SWEPT_BYTE: u8 = 0xf4;
                    ptr::write_bytes(addr as *mut U, SWEPT_BYTE, 1);
                }
                self.header.allocated_bits.set(i, false);
                self.add_to_free_list(addr as *mut U);
            }
            addr += Self::allocation_size();
        }
    }
}

/// Sweep a page.
///
/// # Safety
///
/// This must be called only after a full mark phase, to avoid sweeping objects
/// that are still reachable.
unsafe fn sweep_entry_point<'h, T: IntoHeapAllocation<'h>>(header: &mut PageHeader) {
    header.downcast_mut::<T>().expect("page header corrupted").sweep();
}

/// An unordered collection of memory pages that all share an allocation type.
pub struct PageSet {
    heap: *mut GcHeap,

    sweep_fn: unsafe fn(&mut PageHeader),

    /// The collection of pages.
    ///
    /// All pages in this collection have matching `.heap`, `.mark_fn`, and
    /// `.sweep_fn` fields.
    pages: *mut PageHeader,

    /// The maximum number of pages, or None for no limit.
    limit: Option<usize>,
}

impl Drop for PageSet {
    fn drop(&mut self) {
        unsafe {
            let mut p = self.pages;
            while !p.is_null() {
                let next = (*p).next_page;
                ptr::drop_in_place(p); // drop the header
                Vec::from_raw_parts(p as *mut u8, 0, PAGE_SIZE); // free the page
                p = next;
            }
        }
    }
}

impl PageSet {
    /// Create a new PageSet.
    ///
    /// # Safety
    ///
    /// Safe as long as `heap` is a valid pointer.
    pub unsafe fn new<'h, T: IntoHeapAllocation<'h>>(heap: *mut GcHeap) -> PageSet {
        PageSet {
            heap,
            sweep_fn: sweep_entry_point::<T>,
            pages: ptr::null_mut(),
            limit: None,
        }
    }

    /// Downcast to a typed PageSetRef.
    ///
    /// # Panics
    ///
    /// If T is not the actual allocation type for this page set.
    pub fn downcast_mut<'a, 'h, T>(&'a mut self) -> PageSetRef<'a, 'h, T>
    where
        T: IntoHeapAllocation<'h> + 'a,
    {
        assert_eq!(
            self.sweep_fn as *const (),
            sweep_entry_point::<T> as *const ()
        );

        PageSetRef {
            page_set: self,
            id: PhantomData,
            also: PhantomData,
        }
    }

    /// Clear mark bits from each page in this set.
    ///
    /// # Safety
    ///
    /// This must be called only at the beginning of a GC cycle.
    pub unsafe fn clear_mark_bits(&mut self) {
        let mut page = self.pages;
        while !page.is_null() {
            (*page).clear_mark_bits();
            page = (*page).next_page;
        }
    }

    /// Sweep all unmarked objects from all pages.
    ///
    /// # Safety
    ///
    /// Safe to call only as the final part of GC.
    pub unsafe fn sweep(&mut self) {
        let mut page = self.pages;
        while !page.is_null() {
            (self.sweep_fn)(&mut *page);
            page = (*page).next_page;
        }
    }

    /// Assert that nothing is allocated in this set of pages.
    pub fn all_pages_are_empty(&self) -> bool {
        unsafe {
            let mut page = self.pages;
            while !page.is_null() {
                if !(*page).is_empty() {
                    return false;
                }
                page = (*page).next_page;
            }
        }
        true
    }
}

pub struct PageSetRef<'a, 'h, T: IntoHeapAllocation<'h> + 'a> {
    page_set: &'a mut PageSet,
    id: HeapSessionId<'h>,
    also: PhantomData<&'a mut T>,
}

impl<'a, 'h, T: IntoHeapAllocation<'h> + 'a> PageSetRef<'a, 'h, T> {
    pub fn set_page_limit(&mut self, limit: Option<usize>) {
        self.page_set.limit = limit;
    }

    /// Allocate memory for a value of type `T::In`.
    ///
    /// # Safety
    ///
    /// Safe to call as long as GC is not happening.
    pub unsafe fn try_alloc(&mut self) -> Option<Pointer<T::In>> {
        // First, try to allocate from each existing page. (Obviously slow.)
        let mut page = self.page_set.pages;
        let mut page_count = 0;
        while !page.is_null() {
            let t_page = (*page).downcast_mut::<T>().unwrap();
            if let Some(ptr) = t_page.try_alloc() {
                return Some(ptr);
            }

            page_count += 1;
            page = (*page).next_page;
        }

        // If there is a limit and we already have at least that many pages, fail.
        match self.page_set.limit {
            Some(limit) if page_count >= limit => None,
            _ => self.new_page().try_alloc(),
        }
    }

    /// Allocate a page from the operating system.
    ///
    /// Initialize its header and freelist and link it into this page set's
    /// linked list of pages.
    fn new_page(&mut self) -> &mut TypedPage<T::In> {
        assert!({
            let size_of_page = mem::size_of::<TypedPage<T::In>>();
            let alloc_offset = TypedPage::<T::In>::first_allocation_offset();
            size_of_page <= alloc_offset
        });
        assert!({
            let alloc_offset = TypedPage::<T::In>::first_allocation_offset();
            let alloc_size = TypedPage::<T::In>::allocation_size();
            let capacity = TypedPage::<T::In>::capacity();
            alloc_offset + capacity * alloc_size <= PAGE_SIZE
        });

        let mut vec: Vec<u8> = Vec::with_capacity(PAGE_SIZE);
        let raw_page = vec.as_mut_ptr() as *mut ();

        // Rust makes no guarantee whatsoever that this will work.
        // If it doesn't, panic.
        assert!(is_aligned(raw_page));

        let page_ptr: *mut TypedPage<T::In> = raw_page as *mut TypedPage<T::In>;
        let capacity = TypedPage::<T::In>::capacity();
        unsafe {
            ptr::write(
                page_ptr,
                TypedPage {
                    header: PageHeader {
                        heap: self.page_set.heap,
                        next_page: self.page_set.pages,
                        mark_bits: BitVec::from_elem(capacity, false),
                        allocated_bits: BitVec::from_elem(capacity, false),
                        mark_fn: mark_entry_point::<T>,
                        freelist: ptr::null_mut(),
                    },
                    allocations: PhantomData,
                },
            );

            let page = &mut *page_ptr;
            page.init_freelist();

            // Remove the memory from the vector and link it into
            // the PageSet's linked list.
            mem::forget(vec);
            self.page_set.pages = &mut page.header;

            page
        }
    }
}
<|endoftext|>


<commit_before>//! Defines the scene struct which contains the various objects defining the scene.
//! This includes the geometry, instances of the geometry, the camera and so on.

use std::sync::Arc;

use linalg::{Transform, Point, Vector};
use film::{Camera};
use geometry::{Sphere, Instance};
use geometry::Geometry;
use integrator::{HitMarker, Integrator};

/// The scene containing the objects and camera configuration we'd like to render,
/// shared immutably among the ray tracing threads
pub struct Scene {
    pub camera: Arc<Camera>,
    pub instance: Arc<Instance>,
    pub integrator: Arc<Box<Integrator + Send + Sync>>,
    sphere: Arc<Box<Geometry + Send + Sync>>,
}

impl Scene {
    /// Create our (currently) hard-coded scene, passing in the render target
    /// dimensions so we can set the projection matrix for the camera
    pub fn new(w: uint, h: uint) -> Scene {
        let sphere = Arc::new(box Sphere::new(1.5)
                              as Box<Geometry + Send + Sync>);
        Scene {
            camera: Arc::new(Camera::new(Transform::look_at(&Point::new(0.0, 0.0, -10.0),
                &Point::new(0.0, 0.0, 0.0), &Vector::new(0.0, 1.0, 0.0)), 40.0, (w, h))),
            instance: Arc::new(Instance::new(sphere.clone(),
                Transform::translate(&Vector::new(0.0, 2.0, 0.0)))),
            integrator: Arc::new(box HitMarker as Box<Integrator + Send + Sync>),
            sphere: sphere.clone(),
        }
    }
}

<commit_msg>Tweak formatting<commit_after>//! Defines the scene struct which contains the various objects defining the scene.
//! This includes the geometry, instances of the geometry, the camera and so on.

use std::sync::Arc;

use linalg::{Transform, Point, Vector};
use film::{Camera};
use geometry::{Sphere, Instance};
use geometry::Geometry;
use integrator::{HitMarker, Integrator};

/// The scene containing the objects and camera configuration we'd like to render,
/// shared immutably among the ray tracing threads
pub struct Scene {
    pub camera: Arc<Camera>,
    pub instance: Arc<Instance>,
    pub integrator: Arc<Box<Integrator + Send + Sync>>,
    sphere: Arc<Box<Geometry + Send + Sync>>,
}

impl Scene {
    /// Create our (currently) hard-coded scene, passing in the render target
    /// dimensions so we can set the projection matrix for the camera
    pub fn new(w: uint, h: uint) -> Scene {
        let sphere = Arc::new(box Sphere::new(1.5) as Box<Geometry + Send + Sync>);
        Scene {
            camera: Arc::new(Camera::new(Transform::look_at(&Point::new(0.0, 0.0, -10.0),
                &Point::new(0.0, 0.0, 0.0), &Vector::new(0.0, 1.0, 0.0)), 40.0, (w, h))),
            instance: Arc::new(Instance::new(sphere.clone(),
                Transform::translate(&Vector::new(0.0, 2.0, 0.0)))),
            integrator: Arc::new(box HitMarker as Box<Integrator + Send + Sync>),
            sphere: sphere.clone(),
        }
    }
}

<|endoftext|>


<commit_before>//! Solve systems of linear equations and invert matrices
//!
//! # Examples
//!
//! Solve `A * x = b`:
//!
//! ```
//! #[macro_use]
//! extern crate ndarray;
//! extern crate ndarray_linalg;
//!
//! use ndarray::prelude::*;
//! use ndarray_linalg::Solve;
//! # fn main() {
//!
//! let a: Array2<f64> = array![[3., 2., -1.], [2., -2., 4.], [-2., 1., -2.]];
//! let b: Array1<f64> = array![1., -2., 0.];
//! let x = a.solve_into(b).unwrap();
//! assert!(x.all_close(&array![1., -2., -2.], 1e-9));
//!
//! # }
//! ```
//!
//! There are also special functions for solving `A^T * x = b` and
//! `A^H * x = b`.
//!
//! If you are solving multiple systems of linear equations with the same
//! coefficient matrix `A`, it's faster to compute the LU factorization once at
//! the beginning than solving directly using `A`:
//!
//! ```
//! # extern crate ndarray;
//! # extern crate ndarray_linalg;
//! use ndarray::prelude::*;
//! use ndarray_linalg::*;
//! # fn main() {
//!
//! let a: Array2<f64> = random((3, 3));
//! let f = a.factorize_into().unwrap(); // LU factorize A (A is consumed)
//! for _ in 0..10 {
//!     let b: Array1<f64> = random(3);
//!     let x = f.solve_into(b).unwrap(); // Solve A * x = b using factorized L, U
//! }
//!
//! # }
//! ```

use ndarray::*;

use super::convert::*;
use super::error::*;
use super::layout::*;
use super::types::*;

pub use lapack_traits::{Pivot, Transpose};

/// An interface for solving systems of linear equations.
///
/// There are three groups of methods:
///
/// * `solve*` (normal) methods solve `A * x = b` for `x`.
/// * `solve_t*` (tranpose) methods solve `A^T * x = b` for `x`.
/// * `solve_h*` (conjugate transpose) methods solve `A^H * x = b` for `x`.
///
/// Within each group, there are three methods that handle ownership differently:
///
/// * `*` methods take a reference to `b` and return `x` as a new array.
/// * `*_into` methods take ownership of `b`, store the result in it, and return it.
/// * `*_mut` methods take a mutable reference to `b` and store the result in that array.
///
/// If you plan to solve many equations with the same `A` matrix but different
/// `b` vectors, it's faster to factor the `A` matrix once using the
/// `Factorize` trait, and then solve using the `Factorized` struct.
pub trait Solve<A: Scalar> {
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;

    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_t_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_t_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;

    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_h_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_h_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;
}

/// Represents the LU factorization of a matrix `A` as `A = P*L*U`.
pub struct Factorized<S: Data> {
    /// The factors `L` and `U`; the unit diagonal elements of `L` are not
    /// stored.
    pub a: ArrayBase<S, Ix2>,
    /// The pivot indices that define the permutation matrix `P`.
    pub ipiv: Pivot,
}

impl<A, S> Solve<A> for Factorized<S>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    fn solve_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::No,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
    fn solve_t_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::Transpose,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
    fn solve_h_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::Hermite,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
}

impl<A, S> Solve<A> for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    fn solve_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_mut(rhs)
    }
    fn solve_t_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_t_mut(rhs)
    }
    fn solve_h_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_h_mut(rhs)
    }
}

impl<A, S> Factorized<S>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    /// Computes the inverse of the factorized matrix.
    pub fn into_inverse(mut self) -> Result<ArrayBase<S, Ix2>> {
        unsafe {
            A::inv(
                self.a.square_layout()?,
                self.a.as_allocated_mut()?,
                &self.ipiv,
            )?
        };
        Ok(self.a)
    }
}

/// An interface for computing LU factorizations of matrix refs.
pub trait Factorize<S: Data> {
    /// Computes the LU factorization `A = P*L*U`, where `P` is a permutation
    /// matrix.
    fn factorize(&self) -> Result<Factorized<S>>;
}

/// An interface for computing LU factorizations of matrices.
pub trait FactorizeInto<S: Data> {
    /// Computes the LU factorization `A = P*L*U`, where `P` is a permutation
    /// matrix.
    fn factorize_into(self) -> Result<Factorized<S>>;
}

impl<A, S> FactorizeInto<S> for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    fn factorize_into(mut self) -> Result<Factorized<S>> {
        let ipiv = unsafe { A::lu(self.layout()?, self.as_allocated_mut()?)? };
        Ok(Factorized {
            a: self,
            ipiv: ipiv,
        })
    }
}

impl<A, Si> Factorize<OwnedRepr<A>> for ArrayBase<Si, Ix2>
where
    A: Scalar,
    Si: Data<Elem = A>,
{
    fn factorize(&self) -> Result<Factorized<OwnedRepr<A>>> {
        let mut a: Array2<A> = replicate(self);
        let ipiv = unsafe { A::lu(a.layout()?, a.as_allocated_mut()?)? };
        Ok(Factorized { a: a, ipiv: ipiv })
    }
}

/// An interface for inverting matrix refs.
pub trait Inverse {
    type Output;
    /// Computes the inverse of the matrix.
    fn inv(&self) -> Result<Self::Output>;
}

/// An interface for inverting matrices.
pub trait InverseInto {
    type Output;
    /// Computes the inverse of the matrix.
    fn inv_into(self) -> Result<Self::Output>;
}

impl<A, S> InverseInto for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    type Output = Self;

    fn inv_into(self) -> Result<Self::Output> {
        let f = self.factorize_into()?;
        f.into_inverse()
    }
}

impl<A, Si> Inverse for ArrayBase<Si, Ix2>
where
    A: Scalar,
    Si: Data<Elem = A>,
{
    type Output = Array2<A>;

    fn inv(&self) -> Result<Self::Output> {
        let f = self.factorize()?;
        f.into_inverse()
    }
}
<commit_msg>Fix typo and wording in solve docs<commit_after>//! Solve systems of linear equations and invert matrices
//!
//! # Examples
//!
//! Solve `A * x = b`:
//!
//! ```
//! #[macro_use]
//! extern crate ndarray;
//! extern crate ndarray_linalg;
//!
//! use ndarray::prelude::*;
//! use ndarray_linalg::Solve;
//! # fn main() {
//!
//! let a: Array2<f64> = array![[3., 2., -1.], [2., -2., 4.], [-2., 1., -2.]];
//! let b: Array1<f64> = array![1., -2., 0.];
//! let x = a.solve_into(b).unwrap();
//! assert!(x.all_close(&array![1., -2., -2.], 1e-9));
//!
//! # }
//! ```
//!
//! There are also special functions for solving `A^T * x = b` and
//! `A^H * x = b`.
//!
//! If you are solving multiple systems of linear equations with the same
//! coefficient matrix `A`, it's faster to compute the LU factorization once at
//! the beginning than solving directly using `A`:
//!
//! ```
//! # extern crate ndarray;
//! # extern crate ndarray_linalg;
//! use ndarray::prelude::*;
//! use ndarray_linalg::*;
//! # fn main() {
//!
//! let a: Array2<f64> = random((3, 3));
//! let f = a.factorize_into().unwrap(); // LU factorize A (A is consumed)
//! for _ in 0..10 {
//!     let b: Array1<f64> = random(3);
//!     let x = f.solve_into(b).unwrap(); // Solve A * x = b using factorized L, U
//! }
//!
//! # }
//! ```

use ndarray::*;

use super::convert::*;
use super::error::*;
use super::layout::*;
use super::types::*;

pub use lapack_traits::{Pivot, Transpose};

/// An interface for solving systems of linear equations.
///
/// There are three groups of methods:
///
/// * `solve*` (normal) methods solve `A * x = b` for `x`.
/// * `solve_t*` (transpose) methods solve `A^T * x = b` for `x`.
/// * `solve_h*` (Hermitian conjugate) methods solve `A^H * x = b` for `x`.
///
/// Within each group, there are three methods that handle ownership differently:
///
/// * `*` methods take a reference to `b` and return `x` as a new array.
/// * `*_into` methods take ownership of `b`, store the result in it, and return it.
/// * `*_mut` methods take a mutable reference to `b` and store the result in that array.
///
/// If you plan to solve many equations with the same `A` matrix but different
/// `b` vectors, it's faster to factor the `A` matrix once using the
/// `Factorize` trait, and then solve using the `Factorized` struct.
pub trait Solve<A: Scalar> {
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;

    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_t_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_t_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^T * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_t_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;

    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h<S: Data<Elem = A>>(&self, b: &ArrayBase<S, Ix1>) -> Result<Array1<A>> {
        let mut b = replicate(b);
        self.solve_h_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h_into<S: DataMut<Elem = A>>(&self, mut b: ArrayBase<S, Ix1>) -> Result<ArrayBase<S, Ix1>> {
        self.solve_h_mut(&mut b)?;
        Ok(b)
    }
    /// Solves a system of linear equations `A^H * x = b` where `A` is `self`, `b`
    /// is the argument, and `x` is the successful result.
    fn solve_h_mut<'a, S: DataMut<Elem = A>>(&self, &'a mut ArrayBase<S, Ix1>) -> Result<&'a mut ArrayBase<S, Ix1>>;
}

/// Represents the LU factorization of a matrix `A` as `A = P*L*U`.
pub struct Factorized<S: Data> {
    /// The factors `L` and `U`; the unit diagonal elements of `L` are not
    /// stored.
    pub a: ArrayBase<S, Ix2>,
    /// The pivot indices that define the permutation matrix `P`.
    pub ipiv: Pivot,
}

impl<A, S> Solve<A> for Factorized<S>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    fn solve_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::No,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
    fn solve_t_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::Transpose,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
    fn solve_h_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        unsafe {
            A::solve(
                self.a.square_layout()?,
                Transpose::Hermite,
                self.a.as_allocated()?,
                &self.ipiv,
                rhs.as_slice_mut().unwrap(),
            )?
        };
        Ok(rhs)
    }
}

impl<A, S> Solve<A> for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    fn solve_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_mut(rhs)
    }
    fn solve_t_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_t_mut(rhs)
    }
    fn solve_h_mut<'a, Sb>(&self, mut rhs: &'a mut ArrayBase<Sb, Ix1>) -> Result<&'a mut ArrayBase<Sb, Ix1>>
    where
        Sb: DataMut<Elem = A>,
    {
        let f = self.factorize()?;
        f.solve_h_mut(rhs)
    }
}

impl<A, S> Factorized<S>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    /// Computes the inverse of the factorized matrix.
    pub fn into_inverse(mut self) -> Result<ArrayBase<S, Ix2>> {
        unsafe {
            A::inv(
                self.a.square_layout()?,
                self.a.as_allocated_mut()?,
                &self.ipiv,
            )?
        };
        Ok(self.a)
    }
}

/// An interface for computing LU factorizations of matrix refs.
pub trait Factorize<S: Data> {
    /// Computes the LU factorization `A = P*L*U`, where `P` is a permutation
    /// matrix.
    fn factorize(&self) -> Result<Factorized<S>>;
}

/// An interface for computing LU factorizations of matrices.
pub trait FactorizeInto<S: Data> {
    /// Computes the LU factorization `A = P*L*U`, where `P` is a permutation
    /// matrix.
    fn factorize_into(self) -> Result<Factorized<S>>;
}

impl<A, S> FactorizeInto<S> for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    fn factorize_into(mut self) -> Result<Factorized<S>> {
        let ipiv = unsafe { A::lu(self.layout()?, self.as_allocated_mut()?)? };
        Ok(Factorized {
            a: self,
            ipiv: ipiv,
        })
    }
}

impl<A, Si> Factorize<OwnedRepr<A>> for ArrayBase<Si, Ix2>
where
    A: Scalar,
    Si: Data<Elem = A>,
{
    fn factorize(&self) -> Result<Factorized<OwnedRepr<A>>> {
        let mut a: Array2<A> = replicate(self);
        let ipiv = unsafe { A::lu(a.layout()?, a.as_allocated_mut()?)? };
        Ok(Factorized { a: a, ipiv: ipiv })
    }
}

/// An interface for inverting matrix refs.
pub trait Inverse {
    type Output;
    /// Computes the inverse of the matrix.
    fn inv(&self) -> Result<Self::Output>;
}

/// An interface for inverting matrices.
pub trait InverseInto {
    type Output;
    /// Computes the inverse of the matrix.
    fn inv_into(self) -> Result<Self::Output>;
}

impl<A, S> InverseInto for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    type Output = Self;

    fn inv_into(self) -> Result<Self::Output> {
        let f = self.factorize_into()?;
        f.into_inverse()
    }
}

impl<A, Si> Inverse for ArrayBase<Si, Ix2>
where
    A: Scalar,
    Si: Data<Elem = A>,
{
    type Output = Array2<A>;

    fn inv(&self) -> Result<Self::Output> {
        let f = self.factorize()?;
        f.into_inverse()
    }
}
<|endoftext|>


<commit_before>use State;
use GLOBALSINDEX;
use Type;
use raw;

use libc;
use std::thread::Thread;
use std::any::AnyRefExt;

#[test]
fn test_state_init() {
    let mut _s = State::new();
}

#[test]
#[should_fail]
fn test_error() {
    let mut s = State::new();
    s.pushinteger(42);
    s.error()
}

#[test]
fn test_errorstr() {
    let res = Thread::spawn::<(), _>(move || {
        let mut s = State::new();
        s.errorstr("some err");
    }).join();
    let err = res.unwrap_err();
    let expected = "unprotected error in call to Lua API (some err)";
    let s = err.downcast_ref::<String>();
    if s.is_some() {
        assert_eq!(s.unwrap().as_slice(), expected);
    } else {
        let s = err.downcast_ref::<&'static str>();
        if s.is_some() {
            assert_eq!(*s.unwrap(), expected);
        } else {
            panic!("unexpected failure result");
        }
    }
}

#[test]
fn test_describe() {
    let mut s = State::new();

    assert_eq!(s.typename(1), "no value");
    s.pushnil();
    assert_eq!(s.typename(-1), "nil");
    s.pushinteger(42);
    assert_eq!(s.typename(-1), "number");
    s.pushstring("test");
    assert_eq!(s.typename(-1), "string");
    s.pushboolean(true);
    assert_eq!(s.typename(-1), "boolean");
    s.pushcfunction(dummy);
    assert_eq!(s.typename(-1), "function");

    extern "C" fn dummy(_L: *mut ::raw::lua_State) -> ::libc::c_int {
        0
    }
}

#[test]
fn test_openlibs() {
    let mut s = State::new();

    s.openlibs();
    s.getfield(GLOBALSINDEX, "table");
    assert_eq!(s.type_(-1), Some(Type::Table));
}

#[derive(Copy,PartialEq,Eq,Show)]
enum CheckOptionEnum {
    One,
    Two,
    Three
}

#[test]
fn test_checkoption() {
    let lst = [("one", CheckOptionEnum::One),
               ("two", CheckOptionEnum::Two),
               ("three", CheckOptionEnum::Three)];

    let mut s = State::new();

    for &(k,ref v) in lst.iter() {
        s.pushstring(k);
        assert_eq!(*s.checkoption(1, None, &lst), *v);
        s.pop(1);
    }
    assert_eq!(*s.checkoption(1, Some("three"), &lst), CheckOptionEnum::Three);

    let res = Thread::spawn(move || {
        let mut s = State::new();
        s.checkoption(1, None, &lst);
    }).join();
    assert!(res.is_err(), "expected error from checkoption");

    let res = Thread::spawn(move || {
        let mut s = State::new();
        s.checkoption(1, Some("four"), &lst);
    }).join();
    assert!(res.is_err(), "expected error from checkoption");
}

#[test]
fn test_tocfunction() {
    let mut s = State::new();

    // extern "C" fns don't implement Eq, so cast them to a pointer instead

    s.pushstring("foo");
    assert_eq!(s.tocfunction(1).map(|f| f as *const ()), None);

    s.pushcfunction(cfunc);
    assert_eq!(s.tocfunction(2).map(|f| f as *const ()), Some(cfunc as *const ()));

    extern "C" fn cfunc(_L: *mut raw::lua_State) -> libc::c_int { 0 }
}

#[test]
fn test_gsub() {
    // do some pretty basic gsub tests
    let mut L = State::new();

    assert_eq!(L.gsub("foobar", "bar", "quux"), "fooquux");
    assert_eq!(L.gsub("foo", "o", "ö"), "föö");
    assert_eq!(L.gsub("test", "a", "b"), "test");
    assert_eq!(L.gsub("a b c d e", " ", "."), "a.b.c.d.e");
}
<commit_msg>Update for latest rustc master<commit_after>use State;
use GLOBALSINDEX;
use Type;
use raw;

use libc;
use std::thread::Thread;

#[test]
fn test_state_init() {
    let mut _s = State::new();
}

#[test]
#[should_fail]
fn test_error() {
    let mut s = State::new();
    s.pushinteger(42);
    s.error()
}

#[test]
fn test_errorstr() {
    let res = Thread::spawn::<(), _>(move || {
        let mut s = State::new();
        s.errorstr("some err");
    }).join();
    let err = res.unwrap_err();
    let expected = "unprotected error in call to Lua API (some err)";
    let s = err.downcast_ref::<String>();
    if s.is_some() {
        assert_eq!(s.unwrap().as_slice(), expected);
    } else {
        let s = err.downcast_ref::<&'static str>();
        if s.is_some() {
            assert_eq!(*s.unwrap(), expected);
        } else {
            panic!("unexpected failure result");
        }
    }
}

#[test]
fn test_describe() {
    let mut s = State::new();

    assert_eq!(s.typename(1), "no value");
    s.pushnil();
    assert_eq!(s.typename(-1), "nil");
    s.pushinteger(42);
    assert_eq!(s.typename(-1), "number");
    s.pushstring("test");
    assert_eq!(s.typename(-1), "string");
    s.pushboolean(true);
    assert_eq!(s.typename(-1), "boolean");
    s.pushcfunction(dummy);
    assert_eq!(s.typename(-1), "function");

    extern "C" fn dummy(_L: *mut ::raw::lua_State) -> ::libc::c_int {
        0
    }
}

#[test]
fn test_openlibs() {
    let mut s = State::new();

    s.openlibs();
    s.getfield(GLOBALSINDEX, "table");
    assert_eq!(s.type_(-1), Some(Type::Table));
}

#[derive(Copy,PartialEq,Eq,Show)]
enum CheckOptionEnum {
    One,
    Two,
    Three
}

#[test]
fn test_checkoption() {
    let lst = [("one", CheckOptionEnum::One),
               ("two", CheckOptionEnum::Two),
               ("three", CheckOptionEnum::Three)];

    let mut s = State::new();

    for &(k,ref v) in lst.iter() {
        s.pushstring(k);
        assert_eq!(*s.checkoption(1, None, &lst), *v);
        s.pop(1);
    }
    assert_eq!(*s.checkoption(1, Some("three"), &lst), CheckOptionEnum::Three);

    let res = Thread::spawn(move || {
        let mut s = State::new();
        s.checkoption(1, None, &lst);
    }).join();
    assert!(res.is_err(), "expected error from checkoption");

    let res = Thread::spawn(move || {
        let mut s = State::new();
        s.checkoption(1, Some("four"), &lst);
    }).join();
    assert!(res.is_err(), "expected error from checkoption");
}

#[test]
fn test_tocfunction() {
    let mut s = State::new();

    // extern "C" fns don't implement Eq, so cast them to a pointer instead

    s.pushstring("foo");
    assert_eq!(s.tocfunction(1).map(|f| f as *const ()), None);

    s.pushcfunction(cfunc);
    assert_eq!(s.tocfunction(2).map(|f| f as *const ()), Some(cfunc as *const ()));

    extern "C" fn cfunc(_L: *mut raw::lua_State) -> libc::c_int { 0 }
}

#[test]
fn test_gsub() {
    // do some pretty basic gsub tests
    let mut L = State::new();

    assert_eq!(L.gsub("foobar", "bar", "quux"), "fooquux");
    assert_eq!(L.gsub("foo", "o", "ö"), "föö");
    assert_eq!(L.gsub("test", "a", "b"), "test");
    assert_eq!(L.gsub("a b c d e", " ", "."), "a.b.c.d.e");
}
<|endoftext|>


<commit_before>use crate::errors;
#[cfg(feature = "std")]
use core::fmt::{self, Display};
use core::{iter::FromIterator, result};

#[cfg(feature = "std")]
use std::{convert::{TryFrom, TryInto}, time::{Duration, SystemTime, UNIX_EPOCH}};

use crate::alloc::{string::{ String, ToString }, vec::Vec};

/// A time tag in OSC message consists of two 32-bit integers where the first one denotes the number of seconds since 1900-01-01 and the second the fractions of a second.
/// For details on its semantics see http://opensoundcontrol.org/node/3/#timetags
///
/// # Examples
///
/// ```
/// #[cfg(feature = "std")]
/// {
///     use rosc::OscTime;
///     use std::{convert::TryFrom, time::UNIX_EPOCH};
///
///     assert_eq!(
///         OscTime::try_from(UNIX_EPOCH).unwrap(),
///         OscTime::from((2_208_988_800, 0))
///     );
/// }
/// ```
///
/// # Conversions between `(u32, u32)`
///
/// Prior to version `0.5.0` of this crate, `OscTime` was defined as a type alias to `(u32, u32)`.
/// If you are upgrading from one of these older versions, you can use [`.into()`](Into::into) to
/// convert between `(u32, u32)` and `OscTime` in either direction.
///
/// # Conversions between [`std::time::SystemTime`]
///
/// The traits in `std::convert` are implemented for converting between
/// [`SystemTime`](std::time::SystemTime) and `OscTime` in both directions. An `OscTime` can be
/// converted into a `SystemTime` using [`From`](std::convert::From)/[`Into`](std::convert::Into).
/// A `SystemTime` can be converted into an `OscTime` using
/// [`TryFrom`](std::convert::TryFrom)/[`TryInto`](std::convert::TryInto). The fallible variants of
/// the conversion traits are used this case because not every `SystemTime` can be represented as
/// an `OscTime`.
///
/// **These conversions are lossy**, but are tested to have a deviation within
/// 5 nanoseconds when converted back and forth in either direction.
///
/// Although any time since the OSC epoch (`1900-01-01 00:00:00 UTC`) can be represented using the
/// OSC timestamp format, this crate only allows conversions between times greater than or equal to
/// the [`UNIX_EPOCH`](std::time::UNIX_EPOCH). This allows the math used in the conversions to work
/// on 32-bit systems which cannot represent times that far back.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OscTime {
    pub seconds: u32,
    pub fractional: u32,
}

#[cfg(feature = "std")]
impl OscTime {
    const UNIX_OFFSET: u64 = 2_208_988_800; // From RFC 5905
    const TWO_POW_32: f64 = (u32::MAX as f64) + 1.0; // Number of bits in a `u32`
    const ONE_OVER_TWO_POW_32: f64 = 1.0 / OscTime::TWO_POW_32;
    const NANOS_PER_SECOND: f64 = 1.0e9;
    const SECONDS_PER_NANO: f64 = 1.0 / OscTime::NANOS_PER_SECOND;
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscTime {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> core::result::Result<OscTime, OscTimeError> {
        let duration_since_epoch = time
            .duration_since(UNIX_EPOCH)
            .map_err(|_| OscTimeError(OscTimeErrorKind::BeforeEpoch))?
            + Duration::new(OscTime::UNIX_OFFSET, 0);
        let seconds = u32::try_from(duration_since_epoch.as_secs())
            .map_err(|_| OscTimeError(OscTimeErrorKind::Overflow))?;
        let nanos = duration_since_epoch.subsec_nanos() as f64;
        let fractional = (nanos * OscTime::SECONDS_PER_NANO * OscTime::TWO_POW_32).round() as u32;
        Ok(OscTime {
            seconds,
            fractional,
        })
    }
}

#[cfg(feature = "std")]
impl From<OscTime> for SystemTime {
    fn from(time: OscTime) -> SystemTime {
        let nanos =
            (time.fractional as f64) * OscTime::ONE_OVER_TWO_POW_32 * OscTime::NANOS_PER_SECOND;
        let duration_since_osc_epoch = Duration::new(time.seconds as u64, nanos.round() as u32);
        let duration_since_unix_epoch =
            duration_since_osc_epoch - Duration::new(OscTime::UNIX_OFFSET, 0);
        UNIX_EPOCH + duration_since_unix_epoch
    }
}

impl From<(u32, u32)> for OscTime {
    fn from(time: (u32, u32)) -> OscTime {
        let (seconds, fractional) = time;
        OscTime {
            seconds,
            fractional,
        }
    }
}

impl From<OscTime> for (u32, u32) {
    fn from(time: OscTime) -> (u32, u32) {
        (time.seconds, time.fractional)
    }
}

#[cfg(feature = "std")]
/// An error returned by conversions involving [`OscTime`].
#[derive(Debug)]
pub struct OscTimeError(OscTimeErrorKind);

#[cfg(feature = "std")]
#[derive(Debug)]
enum OscTimeErrorKind {
    BeforeEpoch,
    Overflow,
}

#[cfg(feature = "std")]
impl Display for OscTimeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            OscTimeErrorKind::BeforeEpoch => {
                write!(f, "time is before the unix epoch and cannot be stored")
            }
            OscTimeErrorKind::Overflow => {
                write!(f, "time overflows what OSC time can store")
            }
        }
    }
}

// impl error::Error for OscTimeError {}

/// see OSC Type Tag String: [OSC Spec. 1.0](http://opensoundcontrol.org/spec-1_0)
/// padding: zero bytes (n*4)
#[derive(Clone, Debug, PartialEq)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(OscTime),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Array(OscArray),
    Nil,
    Inf,
}
macro_rules! value_impl {
    ($(($name:ident, $variant:ident, $ty:ty)),*) => {
        $(
        impl OscType {
            #[allow(dead_code)]
            pub fn $name(self) -> Option<$ty> {
                match self {
                    OscType::$variant(v) => Some(v),
                    _ => None
                }
            }
        }
        impl From<$ty> for OscType {
            fn from(v: $ty) -> Self {
                OscType::$variant(v)
            }
        }
        )*
    }
}
value_impl! {
    (int, Int, i32),
    (float, Float, f32),
    (string, String, String),
    (blob, Blob, Vec<u8>),
    (array, Array, OscArray),
    (long, Long, i64),
    (double, Double, f64),
    (char, Char, char),
    (color, Color, OscColor),
    (midi, Midi, OscMidiMessage),
    (bool, Bool, bool)
}
impl From<(u32, u32)> for OscType {
    fn from(time: (u32, u32)) -> Self {
        OscType::Time(time.into())
    }
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscType {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> std::result::Result<OscType, OscTimeError> {
        time.try_into().map(OscType::Time)
    }
}

impl OscType {
    pub fn time(self) -> Option<OscTime> {
        match self {
            OscType::Time(time) => Some(time),
            _ => None,
        }
    }
}
impl<'a> From<&'a str> for OscType {
    fn from(string: &'a str) -> Self {
        OscType::String(string.to_string())
    }
}
/// Represents the parts of a Midi message. Mainly used for
/// tunneling midi over a network using the OSC protocol.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

/// An OSC message consists of an address and
/// zero or more arguments. The address should
/// specify an element of your Instrument (or whatever
/// you want to control with OSC) and the arguments
/// are used to set properties of the element to the
/// respective values.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMessage {
    pub addr: String,
    pub args: Vec<OscType>,
}

/// An OSC bundle contains zero or more OSC packets
/// and a time tag. The contained packets *should* be
/// applied at the given time tag.
#[derive(Clone, Debug, PartialEq)]
pub struct OscBundle {
    pub timetag: OscTime,
    pub content: Vec<OscPacket>,
}

/// An RGBA color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

/// An OscArray color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscArray {
    pub content: Vec<OscType>,
}

impl<T: Into<OscType>> FromIterator<T> for OscArray {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> OscArray {
        OscArray {
            content: iter.into_iter().map(T::into).collect(),
        }
    }
}

pub type Result<T> = result::Result<T, errors::OscError>;

impl From<String> for OscMessage {
    fn from(s: String) -> OscMessage {
        OscMessage {
            addr: s,
            args: vec![],
        }
    }
}
impl<'a> From<&'a str> for OscMessage {
    fn from(s: &str) -> OscMessage {
        OscMessage {
            addr: s.to_string(),
            args: vec![],
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "std")]
    use super::*;
    #[cfg(feature = "std")]
    use std::time::UNIX_EPOCH;

    #[cfg(feature = "std")]
    const TOLERANCE_NANOS: u64 = 5;

    #[cfg(feature = "std")]
    #[test]
    fn system_times_can_be_converted_to_and_from_osc() {
        let times = vec![UNIX_EPOCH, SystemTime::now()];
        for time in times {
            for i in 0..1000 {
                let time = time + Duration::from_nanos(1) * i;
                assert_eq_system_times(time, SystemTime::from(OscTime::try_from(time).unwrap()));
            }
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_times_can_be_converted_to_and_from_system_times() {
        let mut times = vec![];
        // Sweep across a few numbers to check for tolerance
        for seconds in vec![
            // We don't start at zero because times before the UNIX_EPOCH cannot be converted to
            // OscTime.
            OscTime::UNIX_OFFSET as u32,
            OscTime::UNIX_OFFSET as u32 + 1,
            OscTime::UNIX_OFFSET as u32 + 2,
            OscTime::UNIX_OFFSET as u32 + 3,
            u32::MAX - 1,
            u32::MAX,
        ] {
            let fractional_max = 100;
            for fractional in 0..fractional_max {
                times.push((seconds, fractional));
                times.push((seconds, fractional_max - fractional));
            }
        }

        for osc_time in times.into_iter().map(OscTime::from) {
            assert_eq_osc_times(
                osc_time,
                OscTime::try_from(SystemTime::from(osc_time)).unwrap(),
            );
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_time_cannot_represent_times_before_1970_01_01() {
        assert!(OscTime::try_from(UNIX_EPOCH - Duration::from_secs(1)).is_err())
    }

    #[cfg(feature = "std")]
    fn assert_eq_system_times(a: SystemTime, b: SystemTime) {
        let difference = if a < b {
            b.duration_since(a).unwrap()
        } else {
            a.duration_since(b).unwrap()
        };

        let tolerance = Duration::from_nanos(TOLERANCE_NANOS);

        if difference > tolerance {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {:?}",
                a, b, tolerance,
            );
        }
    }

    #[cfg(feature = "std")]
    fn assert_eq_osc_times(a: OscTime, b: OscTime) {
        // I did not want to implement subtraction with carrying in order to implement this in the
        // same way as the alternative for system times. Intsead we are compare each part of the
        // OSC times separately.
        let tolerance_fractional_seconds = ((TOLERANCE_NANOS as f64 * OscTime::TWO_POW_32)
            / OscTime::NANOS_PER_SECOND)
            .round() as i64;
        assert_eq!(
            a.seconds, b.seconds,
            "the seconds components of {:?} and {:?} are different",
            a, b
        );
        if (a.fractional as i64 - b.fractional as i64).abs() > tolerance_fractional_seconds {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {} fractional seconds",
                a, b, tolerance_fractional_seconds,
            );
        }
    }
}
<commit_msg>OscTime conversions tests: greater tolerance on Windows<commit_after>use crate::errors;
#[cfg(feature = "std")]
use core::fmt::{self, Display};
use core::{iter::FromIterator, result};

#[cfg(feature = "std")]
use std::{convert::{TryFrom, TryInto}, time::{Duration, SystemTime, UNIX_EPOCH}};

use crate::alloc::{string::{ String, ToString }, vec::Vec};

/// A time tag in OSC message consists of two 32-bit integers where the first one denotes the number of seconds since 1900-01-01 and the second the fractions of a second.
/// For details on its semantics see http://opensoundcontrol.org/node/3/#timetags
///
/// # Examples
///
/// ```
/// #[cfg(feature = "std")]
/// {
///     use rosc::OscTime;
///     use std::{convert::TryFrom, time::UNIX_EPOCH};
///
///     assert_eq!(
///         OscTime::try_from(UNIX_EPOCH).unwrap(),
///         OscTime::from((2_208_988_800, 0))
///     );
/// }
/// ```
///
/// # Conversions between `(u32, u32)`
///
/// Prior to version `0.5.0` of this crate, `OscTime` was defined as a type alias to `(u32, u32)`.
/// If you are upgrading from one of these older versions, you can use [`.into()`](Into::into) to
/// convert between `(u32, u32)` and `OscTime` in either direction.
///
/// # Conversions between [`std::time::SystemTime`]
///
/// The traits in `std::convert` are implemented for converting between
/// [`SystemTime`](std::time::SystemTime) and `OscTime` in both directions. An `OscTime` can be
/// converted into a `SystemTime` using [`From`](std::convert::From)/[`Into`](std::convert::Into).
/// A `SystemTime` can be converted into an `OscTime` using
/// [`TryFrom`](std::convert::TryFrom)/[`TryInto`](std::convert::TryInto). The fallible variants of
/// the conversion traits are used this case because not every `SystemTime` can be represented as
/// an `OscTime`.
///
/// **These conversions are lossy**, but are tested to have a deviation within
/// 5 nanoseconds when converted back and forth in either direction.
///
/// Although any time since the OSC epoch (`1900-01-01 00:00:00 UTC`) can be represented using the
/// OSC timestamp format, this crate only allows conversions between times greater than or equal to
/// the [`UNIX_EPOCH`](std::time::UNIX_EPOCH). This allows the math used in the conversions to work
/// on 32-bit systems which cannot represent times that far back.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OscTime {
    pub seconds: u32,
    pub fractional: u32,
}

#[cfg(feature = "std")]
impl OscTime {
    const UNIX_OFFSET: u64 = 2_208_988_800; // From RFC 5905
    const TWO_POW_32: f64 = (u32::MAX as f64) + 1.0; // Number of bits in a `u32`
    const ONE_OVER_TWO_POW_32: f64 = 1.0 / OscTime::TWO_POW_32;
    const NANOS_PER_SECOND: f64 = 1.0e9;
    const SECONDS_PER_NANO: f64 = 1.0 / OscTime::NANOS_PER_SECOND;
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscTime {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> core::result::Result<OscTime, OscTimeError> {
        let duration_since_epoch = time
            .duration_since(UNIX_EPOCH)
            .map_err(|_| OscTimeError(OscTimeErrorKind::BeforeEpoch))?
            + Duration::new(OscTime::UNIX_OFFSET, 0);
        let seconds = u32::try_from(duration_since_epoch.as_secs())
            .map_err(|_| OscTimeError(OscTimeErrorKind::Overflow))?;
        let nanos = duration_since_epoch.subsec_nanos() as f64;
        let fractional = (nanos * OscTime::SECONDS_PER_NANO * OscTime::TWO_POW_32).round() as u32;
        Ok(OscTime {
            seconds,
            fractional,
        })
    }
}

#[cfg(feature = "std")]
impl From<OscTime> for SystemTime {
    fn from(time: OscTime) -> SystemTime {
        let nanos =
            (time.fractional as f64) * OscTime::ONE_OVER_TWO_POW_32 * OscTime::NANOS_PER_SECOND;
        let duration_since_osc_epoch = Duration::new(time.seconds as u64, nanos.round() as u32);
        let duration_since_unix_epoch =
            duration_since_osc_epoch - Duration::new(OscTime::UNIX_OFFSET, 0);
        UNIX_EPOCH + duration_since_unix_epoch
    }
}

impl From<(u32, u32)> for OscTime {
    fn from(time: (u32, u32)) -> OscTime {
        let (seconds, fractional) = time;
        OscTime {
            seconds,
            fractional,
        }
    }
}

impl From<OscTime> for (u32, u32) {
    fn from(time: OscTime) -> (u32, u32) {
        (time.seconds, time.fractional)
    }
}

#[cfg(feature = "std")]
/// An error returned by conversions involving [`OscTime`].
#[derive(Debug)]
pub struct OscTimeError(OscTimeErrorKind);

#[cfg(feature = "std")]
#[derive(Debug)]
enum OscTimeErrorKind {
    BeforeEpoch,
    Overflow,
}

#[cfg(feature = "std")]
impl Display for OscTimeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            OscTimeErrorKind::BeforeEpoch => {
                write!(f, "time is before the unix epoch and cannot be stored")
            }
            OscTimeErrorKind::Overflow => {
                write!(f, "time overflows what OSC time can store")
            }
        }
    }
}

// impl error::Error for OscTimeError {}

/// see OSC Type Tag String: [OSC Spec. 1.0](http://opensoundcontrol.org/spec-1_0)
/// padding: zero bytes (n*4)
#[derive(Clone, Debug, PartialEq)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(OscTime),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Array(OscArray),
    Nil,
    Inf,
}
macro_rules! value_impl {
    ($(($name:ident, $variant:ident, $ty:ty)),*) => {
        $(
        impl OscType {
            #[allow(dead_code)]
            pub fn $name(self) -> Option<$ty> {
                match self {
                    OscType::$variant(v) => Some(v),
                    _ => None
                }
            }
        }
        impl From<$ty> for OscType {
            fn from(v: $ty) -> Self {
                OscType::$variant(v)
            }
        }
        )*
    }
}
value_impl! {
    (int, Int, i32),
    (float, Float, f32),
    (string, String, String),
    (blob, Blob, Vec<u8>),
    (array, Array, OscArray),
    (long, Long, i64),
    (double, Double, f64),
    (char, Char, char),
    (color, Color, OscColor),
    (midi, Midi, OscMidiMessage),
    (bool, Bool, bool)
}
impl From<(u32, u32)> for OscType {
    fn from(time: (u32, u32)) -> Self {
        OscType::Time(time.into())
    }
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscType {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> std::result::Result<OscType, OscTimeError> {
        time.try_into().map(OscType::Time)
    }
}

impl OscType {
    pub fn time(self) -> Option<OscTime> {
        match self {
            OscType::Time(time) => Some(time),
            _ => None,
        }
    }
}
impl<'a> From<&'a str> for OscType {
    fn from(string: &'a str) -> Self {
        OscType::String(string.to_string())
    }
}
/// Represents the parts of a Midi message. Mainly used for
/// tunneling midi over a network using the OSC protocol.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

/// An OSC message consists of an address and
/// zero or more arguments. The address should
/// specify an element of your Instrument (or whatever
/// you want to control with OSC) and the arguments
/// are used to set properties of the element to the
/// respective values.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMessage {
    pub addr: String,
    pub args: Vec<OscType>,
}

/// An OSC bundle contains zero or more OSC packets
/// and a time tag. The contained packets *should* be
/// applied at the given time tag.
#[derive(Clone, Debug, PartialEq)]
pub struct OscBundle {
    pub timetag: OscTime,
    pub content: Vec<OscPacket>,
}

/// An RGBA color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

/// An OscArray color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscArray {
    pub content: Vec<OscType>,
}

impl<T: Into<OscType>> FromIterator<T> for OscArray {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> OscArray {
        OscArray {
            content: iter.into_iter().map(T::into).collect(),
        }
    }
}

pub type Result<T> = result::Result<T, errors::OscError>;

impl From<String> for OscMessage {
    fn from(s: String) -> OscMessage {
        OscMessage {
            addr: s,
            args: vec![],
        }
    }
}
impl<'a> From<&'a str> for OscMessage {
    fn from(s: &str) -> OscMessage {
        OscMessage {
            addr: s.to_string(),
            args: vec![],
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "std")]
    use super::*;
    #[cfg(feature = "std")]
    use std::time::UNIX_EPOCH;

    #[cfg(feature = "std")]
    #[cfg(target_os = "windows")]
    // On Windows, the resolution of SystemTime is 100ns, as opposed to 1ns on UNIX
    // (https://doc.rust-lang.org/std/time/struct.SystemTime.html#platform-specific-behavior).
    //
    // As a result, any conversion of OscTime to SystemTime results in the latter being quantized
    // to the nearest 100ns (rounded down).
    // This also means both types of round-trips are lossy.
    const TOLERANCE_NANOS: u64 = 100;

    #[cfg(feature = "std")]
    #[cfg(not(target_os = "windows"))]
    const TOLERANCE_NANOS: u64 = 5;

    #[cfg(feature = "std")]
    #[test]
    fn system_times_can_be_converted_to_and_from_osc() {
        let times = vec![UNIX_EPOCH, SystemTime::now()];
        for time in times {
            for i in 0..1000 {
                let time = time + Duration::from_nanos(1) * i;
                assert_eq_system_times(time, SystemTime::from(OscTime::try_from(time).unwrap()));
            }
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_times_can_be_converted_to_and_from_system_times() {
        let mut times = vec![];
        // Sweep across a few numbers to check for tolerance
        for seconds in vec![
            // We don't start at zero because times before the UNIX_EPOCH cannot be converted to
            // OscTime.
            OscTime::UNIX_OFFSET as u32,
            OscTime::UNIX_OFFSET as u32 + 1,
            OscTime::UNIX_OFFSET as u32 + 2,
            OscTime::UNIX_OFFSET as u32 + 3,
            u32::MAX - 1,
            u32::MAX,
        ] {
            let fractional_max = 100;
            for fractional in 0..fractional_max {
                times.push((seconds, fractional));
                times.push((seconds, fractional_max - fractional));
            }
        }

        for osc_time in times.into_iter().map(OscTime::from) {
            assert_eq_osc_times(
                osc_time,
                OscTime::try_from(SystemTime::from(osc_time)).unwrap(),
            );
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_time_cannot_represent_times_before_1970_01_01() {
        assert!(OscTime::try_from(UNIX_EPOCH - Duration::from_secs(1)).is_err())
    }

    #[cfg(feature = "std")]
    fn assert_eq_system_times(a: SystemTime, b: SystemTime) {
        let difference = if a < b {
            b.duration_since(a).unwrap()
        } else {
            a.duration_since(b).unwrap()
        };

        let tolerance = Duration::from_nanos(TOLERANCE_NANOS);

        if difference > tolerance {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {:?}",
                a, b, tolerance,
            );
        }
    }

    #[cfg(feature = "std")]
    fn assert_eq_osc_times(a: OscTime, b: OscTime) {
        // I did not want to implement subtraction with carrying in order to implement this in the
        // same way as the alternative for system times. Intsead we are compare each part of the
        // OSC times separately.
        let tolerance_fractional_seconds = ((TOLERANCE_NANOS as f64 * OscTime::TWO_POW_32)
            / OscTime::NANOS_PER_SECOND)
            .round() as i64;
        assert_eq!(
            a.seconds, b.seconds,
            "the seconds components of {:?} and {:?} are different",
            a, b
        );
        if (a.fractional as i64 - b.fractional as i64).abs() > tolerance_fractional_seconds {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {} fractional seconds",
                a, b, tolerance_fractional_seconds,
            );
        }
    }
}
<|endoftext|>


<commit_before>//! Type conversions for binding parameters and getting query results.

use super::{PreparedStatement, ResultRow};
use super::{SqliteResult, SQLITE_MISMATCH};
use super::{SQLITE_NULL};
use time;

pub trait ToSql {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()>;
}

/// A trait for result values from a query.
///
/// cf [sqlite3 result values][column].
///
/// *inspired by sfackler's FromSql (and some haskell bindings?)*
///
/// [column]: http://www.sqlite.org/c3ref/column_blob.html
///
///   - TODO: consider a `types` submodule
///   - TODO: many more implementors, including Option<T>
pub trait FromSql {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<Self>;
}

impl ToSql for i32 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_int(ix, *self)
    }
}

impl FromSql for i32 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<i32> { Ok(row.column_int(col)) }
}

impl ToSql for i64 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_int64(ix, *self)
    }
}

impl FromSql for i64 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<i64> { Ok(row.column_int64(col)) }
}

impl ToSql for f64 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_double(ix, *self)
    }
}

impl FromSql for f64 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<f64> { Ok(row.column_double(col)) }
}

impl<T: ToSql + Clone> ToSql for Option<T> {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        match (*self).clone() {
            Some(x) => x.to_sql(s, ix),
            None => s.bind_null(ix)
        }
    }
}

impl<T: FromSql + Clone> FromSql for Option<T> {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<Option<T>> {
        match row.column_type(col) {
            SQLITE_NULL => Ok(None),
            _ => FromSql::from_sql(row, col).map(|x| Some(x))
        }
    }
}

impl ToSql for String {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_text(ix, (*self).as_slice())
    }
}

impl FromSql for String {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<String> {
        Ok(row.column_text(col).unwrap_or("".to_string()))
    }
}

/// Format of sqlite date strings
///
/// From [Date And Time Functions][lang_datefunc]:
/// > The datetime() function returns "YYYY-MM-DD HH:MM:SS"
/// [lang_datefunc]: http://www.sqlite.org/lang_datefunc.html
pub static time_fmt: &'static str = "%F %T";

impl FromSql for time::Tm {
    /// TODO: propagate error message
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<time::Tm> {
        match row.column_text(col) {
            None => Err(SQLITE_MISMATCH),
            Some(txt) => match time::strptime(txt.as_slice(), time_fmt) {
                Ok(tm) => Ok(tm),
                Err(msg) => Err(SQLITE_MISMATCH)
            }
        }
    }
}

impl ToSql for time::Timespec {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_text(ix, time::at_utc(*self).strftime(time_fmt).as_slice())
    }
}

impl FromSql for time::Timespec {
    /// TODO: propagate error message
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<time::Timespec> {
        let tmo: SqliteResult<time::Tm> = FromSql::from_sql(row, col);
        tmo.map(|tm| tm.to_timespec())
    }
}

#[cfg(test)]
mod tests {
    use time::Tm;
    use super::super::{DatabaseConnection, SqliteResult};

    #[test]
    fn get_tm() {
        fn go() -> SqliteResult<()> {
            let mut conn = try!(DatabaseConnection::new());
            let mut stmt = try!(
                conn.prepare("select datetime('2001-01-01', 'weekday 3', '3 hours')"));
            let mut results = stmt.execute();
            match results.step() {
                Some(Ok(ref mut row)) => {
                    assert_eq!(
                        row.get::<uint, Tm>(0u),
                        Tm { tm_sec: 0,
                             tm_min: 0,
                             tm_hour: 3,
                             tm_mday: 3,
                             tm_mon: 0,
                             tm_year: 101,
                             tm_wday: 0,
                             tm_yday: 0,
                             tm_isdst: 0,
                             tm_gmtoff: 0,
                             tm_nsec: 0
                        });
                    Ok(())
                },
                None => fail!("no row"),
                Some(Err(oops)) =>  fail!("error: {}", oops)
            }
        }
        go().unwrap();
    }
}

// Local Variables:
// flycheck-rust-crate-root: "lib.rs"
// End:
<commit_msg>go ahead and suppress warning re error message for now<commit_after>//! Type conversions for binding parameters and getting query results.

use super::{PreparedStatement, ResultRow};
use super::{SqliteResult, SQLITE_MISMATCH};
use super::{SQLITE_NULL};
use time;

pub trait ToSql {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()>;
}

/// A trait for result values from a query.
///
/// cf [sqlite3 result values][column].
///
/// *inspired by sfackler's FromSql (and some haskell bindings?)*
///
/// [column]: http://www.sqlite.org/c3ref/column_blob.html
///
///   - TODO: consider a `types` submodule
///   - TODO: many more implementors, including Option<T>
pub trait FromSql {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<Self>;
}

impl ToSql for i32 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_int(ix, *self)
    }
}

impl FromSql for i32 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<i32> { Ok(row.column_int(col)) }
}

impl ToSql for i64 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_int64(ix, *self)
    }
}

impl FromSql for i64 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<i64> { Ok(row.column_int64(col)) }
}

impl ToSql for f64 {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_double(ix, *self)
    }
}

impl FromSql for f64 {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<f64> { Ok(row.column_double(col)) }
}

impl<T: ToSql + Clone> ToSql for Option<T> {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        match (*self).clone() {
            Some(x) => x.to_sql(s, ix),
            None => s.bind_null(ix)
        }
    }
}

impl<T: FromSql + Clone> FromSql for Option<T> {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<Option<T>> {
        match row.column_type(col) {
            SQLITE_NULL => Ok(None),
            _ => FromSql::from_sql(row, col).map(|x| Some(x))
        }
    }
}

impl ToSql for String {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_text(ix, (*self).as_slice())
    }
}

impl FromSql for String {
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<String> {
        Ok(row.column_text(col).unwrap_or("".to_string()))
    }
}

/// Format of sqlite date strings
///
/// From [Date And Time Functions][lang_datefunc]:
/// > The datetime() function returns "YYYY-MM-DD HH:MM:SS"
/// [lang_datefunc]: http://www.sqlite.org/lang_datefunc.html
pub static time_fmt: &'static str = "%F %T";

impl FromSql for time::Tm {
    /// TODO: propagate error message
    #[allow(unused_variable)]
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<time::Tm> {
        match row.column_text(col) {
            None => Err(SQLITE_MISMATCH),
            Some(txt) => match time::strptime(txt.as_slice(), time_fmt) {
                Ok(tm) => Ok(tm),
                Err(msg) => Err(SQLITE_MISMATCH)
            }
        }
    }
}

impl ToSql for time::Timespec {
    fn to_sql(&self, s: &mut PreparedStatement, ix: uint) -> SqliteResult<()> {
        s.bind_text(ix, time::at_utc(*self).strftime(time_fmt).as_slice())
    }
}

impl FromSql for time::Timespec {
    /// TODO: propagate error message
    fn from_sql(row: &mut ResultRow, col: uint) -> SqliteResult<time::Timespec> {
        let tmo: SqliteResult<time::Tm> = FromSql::from_sql(row, col);
        tmo.map(|tm| tm.to_timespec())
    }
}

#[cfg(test)]
mod tests {
    use time::Tm;
    use super::super::{DatabaseConnection, SqliteResult};

    #[test]
    fn get_tm() {
        fn go() -> SqliteResult<()> {
            let mut conn = try!(DatabaseConnection::new());
            let mut stmt = try!(
                conn.prepare("select datetime('2001-01-01', 'weekday 3', '3 hours')"));
            let mut results = stmt.execute();
            match results.step() {
                Some(Ok(ref mut row)) => {
                    assert_eq!(
                        row.get::<uint, Tm>(0u),
                        Tm { tm_sec: 0,
                             tm_min: 0,
                             tm_hour: 3,
                             tm_mday: 3,
                             tm_mon: 0,
                             tm_year: 101,
                             tm_wday: 0,
                             tm_yday: 0,
                             tm_isdst: 0,
                             tm_gmtoff: 0,
                             tm_nsec: 0
                        });
                    Ok(())
                },
                None => fail!("no row"),
                Some(Err(oops)) =>  fail!("error: {}", oops)
            }
        }
        go().unwrap();
    }
}

// Local Variables:
// flycheck-rust-crate-root: "lib.rs"
// End:
<|endoftext|>