<commit_before>//! Interfaces for accessing instance data from hostcalls.
//!
//! This module contains both a Rust-friendly API ([`Vmctx`](struct.Vmctx.html)) as well as C-style
//! exports for compatibility with hostcalls written against `lucet-runtime-c`.

use crate::alloc::instance_heap_offset;
use crate::context::Context;
use crate::error::Error;
use crate::instance::{
    Instance, InstanceHandle, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE,
    HOST_CTX,
};
use crate::WASM_PAGE_SIZE;
use libc::c_void;
use std::any::Any;
use std::sync::Once;

/// Marker type for the `vmctx` pointer argument.
///
/// This type should only be used with [`Vmctx::from_raw()`](struct.Vmctx.html#method.from_raw).
#[repr(C)]
pub struct lucet_vmctx {
    _unused: [u8; 0],
}

/// An opaque handle to a running instance's context.
#[derive(Debug)]
pub struct Vmctx {
    vmctx: *mut lucet_vmctx,
}

impl Vmctx {
    /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest
    /// function.
    pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx {
        let res = Vmctx { vmctx };
        // we don't actually need the instance for this call, but asking for it here causes an
        // earlier failure if the pointer isn't valid
        assert!(res.instance().valid_magic());
        res
    }

    /// Return the underlying `vmctx` pointer.
    pub fn as_raw(&self) -> *mut lucet_vmctx {
        self.vmctx
    }

    /// Get a reference to the `Instance` for this guest.
    fn instance(&self) -> &Instance {
        unsafe { Instance::from_vmctx(self.vmctx) }
    }

    /// Get a mutable reference to the `Instance` for this guest.  SAFETY NOTE: With this method,
    /// you could hold on to multiple mutable references to the same Instance. Only hold on to one!
    /// This method does not take `&mut self` because otherwise you could not use orthogonal mut
    /// refs that come from Vmctx, like the heap or termination.
    fn instance_mut(&self) -> &mut Instance {
        unsafe { Instance::from_vmctx(self.vmctx) }
    }

    /// Return the WebAssembly heap as a slice of bytes.
    pub fn heap(&self) -> &[u8] {
        self.instance().heap()
    }

    /// Return the WebAssembly heap as a mutable slice of bytes.
    pub fn heap_mut(&mut self) -> &mut [u8] {
        self.instance_mut().heap_mut()
    }

    /// Check whether a given range in the host address space overlaps with the memory that backs
    /// the instance heap.
    pub fn check_heap<T>(&self, ptr: *const T, len: usize) -> bool {
        self.instance().check_heap(ptr, len)
    }

    /// Check whether a context value of a particular type exists.
    pub fn contains_embed_ctx<T: Any>(&self) -> bool {
        self.instance().contains_embed_ctx::<T>()
    }

    /// Get a reference to a context value of a particular type. If it does not exist,
    /// the context will terminate.
    pub fn get_embed_ctx<T: Any>(&self) -> &T {
        self.instance_mut().get_embed_ctx_or_term()
    }

    /// Get a mutable reference to a context value of a particular type> If it does not exist,
    /// the context will terminate.
    pub fn get_embed_ctx_mut<T: Any>(&mut self) -> &mut T {
        self.instance_mut().get_embed_ctx_mut_or_term()
    }

    /// Terminate this guest and return to the host context.
    ///
    /// This will return an `Error::RuntimeTerminated` value to the caller of `Instance::run()`.
    pub fn terminate<I: Any>(&mut self, info: I) -> ! {
        let details = TerminationDetails::provide(info);
        unsafe { self.instance_mut().terminate(details) }
    }

    /// Grow the guest memory by the given number of WebAssembly pages.
    ///
    /// On success, returns the number of pages that existed before the call.
    pub fn grow_memory(&mut self, additional_pages: u32) -> Result<u32, Error> {
        self.instance_mut().grow_memory(additional_pages)
    }

    /// Return the WebAssembly globals as a slice of `i64`s.
    pub fn globals(&self) -> &[i64] {
        self.instance().globals()
    }

    /// Return the WebAssembly globals as a mutable slice of `i64`s.
    pub fn globals_mut(&mut self) -> &mut [i64] {
        self.instance_mut().globals_mut()
    }

    /// Get a function pointer by WebAssembly table and function index.
    ///
    /// This is useful when a hostcall takes a function pointer as its argument, as WebAssembly uses
    /// table indices as its runtime representation of function pointers.
    ///
    /// We do not currently reflect function type information into the Rust type system, so callers
    /// of the returned function must take care to cast it to the correct type before calling. The
    /// correct type will include the `vmctx` argument, which the caller is responsible for passing
    /// from its own context.
    ///
    /// ```no_run
    /// use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx};
    /// #[no_mangle]
    /// extern "C" fn hostcall_call_binop(
    ///     vmctx: *mut lucet_vmctx,
    ///     binop_table_idx: u32,
    ///     binop_func_idx: u32,
    ///     operand1: u32,
    ///     operand2: u32,
    /// ) -> u32 {
    ///     let mut ctx = unsafe { Vmctx::from_raw(vmctx) };
    ///     if let Ok(binop) = ctx.get_func_from_idx(binop_table_idx, binop_func_idx) {
    ///         let typed_binop = binop as *const extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32;
    ///         unsafe { (*typed_binop)(vmctx, operand1, operand2) }
    ///     } else {
    ///         ctx.terminate("invalid function index")
    ///     }
    /// }
    pub fn get_func_from_idx(
        &self,
        table_idx: u32,
        func_idx: u32,
    ) -> Result<*const extern "C" fn(), Error> {
        self.instance()
            .module()
            .get_func_from_idx(table_idx, func_idx)
    }
}

/// Terminating an instance requires mutating the state field, and then jumping back to the
/// host context. The mutable borrow may conflict with a mutable borrow of the embed_ctx if
/// this is performed via a method call. We use a macro so we can convince the borrow checker that
/// this is safe at each use site.
macro_rules! inst_terminate {
    ($self:ident, $details:expr) => {{
        $self.state = State::Terminated { details: $details };
        #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused
        HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) })
    }};
}

impl Instance {
    /// Get an Instance from the `vmctx` pointer.
    ///
    /// Only safe to call from within the guest context.
    unsafe fn from_vmctx<'a>(vmctx: *mut lucet_vmctx) -> &'a mut Instance {
        assert!(!vmctx.is_null(), "vmctx is not null");

        let inst_ptr = (vmctx as usize - instance_heap_offset()) as *mut Instance;

        // We shouldn't actually need to access the thread local, only the exception handler should
        // need to. But, as long as the thread local exists, we should make sure that the guest
        // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest
        // cant pull any shenanigans but there have been bugs before.)
        CURRENT_INSTANCE.with(|current_instance| {
            if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) {
                assert_eq!(
                    inst_ptr, current_inst_ptr,
                    "vmctx corresponds to current instance"
                );
            } else {
                panic!(
                    "current instance is not set; thread local storage failure can indicate \
                     dynamic linking issues"
                );
            }
        });

        let inst = inst_ptr.as_mut().unwrap();
        assert!(inst.valid_magic());
        inst
    }

    /// Helper function specific to Vmctx::get_embed_ctx. From the vmctx interface,
    /// there is no way to recover if the expected embedder ctx is not set, so we terminate
    /// the instance.
    fn get_embed_ctx_or_term<T: Any>(&mut self) -> &T {
        match self.embed_ctx.get::<T>() {
            Some(t) => t,
            None => inst_terminate!(self, TerminationDetails::GetEmbedCtx),
        }
    }

    /// Helper function specific to Vmctx::get_embed_ctx_mut. See above.
    fn get_embed_ctx_mut_or_term<T: Any>(&mut self) -> &mut T {
        match self.embed_ctx.get_mut::<T>() {
            Some(t) => t,
            None => inst_terminate!(self, TerminationDetails::GetEmbedCtx),
        }
    }

    /// Terminate the guest and swap back to the host context.
    ///
    /// Only safe to call from within the guest context.
    unsafe fn terminate(&mut self, details: TerminationDetails) -> ! {
        inst_terminate!(self, details)
    }
}

/// Unsafely get a `Vmctx` from an `InstanceHandle`, and fake a current instance TLS variable.
///
/// This is provided for compatibility with the Terrarium memory management test suite, but should
/// absolutely not be used in newer code.
#[deprecated]
pub unsafe fn vmctx_from_mock_instance(inst: &InstanceHandle) -> Vmctx {
    CURRENT_INSTANCE.with(|current_instance| {
        let mut current_instance = current_instance.borrow_mut();
        *current_instance = Some(std::ptr::NonNull::new_unchecked(
            inst.alloc().slot().start as *mut Instance,
        ));
    });
    Vmctx::from_raw(inst.alloc().slot().heap as *mut lucet_vmctx)
}

static VMCTX_CAPI_INIT: Once = Once::new();

/// Should never actually be called, but should be reachable via a trait method to prevent DCE.
pub fn vmctx_capi_init() {
    use std::ptr::read_volatile;
    VMCTX_CAPI_INIT.call_once(|| unsafe {
        read_volatile(lucet_vmctx_get_heap as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_globals as *const extern "C" fn());
        read_volatile(lucet_vmctx_current_memory as *const extern "C" fn());
        read_volatile(lucet_vmctx_grow_memory as *const extern "C" fn());
        read_volatile(lucet_vmctx_check_heap as *const extern "C" fn());
        read_volatile(lucet_vmctx_terminate as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_delegate as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_func_from_idx as *const extern "C" fn());
        // need at least one of these to get the symbols exported
        read_volatile(crate::c_api::lucet_dl_module_load as *const c_void);
    });
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_heap(vmctx: *mut lucet_vmctx) -> *mut u8 {
    Vmctx::from_raw(vmctx).instance().alloc().slot().heap as *mut u8
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut i64 {
    Vmctx::from_raw(vmctx).instance().alloc().slot().globals as *mut i64
}

/// Get the number of WebAssembly pages currently in the heap.
#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_current_memory(vmctx: *mut lucet_vmctx) -> libc::uint32_t {
    Vmctx::from_raw(vmctx).instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE
}

#[no_mangle]
/// Grows the guest heap by the given number of WebAssembly pages.
///
/// On success, returns the number of pages that existed before the call. On failure, returns `-1`.
pub unsafe extern "C" fn lucet_vmctx_grow_memory(
    vmctx: *mut lucet_vmctx,
    additional_pages: libc::uint32_t,
) -> libc::int32_t {
    let inst = Instance::from_vmctx(vmctx);
    if let Ok(old_pages) = inst.grow_memory(additional_pages) {
        old_pages as libc::int32_t
    } else {
        -1
    }
}

#[no_mangle]
/// Check if a memory region is inside the instance heap.
pub unsafe extern "C" fn lucet_vmctx_check_heap(
    vmctx: *mut lucet_vmctx,
    ptr: *mut c_void,
    len: libc::size_t,
) -> bool {
    let inst = Instance::from_vmctx(vmctx);
    inst.check_heap(ptr, len)
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx(
    vmctx: *mut lucet_vmctx,
    table_idx: u32,
    func_idx: u32,
) -> *const c_void {
    let inst = Instance::from_vmctx(vmctx);
    inst.module()
        .get_func_from_idx(table_idx, func_idx)
        // the Rust API actually returns a pointer to a function pointer, so we want to dereference
        // one layer of that to make it nicer in C
        .map(|fptr| *(fptr as *const *const c_void))
        .unwrap_or(std::ptr::null())
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_terminate(vmctx: *mut lucet_vmctx, info: *mut c_void) {
    Vmctx::from_raw(vmctx).terminate(info);
}

#[no_mangle]
/// Get the delegate object for the current instance.
///
/// TODO: rename
pub unsafe extern "C" fn lucet_vmctx_get_delegate(vmctx: *mut lucet_vmctx) -> *mut c_void {
    let inst = Instance::from_vmctx(vmctx);
    inst.embed_ctx
        .get::<*mut c_void>()
        .map(|p| *p)
        .unwrap_or(std::ptr::null_mut())
}
<commit_msg>lucet-runtime: vmctx internal unsafe methods marked as such<commit_after>//! Interfaces for accessing instance data from hostcalls.
//!
//! This module contains both a Rust-friendly API ([`Vmctx`](struct.Vmctx.html)) as well as C-style
//! exports for compatibility with hostcalls written against `lucet-runtime-c`.

use crate::alloc::instance_heap_offset;
use crate::context::Context;
use crate::error::Error;
use crate::instance::{
    Instance, InstanceHandle, InstanceInternal, State, TerminationDetails, CURRENT_INSTANCE,
    HOST_CTX,
};
use crate::WASM_PAGE_SIZE;
use libc::c_void;
use std::any::Any;
use std::sync::Once;

/// Marker type for the `vmctx` pointer argument.
///
/// This type should only be used with [`Vmctx::from_raw()`](struct.Vmctx.html#method.from_raw).
#[repr(C)]
pub struct lucet_vmctx {
    _unused: [u8; 0],
}

/// An opaque handle to a running instance's context.
#[derive(Debug)]
pub struct Vmctx {
    vmctx: *mut lucet_vmctx,
}

impl Vmctx {
    /// Create a `Vmctx` from the compiler-inserted `vmctx` argument in a guest
    /// function.
    pub unsafe fn from_raw(vmctx: *mut lucet_vmctx) -> Vmctx {
        let res = Vmctx { vmctx };
        // we don't actually need the instance for this call, but asking for it here causes an
        // earlier failure if the pointer isn't valid
        assert!(res.instance().valid_magic());
        res
    }

    /// Return the underlying `vmctx` pointer.
    pub fn as_raw(&self) -> *mut lucet_vmctx {
        self.vmctx
    }

    /// Get a reference to the `Instance` for this guest.
    fn instance(&self) -> &Instance {
        unsafe { Instance::from_vmctx(self.vmctx) }
    }

    /// Get a mutable reference to the `Instance` for this guest.  SAFETY NOTE: With this method,
    /// you could hold on to multiple mutable references to the same Instance. Only hold on to one!
    /// This method does not take `&mut self` because otherwise you could not use orthogonal mut
    /// refs that come from Vmctx, like the heap or termination.
    unsafe fn instance_mut(&self) -> &mut Instance {
        Instance::from_vmctx(self.vmctx)
    }

    /// Return the WebAssembly heap as a slice of bytes.
    pub fn heap(&self) -> &[u8] {
        self.instance().heap()
    }

    /// Return the WebAssembly heap as a mutable slice of bytes.
    pub fn heap_mut(&mut self) -> &mut [u8] {
        unsafe { self.instance_mut().heap_mut() }
    }

    /// Check whether a given range in the host address space overlaps with the memory that backs
    /// the instance heap.
    pub fn check_heap<T>(&self, ptr: *const T, len: usize) -> bool {
        self.instance().check_heap(ptr, len)
    }

    /// Check whether a context value of a particular type exists.
    pub fn contains_embed_ctx<T: Any>(&self) -> bool {
        self.instance().contains_embed_ctx::<T>()
    }

    /// Get a reference to a context value of a particular type. If it does not exist,
    /// the context will terminate.
    pub fn get_embed_ctx<T: Any>(&self) -> &T {
        unsafe { self.instance_mut().get_embed_ctx_or_term() }
    }

    /// Get a mutable reference to a context value of a particular type> If it does not exist,
    /// the context will terminate.
    pub fn get_embed_ctx_mut<T: Any>(&mut self) -> &mut T {
        unsafe { self.instance_mut().get_embed_ctx_mut_or_term() }
    }

    /// Terminate this guest and return to the host context.
    ///
    /// This will return an `Error::RuntimeTerminated` value to the caller of `Instance::run()`.
    pub fn terminate<I: Any>(&mut self, info: I) -> ! {
        let details = TerminationDetails::provide(info);
        unsafe { self.instance_mut().terminate(details) }
    }

    /// Grow the guest memory by the given number of WebAssembly pages.
    ///
    /// On success, returns the number of pages that existed before the call.
    pub fn grow_memory(&mut self, additional_pages: u32) -> Result<u32, Error> {
        unsafe { self.instance_mut().grow_memory(additional_pages) }
    }

    /// Return the WebAssembly globals as a slice of `i64`s.
    pub fn globals(&self) -> &[i64] {
        self.instance().globals()
    }

    /// Return the WebAssembly globals as a mutable slice of `i64`s.
    pub fn globals_mut(&mut self) -> &mut [i64] {
        unsafe { self.instance_mut().globals_mut() }
    }

    /// Get a function pointer by WebAssembly table and function index.
    ///
    /// This is useful when a hostcall takes a function pointer as its argument, as WebAssembly uses
    /// table indices as its runtime representation of function pointers.
    ///
    /// We do not currently reflect function type information into the Rust type system, so callers
    /// of the returned function must take care to cast it to the correct type before calling. The
    /// correct type will include the `vmctx` argument, which the caller is responsible for passing
    /// from its own context.
    ///
    /// ```no_run
    /// use lucet_runtime_internals::vmctx::{lucet_vmctx, Vmctx};
    /// #[no_mangle]
    /// extern "C" fn hostcall_call_binop(
    ///     vmctx: *mut lucet_vmctx,
    ///     binop_table_idx: u32,
    ///     binop_func_idx: u32,
    ///     operand1: u32,
    ///     operand2: u32,
    /// ) -> u32 {
    ///     let mut ctx = unsafe { Vmctx::from_raw(vmctx) };
    ///     if let Ok(binop) = ctx.get_func_from_idx(binop_table_idx, binop_func_idx) {
    ///         let typed_binop = binop as *const extern "C" fn(*mut lucet_vmctx, u32, u32) -> u32;
    ///         unsafe { (*typed_binop)(vmctx, operand1, operand2) }
    ///     } else {
    ///         ctx.terminate("invalid function index")
    ///     }
    /// }
    pub fn get_func_from_idx(
        &self,
        table_idx: u32,
        func_idx: u32,
    ) -> Result<*const extern "C" fn(), Error> {
        self.instance()
            .module()
            .get_func_from_idx(table_idx, func_idx)
    }
}

/// Terminating an instance requires mutating the state field, and then jumping back to the
/// host context. The mutable borrow may conflict with a mutable borrow of the embed_ctx if
/// this is performed via a method call. We use a macro so we can convince the borrow checker that
/// this is safe at each use site.
macro_rules! inst_terminate {
    ($self:ident, $details:expr) => {{
        $self.state = State::Terminated { details: $details };
        #[allow(unused_unsafe)] // The following unsafe will be incorrectly warned as unused
        HOST_CTX.with(|host_ctx| unsafe { Context::set(&*host_ctx.get()) })
    }};
}

impl Instance {
    /// Get an Instance from the `vmctx` pointer.
    ///
    /// Only safe to call from within the guest context.
    unsafe fn from_vmctx<'a>(vmctx: *mut lucet_vmctx) -> &'a mut Instance {
        assert!(!vmctx.is_null(), "vmctx is not null");

        let inst_ptr = (vmctx as usize - instance_heap_offset()) as *mut Instance;

        // We shouldn't actually need to access the thread local, only the exception handler should
        // need to. But, as long as the thread local exists, we should make sure that the guest
        // hasn't pulled any shenanigans and passed a bad vmctx. (Codegen should ensure the guest
        // cant pull any shenanigans but there have been bugs before.)
        CURRENT_INSTANCE.with(|current_instance| {
            if let Some(current_inst_ptr) = current_instance.borrow().map(|nn| nn.as_ptr()) {
                assert_eq!(
                    inst_ptr, current_inst_ptr,
                    "vmctx corresponds to current instance"
                );
            } else {
                panic!(
                    "current instance is not set; thread local storage failure can indicate \
                     dynamic linking issues"
                );
            }
        });

        let inst = inst_ptr.as_mut().unwrap();
        assert!(inst.valid_magic());
        inst
    }

    /// Helper function specific to Vmctx::get_embed_ctx. From the vmctx interface,
    /// there is no way to recover if the expected embedder ctx is not set, so we terminate
    /// the instance.
    fn get_embed_ctx_or_term<T: Any>(&mut self) -> &T {
        match self.embed_ctx.get::<T>() {
            Some(t) => t,
            None => inst_terminate!(self, TerminationDetails::GetEmbedCtx),
        }
    }

    /// Helper function specific to Vmctx::get_embed_ctx_mut. See above.
    fn get_embed_ctx_mut_or_term<T: Any>(&mut self) -> &mut T {
        match self.embed_ctx.get_mut::<T>() {
            Some(t) => t,
            None => inst_terminate!(self, TerminationDetails::GetEmbedCtx),
        }
    }

    /// Terminate the guest and swap back to the host context.
    ///
    /// Only safe to call from within the guest context.
    unsafe fn terminate(&mut self, details: TerminationDetails) -> ! {
        inst_terminate!(self, details)
    }
}

/// Unsafely get a `Vmctx` from an `InstanceHandle`, and fake a current instance TLS variable.
///
/// This is provided for compatibility with the Terrarium memory management test suite, but should
/// absolutely not be used in newer code.
#[deprecated]
pub unsafe fn vmctx_from_mock_instance(inst: &InstanceHandle) -> Vmctx {
    CURRENT_INSTANCE.with(|current_instance| {
        let mut current_instance = current_instance.borrow_mut();
        *current_instance = Some(std::ptr::NonNull::new_unchecked(
            inst.alloc().slot().start as *mut Instance,
        ));
    });
    Vmctx::from_raw(inst.alloc().slot().heap as *mut lucet_vmctx)
}

static VMCTX_CAPI_INIT: Once = Once::new();

/// Should never actually be called, but should be reachable via a trait method to prevent DCE.
pub fn vmctx_capi_init() {
    use std::ptr::read_volatile;
    VMCTX_CAPI_INIT.call_once(|| unsafe {
        read_volatile(lucet_vmctx_get_heap as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_globals as *const extern "C" fn());
        read_volatile(lucet_vmctx_current_memory as *const extern "C" fn());
        read_volatile(lucet_vmctx_grow_memory as *const extern "C" fn());
        read_volatile(lucet_vmctx_check_heap as *const extern "C" fn());
        read_volatile(lucet_vmctx_terminate as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_delegate as *const extern "C" fn());
        read_volatile(lucet_vmctx_get_func_from_idx as *const extern "C" fn());
        // need at least one of these to get the symbols exported
        read_volatile(crate::c_api::lucet_dl_module_load as *const c_void);
    });
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_heap(vmctx: *mut lucet_vmctx) -> *mut u8 {
    Vmctx::from_raw(vmctx).instance().alloc().slot().heap as *mut u8
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_globals(vmctx: *mut lucet_vmctx) -> *mut i64 {
    Vmctx::from_raw(vmctx).instance().alloc().slot().globals as *mut i64
}

/// Get the number of WebAssembly pages currently in the heap.
#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_current_memory(vmctx: *mut lucet_vmctx) -> libc::uint32_t {
    Vmctx::from_raw(vmctx).instance().alloc().heap_len() as u32 / WASM_PAGE_SIZE
}

#[no_mangle]
/// Grows the guest heap by the given number of WebAssembly pages.
///
/// On success, returns the number of pages that existed before the call. On failure, returns `-1`.
pub unsafe extern "C" fn lucet_vmctx_grow_memory(
    vmctx: *mut lucet_vmctx,
    additional_pages: libc::uint32_t,
) -> libc::int32_t {
    let inst = Instance::from_vmctx(vmctx);
    if let Ok(old_pages) = inst.grow_memory(additional_pages) {
        old_pages as libc::int32_t
    } else {
        -1
    }
}

#[no_mangle]
/// Check if a memory region is inside the instance heap.
pub unsafe extern "C" fn lucet_vmctx_check_heap(
    vmctx: *mut lucet_vmctx,
    ptr: *mut c_void,
    len: libc::size_t,
) -> bool {
    let inst = Instance::from_vmctx(vmctx);
    inst.check_heap(ptr, len)
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_get_func_from_idx(
    vmctx: *mut lucet_vmctx,
    table_idx: u32,
    func_idx: u32,
) -> *const c_void {
    let inst = Instance::from_vmctx(vmctx);
    inst.module()
        .get_func_from_idx(table_idx, func_idx)
        // the Rust API actually returns a pointer to a function pointer, so we want to dereference
        // one layer of that to make it nicer in C
        .map(|fptr| *(fptr as *const *const c_void))
        .unwrap_or(std::ptr::null())
}

#[no_mangle]
pub unsafe extern "C" fn lucet_vmctx_terminate(vmctx: *mut lucet_vmctx, info: *mut c_void) {
    Vmctx::from_raw(vmctx).terminate(info);
}

#[no_mangle]
/// Get the delegate object for the current instance.
///
/// TODO: rename
pub unsafe extern "C" fn lucet_vmctx_get_delegate(vmctx: *mut lucet_vmctx) -> *mut c_void {
    let inst = Instance::from_vmctx(vmctx);
    inst.embed_ctx
        .get::<*mut c_void>()
        .map(|p| *p)
        .unwrap_or(std::ptr::null_mut())
}
<|endoftext|>


<commit_before>s! {
    pub struct sigaction {
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct stack_t {
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_errno: ::c_int,
        pub si_code: ::c_int,
        pub _pad: [::c_int; 29],
        _align: [usize; 0],
    }

    pub struct glob64_t {
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut ::c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,

        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }
}

pub const RLIMIT_RSS: ::c_int = 5;
pub const RLIMIT_NOFILE: ::c_int = 7;
pub const RLIMIT_AS: ::c_int = 9;
pub const RLIMIT_NPROC: ::c_int = 6;
pub const RLIMIT_MEMLOCK: ::c_int = 8;
pub const RLIM_INFINITY: ::rlim_t = !0;
pub const RLIMIT_RTTIME: ::c_int = 15;
pub const RLIMIT_NLIMITS: ::c_int = 16;

pub const O_APPEND: ::c_int = 1024;
pub const O_CREAT: ::c_int = 64;
pub const O_EXCL: ::c_int = 128;
pub const O_NOCTTY: ::c_int = 256;
pub const O_NONBLOCK: ::c_int = 2048;
pub const O_SYNC: ::c_int = 1052672;
pub const O_RSYNC: ::c_int = 1052672;
pub const O_DSYNC: ::c_int = 4096;

pub const MAP_ANON: ::c_int = 0x0020;
pub const MAP_ANONYMOUS: ::c_int = 0x0020;
pub const MAP_GROWSDOWN: ::c_int = 0x0100;
pub const MAP_DENYWRITE: ::c_int = 0x0800;
pub const MAP_EXECUTABLE: ::c_int = 0x01000;
pub const MAP_LOCKED: ::c_int = 0x02000;
pub const MAP_NORESERVE: ::c_int = 0x04000;
pub const MAP_POPULATE: ::c_int = 0x08000;
pub const MAP_NONBLOCK: ::c_int = 0x010000;
pub const MAP_STACK: ::c_int = 0x020000;

pub const EDEADLK: ::c_int = 35;
pub const ENAMETOOLONG: ::c_int = 36;
pub const ENOLCK: ::c_int = 37;
pub const ENOSYS: ::c_int = 38;
pub const ENOTEMPTY: ::c_int = 39;
pub const ELOOP: ::c_int = 40;
pub const ENOMSG: ::c_int = 42;
pub const EIDRM: ::c_int = 43;
pub const ECHRNG: ::c_int = 44;
pub const EL2NSYNC: ::c_int = 45;
pub const EL3HLT: ::c_int = 46;
pub const EL3RST: ::c_int = 47;
pub const ELNRNG: ::c_int = 48;
pub const EUNATCH: ::c_int = 49;
pub const ENOCSI: ::c_int = 50;
pub const EL2HLT: ::c_int = 51;
pub const EBADE: ::c_int = 52;
pub const EBADR: ::c_int = 53;
pub const EXFULL: ::c_int = 54;
pub const ENOANO: ::c_int = 55;
pub const EBADRQC: ::c_int = 56;
pub const EBADSLT: ::c_int = 57;
pub const EDEADLOCK: ::c_int = EDEADLK;
pub const EMULTIHOP: ::c_int = 72;
pub const EOVERFLOW: ::c_int = 75;
pub const ENOTUNIQ: ::c_int = 76;
pub const EBADFD: ::c_int = 77;
pub const EBADMSG: ::c_int = 74;
pub const EREMCHG: ::c_int = 78;
pub const ELIBACC: ::c_int = 79;
pub const ELIBBAD: ::c_int = 80;
pub const ELIBSCN: ::c_int = 81;
pub const ELIBMAX: ::c_int = 82;
pub const ELIBEXEC: ::c_int = 83;
pub const EILSEQ: ::c_int = 84;
pub const ERESTART: ::c_int = 85;
pub const ESTRPIPE: ::c_int = 86;
pub const EUSERS: ::c_int = 87;
pub const ENOTSOCK: ::c_int = 88;
pub const EDESTADDRREQ: ::c_int = 89;
pub const EMSGSIZE: ::c_int = 90;
pub const EPROTOTYPE: ::c_int = 91;
pub const ENOPROTOOPT: ::c_int = 92;
pub const EPROTONOSUPPORT: ::c_int = 93;
pub const ESOCKTNOSUPPORT: ::c_int = 94;
pub const EOPNOTSUPP: ::c_int = 95;
pub const EPFNOSUPPORT: ::c_int = 96;
pub const EAFNOSUPPORT: ::c_int = 97;
pub const EADDRINUSE: ::c_int = 98;
pub const EADDRNOTAVAIL: ::c_int = 99;
pub const ENETDOWN: ::c_int = 100;
pub const ENETUNREACH: ::c_int = 101;
pub const ENETRESET: ::c_int = 102;
pub const ECONNABORTED: ::c_int = 103;
pub const ECONNRESET: ::c_int = 104;
pub const ENOBUFS: ::c_int = 105;
pub const EISCONN: ::c_int = 106;
pub const ENOTCONN: ::c_int = 107;
pub const ESHUTDOWN: ::c_int = 108;
pub const ETOOMANYREFS: ::c_int = 109;
pub const ETIMEDOUT: ::c_int = 110;
pub const ECONNREFUSED: ::c_int = 111;
pub const EHOSTDOWN: ::c_int = 112;
pub const EHOSTUNREACH: ::c_int = 113;
pub const EALREADY: ::c_int = 114;
pub const EINPROGRESS: ::c_int = 115;
pub const ESTALE: ::c_int = 116;
pub const EUCLEAN: ::c_int = 117;
pub const ENOTNAM: ::c_int = 118;
pub const ENAVAIL: ::c_int = 119;
pub const EISNAM: ::c_int = 120;
pub const EREMOTEIO: ::c_int = 121;
pub const EDQUOT: ::c_int = 122;
pub const ENOMEDIUM: ::c_int = 123;
pub const EMEDIUMTYPE: ::c_int = 124;
pub const ECANCELED: ::c_int = 125;
pub const ENOKEY: ::c_int = 126;
pub const EKEYEXPIRED: ::c_int = 127;
pub const EKEYREVOKED: ::c_int = 128;
pub const EKEYREJECTED: ::c_int = 129;
pub const EOWNERDEAD: ::c_int = 130;
pub const ENOTRECOVERABLE: ::c_int = 131;
pub const EHWPOISON: ::c_int = 133;
pub const ERFKILL: ::c_int = 132;

pub const SOCK_STREAM: ::c_int = 1;
pub const SOCK_DGRAM: ::c_int = 2;

pub const SOL_SOCKET: ::c_int = 1;

pub const SO_REUSEADDR: ::c_int = 2;
pub const SO_TYPE: ::c_int = 3;
pub const SO_ERROR: ::c_int = 4;
pub const SO_DONTROUTE: ::c_int = 5;
pub const SO_BROADCAST: ::c_int = 6;
pub const SO_SNDBUF: ::c_int = 7;
pub const SO_RCVBUF: ::c_int = 8;
pub const SO_KEEPALIVE: ::c_int = 9;
pub const SO_OOBINLINE: ::c_int = 10;
pub const SO_LINGER: ::c_int = 13;
pub const SO_REUSEPORT: ::c_int = 15;
pub const SO_RCVLOWAT: ::c_int = 18;
pub const SO_SNDLOWAT: ::c_int = 19;
pub const SO_RCVTIMEO: ::c_int = 20;
pub const SO_SNDTIMEO: ::c_int = 21;
pub const SO_ACCEPTCONN: ::c_int = 30;

pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SA_ONSTACK: ::c_int = 0x08000000;
pub const SA_SIGINFO: ::c_int = 0x00000004;
pub const SA_NOCLDWAIT: ::c_int = 0x00000002;

pub const SIGCHLD: ::c_int = 17;
pub const SIGBUS: ::c_int = 7;
pub const SIG_SETMASK: ::c_int = 2;

pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01;
pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02;

pub const FIOCLEX: ::c_ulong = 0x5451;
pub const FIONBIO: ::c_ulong = 0x5421;

pub const BUFSIZ: ::c_uint = 8192;
pub const TMP_MAX: ::c_uint = 238328;
pub const FOPEN_MAX: ::c_uint = 16;
pub const POSIX_MADV_DONTNEED: ::c_int = 4;
pub const _SC_2_C_VERSION: ::c_int = 96;
pub const RUSAGE_THREAD: ::c_int = 1;
pub const O_ACCMODE: ::c_int = 3;
pub const RUSAGE_CHILDREN: ::c_int = -1;
pub const ST_RELATIME: ::c_ulong = 4096;
pub const NI_MAXHOST: ::socklen_t = 1025;

cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86",
                 target_arch = "x86_64"))] {
        pub const PTHREAD_STACK_MIN: ::size_t = 16384;
    } else {
        pub const PTHREAD_STACK_MIN: ::size_t = 131072;
    }
}

extern {
    pub fn sysctl(name: *mut ::c_int,
                  namelen: ::c_int,
                  oldp: *mut ::c_void,
                  oldlenp: *mut ::size_t,
                  newp: *mut ::c_void,
                  newlen: ::size_t)
                  -> ::c_int;
    pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int;
    pub fn backtrace(buf: *mut *mut ::c_void,
                     sz: ::c_int) -> ::c_int;
    pub fn glob64(pattern: *const ::c_char,
                  flags: ::c_int,
                  errfunc: ::dox::Option<extern "C" fn(epath: *const ::c_char,
                                                       errno: ::c_int) -> ::c_int>,
                  pglob: *mut glob64_t) -> ::c_int;
    pub fn globfree64(pglob: *mut glob64_t);
    pub fn getnameinfo(sa: *const ::sockaddr,
                       salen: ::socklen_t,
                       host: *mut ::c_char,
                       hostlen: ::socklen_t,
                       serv: *mut ::c_char,
                       sevlen: ::socklen_t,
                       flags: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "arm"))] {
        mod b32;
        pub use self::b32::*;
    } else if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    } else {
        // ...
    }
}

s! {
    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort,
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_atime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused1: ::c_ulong,
        pub shm_dtime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused2: ::c_ulong,
        pub shm_ctime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused3: ::c_ulong,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused4: ::c_ulong,
        __unused5: ::c_ulong
    }
}
<commit_msg>Expose functionality to get peer credentials for a Unix socket on Linux<commit_after>s! {
    pub struct sigaction {
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct stack_t {
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct siginfo_t {
        pub si_signo: ::c_int,
        pub si_errno: ::c_int,
        pub si_code: ::c_int,
        pub _pad: [::c_int; 29],
        _align: [usize; 0],
    }

    pub struct glob64_t {
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut ::c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,

        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct ucred {
        pub pid: ::pid_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
    }
}

pub const RLIMIT_RSS: ::c_int = 5;
pub const RLIMIT_NOFILE: ::c_int = 7;
pub const RLIMIT_AS: ::c_int = 9;
pub const RLIMIT_NPROC: ::c_int = 6;
pub const RLIMIT_MEMLOCK: ::c_int = 8;
pub const RLIM_INFINITY: ::rlim_t = !0;
pub const RLIMIT_RTTIME: ::c_int = 15;
pub const RLIMIT_NLIMITS: ::c_int = 16;

pub const O_APPEND: ::c_int = 1024;
pub const O_CREAT: ::c_int = 64;
pub const O_EXCL: ::c_int = 128;
pub const O_NOCTTY: ::c_int = 256;
pub const O_NONBLOCK: ::c_int = 2048;
pub const O_SYNC: ::c_int = 1052672;
pub const O_RSYNC: ::c_int = 1052672;
pub const O_DSYNC: ::c_int = 4096;

pub const MAP_ANON: ::c_int = 0x0020;
pub const MAP_ANONYMOUS: ::c_int = 0x0020;
pub const MAP_GROWSDOWN: ::c_int = 0x0100;
pub const MAP_DENYWRITE: ::c_int = 0x0800;
pub const MAP_EXECUTABLE: ::c_int = 0x01000;
pub const MAP_LOCKED: ::c_int = 0x02000;
pub const MAP_NORESERVE: ::c_int = 0x04000;
pub const MAP_POPULATE: ::c_int = 0x08000;
pub const MAP_NONBLOCK: ::c_int = 0x010000;
pub const MAP_STACK: ::c_int = 0x020000;

pub const EDEADLK: ::c_int = 35;
pub const ENAMETOOLONG: ::c_int = 36;
pub const ENOLCK: ::c_int = 37;
pub const ENOSYS: ::c_int = 38;
pub const ENOTEMPTY: ::c_int = 39;
pub const ELOOP: ::c_int = 40;
pub const ENOMSG: ::c_int = 42;
pub const EIDRM: ::c_int = 43;
pub const ECHRNG: ::c_int = 44;
pub const EL2NSYNC: ::c_int = 45;
pub const EL3HLT: ::c_int = 46;
pub const EL3RST: ::c_int = 47;
pub const ELNRNG: ::c_int = 48;
pub const EUNATCH: ::c_int = 49;
pub const ENOCSI: ::c_int = 50;
pub const EL2HLT: ::c_int = 51;
pub const EBADE: ::c_int = 52;
pub const EBADR: ::c_int = 53;
pub const EXFULL: ::c_int = 54;
pub const ENOANO: ::c_int = 55;
pub const EBADRQC: ::c_int = 56;
pub const EBADSLT: ::c_int = 57;
pub const EDEADLOCK: ::c_int = EDEADLK;
pub const EMULTIHOP: ::c_int = 72;
pub const EOVERFLOW: ::c_int = 75;
pub const ENOTUNIQ: ::c_int = 76;
pub const EBADFD: ::c_int = 77;
pub const EBADMSG: ::c_int = 74;
pub const EREMCHG: ::c_int = 78;
pub const ELIBACC: ::c_int = 79;
pub const ELIBBAD: ::c_int = 80;
pub const ELIBSCN: ::c_int = 81;
pub const ELIBMAX: ::c_int = 82;
pub const ELIBEXEC: ::c_int = 83;
pub const EILSEQ: ::c_int = 84;
pub const ERESTART: ::c_int = 85;
pub const ESTRPIPE: ::c_int = 86;
pub const EUSERS: ::c_int = 87;
pub const ENOTSOCK: ::c_int = 88;
pub const EDESTADDRREQ: ::c_int = 89;
pub const EMSGSIZE: ::c_int = 90;
pub const EPROTOTYPE: ::c_int = 91;
pub const ENOPROTOOPT: ::c_int = 92;
pub const EPROTONOSUPPORT: ::c_int = 93;
pub const ESOCKTNOSUPPORT: ::c_int = 94;
pub const EOPNOTSUPP: ::c_int = 95;
pub const EPFNOSUPPORT: ::c_int = 96;
pub const EAFNOSUPPORT: ::c_int = 97;
pub const EADDRINUSE: ::c_int = 98;
pub const EADDRNOTAVAIL: ::c_int = 99;
pub const ENETDOWN: ::c_int = 100;
pub const ENETUNREACH: ::c_int = 101;
pub const ENETRESET: ::c_int = 102;
pub const ECONNABORTED: ::c_int = 103;
pub const ECONNRESET: ::c_int = 104;
pub const ENOBUFS: ::c_int = 105;
pub const EISCONN: ::c_int = 106;
pub const ENOTCONN: ::c_int = 107;
pub const ESHUTDOWN: ::c_int = 108;
pub const ETOOMANYREFS: ::c_int = 109;
pub const ETIMEDOUT: ::c_int = 110;
pub const ECONNREFUSED: ::c_int = 111;
pub const EHOSTDOWN: ::c_int = 112;
pub const EHOSTUNREACH: ::c_int = 113;
pub const EALREADY: ::c_int = 114;
pub const EINPROGRESS: ::c_int = 115;
pub const ESTALE: ::c_int = 116;
pub const EUCLEAN: ::c_int = 117;
pub const ENOTNAM: ::c_int = 118;
pub const ENAVAIL: ::c_int = 119;
pub const EISNAM: ::c_int = 120;
pub const EREMOTEIO: ::c_int = 121;
pub const EDQUOT: ::c_int = 122;
pub const ENOMEDIUM: ::c_int = 123;
pub const EMEDIUMTYPE: ::c_int = 124;
pub const ECANCELED: ::c_int = 125;
pub const ENOKEY: ::c_int = 126;
pub const EKEYEXPIRED: ::c_int = 127;
pub const EKEYREVOKED: ::c_int = 128;
pub const EKEYREJECTED: ::c_int = 129;
pub const EOWNERDEAD: ::c_int = 130;
pub const ENOTRECOVERABLE: ::c_int = 131;
pub const EHWPOISON: ::c_int = 133;
pub const ERFKILL: ::c_int = 132;

pub const SOCK_STREAM: ::c_int = 1;
pub const SOCK_DGRAM: ::c_int = 2;

pub const SOL_SOCKET: ::c_int = 1;

pub const SO_REUSEADDR: ::c_int = 2;
pub const SO_TYPE: ::c_int = 3;
pub const SO_ERROR: ::c_int = 4;
pub const SO_DONTROUTE: ::c_int = 5;
pub const SO_BROADCAST: ::c_int = 6;
pub const SO_SNDBUF: ::c_int = 7;
pub const SO_RCVBUF: ::c_int = 8;
pub const SO_KEEPALIVE: ::c_int = 9;
pub const SO_OOBINLINE: ::c_int = 10;
pub const SO_LINGER: ::c_int = 13;
pub const SO_REUSEPORT: ::c_int = 15;
pub const SO_PEERCRED: ::c_int = 17;
pub const SO_RCVLOWAT: ::c_int = 18;
pub const SO_SNDLOWAT: ::c_int = 19;
pub const SO_RCVTIMEO: ::c_int = 20;
pub const SO_SNDTIMEO: ::c_int = 21;
pub const SO_ACCEPTCONN: ::c_int = 30;

pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15;
pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16;
pub const TCP_THIN_DUPACK: ::c_int = 17;
pub const TCP_USER_TIMEOUT: ::c_int = 18;
pub const TCP_REPAIR: ::c_int = 19;
pub const TCP_REPAIR_QUEUE: ::c_int = 20;
pub const TCP_QUEUE_SEQ: ::c_int = 21;
pub const TCP_REPAIR_OPTIONS: ::c_int = 22;
pub const TCP_FASTOPEN: ::c_int = 23;
pub const TCP_TIMESTAMP: ::c_int = 24;

pub const SA_ONSTACK: ::c_int = 0x08000000;
pub const SA_SIGINFO: ::c_int = 0x00000004;
pub const SA_NOCLDWAIT: ::c_int = 0x00000002;

pub const SIGCHLD: ::c_int = 17;
pub const SIGBUS: ::c_int = 7;
pub const SIG_SETMASK: ::c_int = 2;

pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01;
pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02;

pub const FIOCLEX: ::c_ulong = 0x5451;
pub const FIONBIO: ::c_ulong = 0x5421;

pub const BUFSIZ: ::c_uint = 8192;
pub const TMP_MAX: ::c_uint = 238328;
pub const FOPEN_MAX: ::c_uint = 16;
pub const POSIX_MADV_DONTNEED: ::c_int = 4;
pub const _SC_2_C_VERSION: ::c_int = 96;
pub const RUSAGE_THREAD: ::c_int = 1;
pub const O_ACCMODE: ::c_int = 3;
pub const RUSAGE_CHILDREN: ::c_int = -1;
pub const ST_RELATIME: ::c_ulong = 4096;
pub const NI_MAXHOST: ::socklen_t = 1025;

cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86",
                 target_arch = "x86_64"))] {
        pub const PTHREAD_STACK_MIN: ::size_t = 16384;
    } else {
        pub const PTHREAD_STACK_MIN: ::size_t = 131072;
    }
}

extern {
    pub fn sysctl(name: *mut ::c_int,
                  namelen: ::c_int,
                  oldp: *mut ::c_void,
                  oldlenp: *mut ::size_t,
                  newp: *mut ::c_void,
                  newlen: ::size_t)
                  -> ::c_int;
    pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int;
    pub fn backtrace(buf: *mut *mut ::c_void,
                     sz: ::c_int) -> ::c_int;
    pub fn glob64(pattern: *const ::c_char,
                  flags: ::c_int,
                  errfunc: ::dox::Option<extern "C" fn(epath: *const ::c_char,
                                                       errno: ::c_int) -> ::c_int>,
                  pglob: *mut glob64_t) -> ::c_int;
    pub fn globfree64(pglob: *mut glob64_t);
    pub fn getnameinfo(sa: *const ::sockaddr,
                       salen: ::socklen_t,
                       host: *mut ::c_char,
                       hostlen: ::socklen_t,
                       serv: *mut ::c_char,
                       sevlen: ::socklen_t,
                       flags: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "arm"))] {
        mod b32;
        pub use self::b32::*;
    } else if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    } else {
        // ...
    }
}

s! {
    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort,
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_atime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused1: ::c_ulong,
        pub shm_dtime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused2: ::c_ulong,
        pub shm_ctime: ::time_t,
        #[cfg(target_pointer_width = "32")]
        __unused3: ::c_ulong,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused4: ::c_ulong,
        __unused5: ::c_ulong
    }
}
<|endoftext|>


<commit_before>// This is actually a test that runs on the HOST (!). I had to hack things
// around quite a bit to make this work; that's way this ended up in this
// directory :-).

extern crate f3;

use f3::peripheral;

macro_rules! offset {
    ($register:expr, $offset:expr) => {
        if $offset != &$register as *const _ as usize {
            panic!("{}: expected 0x{:x}, got 0x{:x}. Off by {}",
                   stringify!($register), $offset,
                   &$register as *const _ as usize,
                   (&$register as *const _ as isize - $offset).abs())
        }
    }
}

fn main() {
    let dbgmcu = unsafe { &*(0x0 as *const peripheral::dbgmcu::Dbgmcu) };

    offset!(dbgmcu.idcode, 0x0);
    offset!(dbgmcu.cr, 0x4);
    offset!(dbgmcu.apb1fz, 0x8);
    offset!(dbgmcu.apb2fz, 0xc);

    let gpio = unsafe { &*(0x0 as *const peripheral::gpio::Gpio) };

    offset!(gpio.moder, 0x0);
    offset!(gpio.otyper, 0x4);
    offset!(gpio.ospeedr, 0x8);
    offset!(gpio.pupdr, 0xc);
    offset!(gpio.idr, 0x10);
    offset!(gpio.odr, 0x14);
    offset!(gpio.bsrr, 0x18);
    offset!(gpio.lckr, 0x1c);
    offset!(gpio.afrl, 0x20);
    offset!(gpio.afrh, 0x24);
    offset!(gpio.brr, 0x28);

    let i2c = unsafe { &*(0x0 as *const peripheral::i2c::I2c) };

    offset!(i2c.cr1, 0x0);
    offset!(i2c.cr2, 0x4);
    offset!(i2c.oar1, 0x8);
    offset!(i2c.oar2, 0xc);
    offset!(i2c.timingr, 0x10);
    offset!(i2c.timeoutr, 0x14);
    offset!(i2c.isr, 0x18);
    offset!(i2c.icr, 0x1c);
    offset!(i2c.pecr, 0x20);
    offset!(i2c.rxdr, 0x24);
    offset!(i2c.txdr, 0x28);

    let rcc = unsafe { &*(0x0 as *const peripheral::rcc::Rcc) };

    offset!(rcc.cr, 0x0);
    offset!(rcc.cfgr, 0x4);
    offset!(rcc.cir, 0x8);
    offset!(rcc.apb2rstr, 0xc);
    offset!(rcc.apb1rstr, 0x10);
    offset!(rcc.ahbenr, 0x14);
    offset!(rcc.apb2enr, 0x18);
    offset!(rcc.apb1enr, 0x1c);
    offset!(rcc.bdcr, 0x20);
    offset!(rcc.csr, 0x24);
    offset!(rcc.ahbrstr, 0x28);
    offset!(rcc.cfgr2, 0x2c);
    offset!(rcc.cfgr3, 0x30);

    let spi = unsafe { &*(0x0 as *const peripheral::spi::Spi) };

    offset!(spi.cr1, 0x00);
    offset!(spi.cr2, 0x04);
    offset!(spi.sr, 0x08);
    offset!(spi.dr, 0x0C);
    offset!(spi.crcpr, 0x10);
    offset!(spi.rxcrcr, 0x14);
    offset!(spi.txcrcr, 0x18);
    offset!(spi.i2scfgr, 0x1C);
    offset!(spi.i2spr, 0x20);

    let tim = unsafe { &*(0x0 as *const peripheral::tim::Tim) };

    offset!(tim.cr1, 0x0);
    offset!(tim.cr2, 0x4);
    offset!(tim.dier, 0xc);
    offset!(tim.sr, 0x10);
    offset!(tim.egr, 0x14);
    offset!(tim.cnt, 0x24);
    offset!(tim.psc, 0x28);
    offset!(tim.arr, 0x2c);

    let usart = unsafe { &*(0x0 as *const peripheral::usart::Usart) };

    offset!(usart.cr1, 0x0);
    offset!(usart.cr2, 0x4);
    offset!(usart.cr3, 0x8);
    offset!(usart.brr, 0xc);
    offset!(usart.gtpr, 0x10);
    offset!(usart.rtor, 0x14);
    offset!(usart.rqr, 0x18);
    offset!(usart.isr, 0x1c);
    offset!(usart.icr, 0x20);
    offset!(usart.rdr, 0x24);
    offset!(usart.tdr, 0x28);
}
<commit_msg>fix test<commit_after>// This is actually a test that runs on the HOST (!). I had to hack things
// around quite a bit to make this work; that's way this ended up in this
// directory :-).

extern crate f3;

use f3::peripheral;

macro_rules! offset {
    ($register:expr, $offset:expr) => {
        if $offset != &$register as *const _ as usize {
            panic!("{}: expected 0x{:x}, got 0x{:x}. Off by {}",
                   stringify!($register), $offset,
                   &$register as *const _ as usize,
                   (&$register as *const _ as isize - $offset).abs())
        }
    }
}

fn main() {
    let btim = unsafe { &*(0x0 as *const peripheral::tim::BTim) };

    offset!(btim.cr1, 0x0);
    offset!(btim.cr2, 0x4);
    offset!(btim.dier, 0xc);
    offset!(btim.sr, 0x10);
    offset!(btim.egr, 0x14);
    offset!(btim.cnt, 0x24);
    offset!(btim.psc, 0x28);
    offset!(btim.arr, 0x2c);

    let dbgmcu = unsafe { &*(0x0 as *const peripheral::dbgmcu::Dbgmcu) };

    offset!(dbgmcu.idcode, 0x0);
    offset!(dbgmcu.cr, 0x4);
    offset!(dbgmcu.apb1fz, 0x8);
    offset!(dbgmcu.apb2fz, 0xc);

    let gpio = unsafe { &*(0x0 as *const peripheral::gpio::Gpio) };

    offset!(gpio.moder, 0x0);
    offset!(gpio.otyper, 0x4);
    offset!(gpio.ospeedr, 0x8);
    offset!(gpio.pupdr, 0xc);
    offset!(gpio.idr, 0x10);
    offset!(gpio.odr, 0x14);
    offset!(gpio.bsrr, 0x18);
    offset!(gpio.lckr, 0x1c);
    offset!(gpio.afrl, 0x20);
    offset!(gpio.afrh, 0x24);
    offset!(gpio.brr, 0x28);

    let gptim = unsafe { &*(0x0 as *const peripheral::tim::GpTim) };

    offset!(gptim.cr1, 0x0);
    offset!(gptim.cr2, 0x4);
    offset!(gptim.smcr, 0x8);
    offset!(gptim.dier, 0xc);
    offset!(gptim.sr, 0x10);
    offset!(gptim.egr, 0x14);
    offset!(gptim.ccmr1, 0x18);
    offset!(gptim.ccmr2, 0x1c);
    offset!(gptim.ccer, 0x20);
    offset!(gptim.cnt, 0x24);
    offset!(gptim.psc, 0x28);
    offset!(gptim.arr, 0x2c);
    offset!(gptim.ccr1, 0x34);
    offset!(gptim.ccr2, 0x38);
    offset!(gptim.ccr3, 0x3c);
    offset!(gptim.ccr4, 0x40);
    offset!(gptim.dcr, 0x48);
    offset!(gptim.dmar, 0x4c);

    let i2c = unsafe { &*(0x0 as *const peripheral::i2c::I2c) };

    offset!(i2c.cr1, 0x0);
    offset!(i2c.cr2, 0x4);
    offset!(i2c.oar1, 0x8);
    offset!(i2c.oar2, 0xc);
    offset!(i2c.timingr, 0x10);
    offset!(i2c.timeoutr, 0x14);
    offset!(i2c.isr, 0x18);
    offset!(i2c.icr, 0x1c);
    offset!(i2c.pecr, 0x20);
    offset!(i2c.rxdr, 0x24);
    offset!(i2c.txdr, 0x28);

    let rcc = unsafe { &*(0x0 as *const peripheral::rcc::Rcc) };

    offset!(rcc.cr, 0x0);
    offset!(rcc.cfgr, 0x4);
    offset!(rcc.cir, 0x8);
    offset!(rcc.apb2rstr, 0xc);
    offset!(rcc.apb1rstr, 0x10);
    offset!(rcc.ahbenr, 0x14);
    offset!(rcc.apb2enr, 0x18);
    offset!(rcc.apb1enr, 0x1c);
    offset!(rcc.bdcr, 0x20);
    offset!(rcc.csr, 0x24);
    offset!(rcc.ahbrstr, 0x28);
    offset!(rcc.cfgr2, 0x2c);
    offset!(rcc.cfgr3, 0x30);

    let spi = unsafe { &*(0x0 as *const peripheral::spi::Spi) };

    offset!(spi.cr1, 0x00);
    offset!(spi.cr2, 0x04);
    offset!(spi.sr, 0x08);
    offset!(spi.dr, 0x0C);
    offset!(spi.crcpr, 0x10);
    offset!(spi.rxcrcr, 0x14);
    offset!(spi.txcrcr, 0x18);
    offset!(spi.i2scfgr, 0x1C);
    offset!(spi.i2spr, 0x20);

    let usart = unsafe { &*(0x0 as *const peripheral::usart::Usart) };

    offset!(usart.cr1, 0x0);
    offset!(usart.cr2, 0x4);
    offset!(usart.cr3, 0x8);
    offset!(usart.brr, 0xc);
    offset!(usart.gtpr, 0x10);
    offset!(usart.rtor, 0x14);
    offset!(usart.rqr, 0x18);
    offset!(usart.isr, 0x1c);
    offset!(usart.icr, 0x20);
    offset!(usart.rdr, 0x24);
    offset!(usart.tdr, 0x28);
}
<|endoftext|>


<commit_before>/* This thing crashes Enigo.
 * Obviously, this is a bug, and is being worked on.
 * It's here for us to experiment around to see why it crashes and
 * how to fix it. */
// Cheers!
//
extern crate enigo;
use enigo::{Enigo, KeyboardControllable, Key};

fn main() {
    let mut enigo = Enigo::new();

    // enigo.key_sequence("ä#+ -> hello world ... 𝕊");
    enigo.key_sequence("aaa𝕊");
    println!("woot m9");
    enigo.key_click(Key::Return);
    println!("m9 woot");
}
<commit_msg>Deleted crash.rs example (fixed)<commit_after><|endoftext|>


<commit_before>use crate::{pagecache::*, *};

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) iobuf: Arc<IoBuf>,
    pub(super) buf: &'a mut [u8],
    pub(super) flushed: bool,
    pub(super) pointer: DiskPtr,
    pub(super) lsn: Lsn,
    pub(super) is_blob_rewrite: bool,
    pub(super) header_len: usize,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            let _written = self.flush(false).unwrap();
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr)> {
        if self.pointer.is_blob() && !self.is_blob_rewrite {
            // we don't want to remove this blob if something
            // else may still be using it.

            trace!(
                "removing blob for aborted reservation at lsn {}",
                self.pointer
            );

            remove_blob(self.pointer.blob().1, &self.log.config)?;
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Get the log file offset for reading this buffer in the future.
    pub fn lid(&self) -> LogOffset {
        self.pointer.lid()
    }

    /// Get the log sequence number for this update.
    pub const fn lsn(&self) -> Lsn {
        self.lsn
    }

    /// Get the underlying storage location for the written value.
    /// Note that an blob write still has a pointer in the
    /// log at the provided lid location.
    pub const fn pointer(&self) -> DiskPtr {
        self.pointer
    }

    /// Returns the length of the on-log reservation.
    pub const fn reservation_len(&self) -> usize {
        self.buf.len()
    }

    /// Refills the reservation buffer with new data.
    /// Must supply a buffer of an identical length
    /// as the one initially provided. Don't use this
    /// on messages subject to compression etc...
    ///
    /// # Panics
    ///
    /// Will panic if the reservation is not the correct
    /// size to hold a serialized Lsn.
    #[doc(hidden)]
    pub fn mark_writebatch(&mut self, lsn: Lsn) {
        trace!(
            "writing batch required stable lsn {} into \
             BatchManifest at lid {} lsn {}",
            lsn,
            self.pointer.lid(),
            self.lsn
        );

        self.buf[0] = MessageKind::BatchManifest.into();

        let buf = lsn_to_arr(lsn);

        let dst = &mut self.buf[self.header_len..];

        dst.copy_from_slice(&buf);
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            // don't actually zero the message, still check its hash
            // on recovery to find corruption.
            self.buf[0] = MessageKind::Canceled.into();
        }

        // the order of hashing must be the
        // same here as during calls to
        // LogReader::read_message
        let mut hasher = crc32fast::Hasher::new();
        hasher.update(&self.buf[self.header_len..]);
        hasher.update(&self.buf[..self.header_len]);
        let crc32 = hasher.finalize();
        let crc32_arr = u32_to_arr(crc32 ^ 0xFFFF_FFFF);

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.buf.as_mut_ptr(),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(&self.iobuf)?;

        Ok((self.lsn(), self.pointer()))
    }
}
<commit_msg>Update checksumming logic in the reservation<commit_after>use crate::{pagecache::*, *};

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) iobuf: Arc<IoBuf>,
    pub(super) buf: &'a mut [u8],
    pub(super) flushed: bool,
    pub(super) pointer: DiskPtr,
    pub(super) lsn: Lsn,
    pub(super) is_blob_rewrite: bool,
    pub(super) header_len: usize,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            let _written = self.flush(false).unwrap();
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr)> {
        if self.pointer.is_blob() && !self.is_blob_rewrite {
            // we don't want to remove this blob if something
            // else may still be using it.

            trace!(
                "removing blob for aborted reservation at lsn {}",
                self.pointer
            );

            remove_blob(self.pointer.blob().1, &self.log.config)?;
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Get the log file offset for reading this buffer in the future.
    pub fn lid(&self) -> LogOffset {
        self.pointer.lid()
    }

    /// Get the log sequence number for this update.
    pub const fn lsn(&self) -> Lsn {
        self.lsn
    }

    /// Get the underlying storage location for the written value.
    /// Note that an blob write still has a pointer in the
    /// log at the provided lid location.
    pub const fn pointer(&self) -> DiskPtr {
        self.pointer
    }

    /// Returns the length of the on-log reservation.
    pub const fn reservation_len(&self) -> usize {
        self.buf.len()
    }

    /// Refills the reservation buffer with new data.
    /// Must supply a buffer of an identical length
    /// as the one initially provided. Don't use this
    /// on messages subject to compression etc...
    ///
    /// # Panics
    ///
    /// Will panic if the reservation is not the correct
    /// size to hold a serialized Lsn.
    #[doc(hidden)]
    pub fn mark_writebatch(&mut self, lsn: Lsn) {
        trace!(
            "writing batch required stable lsn {} into \
             BatchManifest at lid {} lsn {}",
            lsn,
            self.pointer.lid(),
            self.lsn
        );

        self.buf[0] = MessageKind::BatchManifest.into();

        let buf = lsn_to_arr(lsn);

        let dst = &mut self.buf[self.header_len..];

        dst.copy_from_slice(&buf);
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            // don't actually zero the message, still check its hash
            // on recovery to find corruption.
            self.buf[0] = MessageKind::Canceled.into();
        }

        // the order of hashing must be the
        // same here as during calls to
        // LogReader::read_message
        let mut hasher = crc32fast::Hasher::new();
        hasher.update(&self.buf[self.header_len..]);
        hasher.update(&self.buf[std::mem::size_of::<u32>()..self.header_len]);

        let crc32 = hasher.finalize();
        let crc32_arr = u32_to_arr(crc32 ^ 0xFFFF_FFFF);

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.buf.as_mut_ptr(),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(&self.iobuf)?;

        Ok((self.lsn(), self.pointer()))
    }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

use num_traits::{pow,ToPrimitive};
use num_bigint::{BigUint,ToBigUint};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
    use seed::prelude::*;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
	let two:BigUint = 2.to_biguint().unwrap();

    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
		let download_filename:String = format!("P{}.txt",&perfects[n].n.to_string());
        let download_txt:String = format!("https://static.bigprimes.net/archive/perfect/{}.txt",&perfects[n].n.to_string());

		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
                td![a![attrs!{At::Href => download_txt},"TXT"]],//downloads
				td![perfects_utils::save_as_file(String::from(&download_filename),perfect_value.to_string())],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Removed old TXT download links<commit_after>use seed::prelude::*;
use crate::Msg;

use num_traits::{pow,ToPrimitive};
use num_bigint::{BigUint,ToBigUint};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
    use seed::prelude::*;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
	let two:BigUint = 2.to_biguint().unwrap();

    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
		let download_filename:String = format!("P{}.txt",&perfects[n].n.to_string());
        let download_txt:String = format!("https://static.bigprimes.net/archive/perfect/{}.txt",&perfects[n].n.to_string());

		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
				td![perfects_utils::save_as_file(String::from(&download_filename),perfect_value.to_string())],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

pub mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
    use crate::Msg;

	#[derive(Clone)]
	pub struct Perfect {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: String,
	}

	#[derive(Clone)]
	pub struct PerfectDownload {
		pub n: u64,
		pub p: u64,
	}

	pub fn perfects() -> Vec<Perfect> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: String::from("1979 Nelson&Slowinski") },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: String::from("1979 Noll") },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: String::from("1978 Noll&Nickel") },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: String::from("1971 Tuckerman") },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: String::from("1963 Gillies") },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: String::from("1963 Gillies") },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: String::from("1963 Gillies") },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: String::from("1957 Riesel") },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: String::from("1952 Robinson") },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: String::from("1952 Robinson") },
			Perfect {n: 14, p: 607, digits: 366, discovery: String::from("1952 Robinson") },
			Perfect {n: 13, p: 521, digits: 314, discovery: String::from("1952 Robinson") },
			Perfect {n: 12, p: 127, digits: 77, discovery: String::from("1876 Lucas") },
			Perfect {n: 11, p: 107, digits: 65, discovery: String::from("1914 Powers") },
			Perfect {n: 10, p: 89, digits: 54, discovery: String::from("1911 Powers") },
			Perfect {n: 9, p: 61, digits: 37, discovery: String::from("1883 Pervushin") },
			Perfect {n: 8, p: 31, digits: 19, discovery: String::from("1772 Euler") },
			Perfect {n: 7, p: 19, digits: 12, discovery: String::from("1588 Cataldi") },
			Perfect {n: 6, p: 17, digits: 10, discovery: String::from("1588 Cataldi") },
			Perfect {n: 5, p: 13, digits: 8, discovery: String::from("1456 ?") },
			Perfect {n: 4, p: 7, digits: 4, discovery: String::from("?") },
			Perfect {n: 3, p: 5, digits: 3, discovery: String::from("?") },
			Perfect {n: 2, p: 3, digits: 2, discovery: String::from("?") },
			Perfect {n: 1, p: 2, digits: 1, discovery: String::from("?") },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize, p:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
		let perfectp:u64 = perfect.p;
		let perfect_download = perfects_utils::PerfectDownload {n: perfect.n, p: perfect.p};
		let equation:String = format!("2{} × (2{}-1)",&(perfectp-1).to_string(),&(perfectp).to_string());

		let p:usize = perfectp.to_usize().unwrap();

        html.push(
            tr![
                td![perfect.n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfect.digits.to_string()],//digits in length
                td![perfect.discovery],//discovery
				td![button!["Generate",input_ev("input", move |text| Msg::GenerateDownload(perfect_download))]],

            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Removed unused variable<commit_after>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

pub mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
    use crate::Msg;

	#[derive(Clone)]
	pub struct Perfect {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: String,
	}

	#[derive(Clone)]
	pub struct PerfectDownload {
		pub n: u64,
		pub p: u64,
	}

	pub fn perfects() -> Vec<Perfect> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: String::from("1979 Nelson&Slowinski") },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: String::from("1979 Noll") },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: String::from("1978 Noll&Nickel") },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: String::from("1971 Tuckerman") },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: String::from("1963 Gillies") },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: String::from("1963 Gillies") },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: String::from("1963 Gillies") },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: String::from("1961 Hurwitz") },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: String::from("1957 Riesel") },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: String::from("1952 Robinson") },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: String::from("1952 Robinson") },
			Perfect {n: 14, p: 607, digits: 366, discovery: String::from("1952 Robinson") },
			Perfect {n: 13, p: 521, digits: 314, discovery: String::from("1952 Robinson") },
			Perfect {n: 12, p: 127, digits: 77, discovery: String::from("1876 Lucas") },
			Perfect {n: 11, p: 107, digits: 65, discovery: String::from("1914 Powers") },
			Perfect {n: 10, p: 89, digits: 54, discovery: String::from("1911 Powers") },
			Perfect {n: 9, p: 61, digits: 37, discovery: String::from("1883 Pervushin") },
			Perfect {n: 8, p: 31, digits: 19, discovery: String::from("1772 Euler") },
			Perfect {n: 7, p: 19, digits: 12, discovery: String::from("1588 Cataldi") },
			Perfect {n: 6, p: 17, digits: 10, discovery: String::from("1588 Cataldi") },
			Perfect {n: 5, p: 13, digits: 8, discovery: String::from("1456 ?") },
			Perfect {n: 4, p: 7, digits: 4, discovery: String::from("?") },
			Perfect {n: 3, p: 5, digits: 3, discovery: String::from("?") },
			Perfect {n: 2, p: 3, digits: 2, discovery: String::from("?") },
			Perfect {n: 1, p: 2, digits: 1, discovery: String::from("?") },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize, p:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let perfects = perfects_utils::perfects().to_owned();

    for perfect in perfects.iter() {
		let perfectp:u64 = perfect.p;
		let perfect_download = perfects_utils::PerfectDownload {n: perfect.n, p: perfect.p};
		let equation:String = format!("2{} × (2{}-1)",&(perfectp-1).to_string(),&(perfectp).to_string());

        html.push(
            tr![
                td![perfect.n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfect.digits.to_string()],//digits in length
                td![perfect.discovery],//discovery
				td![button!["Generate",input_ev("input", move |text| Msg::GenerateDownload(perfect_download))]],

            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>