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

use libc::{self, c_char, c_int, c_short, c_void, size_t, socklen_t, ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnixSender>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, sender_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + sender_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let senders = (0..sender_length).map(|index| {
                UnixSender::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, senders))
        }
    }
}

pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], senders: Vec<UnixSender>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), senders.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as u64,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + senders.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for sender in senders.into_iter() {
                fds.push(sender.fd);
                mem::forget(sender);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_mut_ptr() as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::PF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let mut path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX").unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if libc::mkstemp(path.as_mut_ptr()) == ptr::null() {
                    return Error::last_os_error().raw_os_error()
                }

                let mut sockaddr = libc::sockaddr_un {
                    sun_family: libc::AF_UNIX,
                    sun_path: [ 0 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr(),
                              sockaddr.sun_path.len() as size_t);

                if libc::bind(fd,
                              &sockaddr,
                              mem::size_of::<c_short>() + libc::strlen(sockaddr.sun_path)) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error())
            }

            Ok(UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr()).to_bytes()))
        }
    }

    pub fn accept(mut self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnixSender>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, senders) = try!(receiver.recv());
            Ok((receiver, data, senders))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[cfg(target_os="linux")]
#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

<commit_msg>Get things compiling on Linux<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::{self, c_char, c_int, c_short, c_uint, c_ushort, c_void, size_t, sockaddr, sockaddr_un, socklen_t};
use libc::{ssize_t};
use std::ffi::{CStr, CString};
use std::io::Error;
use std::iter;
use std::mem;
use std::ptr;

pub fn channel() -> Result<(UnixSender, UnixReceiver),c_int> {
    let mut results = [0, 0];
    unsafe {
        if socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, &mut results[0]) >= 0 {
            Ok((UnixSender::from_fd(results[0]), UnixReceiver::from_fd(results[1])))
        } else {
            Err(Error::last_os_error().raw_os_error().unwrap())
        }
    }
}

pub struct UnixReceiver {
    fd: c_int,
}

impl Drop for UnixReceiver {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixReceiver {
    fn from_fd(fd: c_int) -> UnixReceiver {
        UnixReceiver {
            fd: fd,
        }
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<UnixSender>),c_int> {
        unsafe {
            let mut length_data: [usize; 2] = [0, 0];
            let result = libc::recv(self.fd,
                                    &mut length_data[0] as *mut _ as *mut c_void,
                                    mem::size_of::<[usize; 2]>() as size_t,
                                    MSG_WAITALL);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let [data_length, sender_length] = length_data;
            let cmsg_length = mem::size_of::<cmsghdr>() + sender_length * mem::size_of::<c_int>();
            let cmsg_buffer: *mut cmsghdr = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;

            let mut data_buffer: Vec<u8> = iter::repeat(0).take(data_length).collect();
            let mut iovec = iovec {
                iov_base: &mut data_buffer[0] as *mut _ as *mut i8,
                iov_len: data_length as size_t,
            };

            let mut msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = recvmsg(self.fd, &mut msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_fds = cmsg_buffer.offset(1) as *const u8 as *const c_int;
            let senders = (0..sender_length).map(|index| {
                UnixSender::from_fd(*cmsg_fds.offset(index as isize))
            }).collect();

            Ok((data_buffer, senders))
        }
    }
}

pub struct UnixSender {
    fd: c_int,
}

impl Drop for UnixSender {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl Clone for UnixSender {
    fn clone(&self) -> UnixSender {
        unsafe {
            UnixSender {
                fd: libc::dup(self.fd)
            }
        }
    }
}

impl UnixSender {
    fn from_fd(fd: c_int) -> UnixSender {
        UnixSender {
            fd: fd,
        }
    }

    pub fn send(&self, data: &[u8], senders: Vec<UnixSender>) -> Result<(),c_int> {
        unsafe {
            let length_data: [usize; 2] = [data.len(), senders.len()];
            let result = libc::send(self.fd,
                                    &length_data[0] as *const _ as *const c_void,
                                    mem::size_of::<[usize; 2]>() as u64,
                                    0);
            if result <= 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let cmsg_length = mem::size_of::<cmsghdr>() + senders.len() * mem::size_of::<c_int>();
            let cmsg_buffer = libc::malloc(cmsg_length as size_t) as *mut cmsghdr;
            (*cmsg_buffer).cmsg_len = cmsg_length as size_t;
            (*cmsg_buffer).cmsg_level = libc::SOL_SOCKET;
            (*cmsg_buffer).cmsg_type = SCM_RIGHTS;

            let mut fds = Vec::new();
            for sender in senders.into_iter() {
                fds.push(sender.fd);
                mem::forget(sender);
            }
            ptr::copy_nonoverlapping(fds.as_ptr(),
                                     cmsg_buffer.offset(1) as *mut _ as *mut c_int,
                                     fds.len());

            let mut iovec = iovec {
                iov_base: data.as_ptr() as *const i8 as *mut i8,
                iov_len: data.len() as size_t,
            };

            let msghdr = msghdr {
                msg_name: ptr::null_mut(),
                msg_namelen: 0,
                msg_iov: &mut iovec,
                msg_iovlen: 1,
                msg_control: cmsg_buffer as *mut c_void,
                msg_controllen: cmsg_length as size_t,
                msg_flags: 0,
            };

            let result = sendmsg(self.fd, &msghdr, 0);
            libc::free(cmsg_buffer as *mut c_void);

            if result > 0 {
                Ok(())
            } else {
                Err(Error::last_os_error().raw_os_error().unwrap())
            }
        }
    }

    pub fn connect(name: String) -> Result<UnixSender,c_int> {
        let name = CString::new(name).unwrap();
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut sockaddr = sockaddr_un {
                sun_family: libc::AF_UNIX as u16,
                sun_path: [ 0; 108 ],
            };
            libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                          name.as_ptr(),
                          sockaddr.sun_path.len() as size_t);

            let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
            if libc::connect(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok(UnixSender {
                fd: fd,
            })
        }
    }
}

pub struct UnixOneShotServer {
    fd: c_int,
}

impl Drop for UnixOneShotServer {
    fn drop(&mut self) {
        unsafe {
            assert!(libc::close(self.fd) == 0)
        }
    }
}

impl UnixOneShotServer {
    pub fn new() -> Result<(UnixOneShotServer, String),c_int> {
        unsafe {
            let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
            let mut path: Vec<u8>;
            loop {
                let path_string = CString::new(b"/tmp/rust-ipc-socket.XXXXXX" as &[u8]).unwrap();
                path = path_string.as_bytes().iter().cloned().collect();
                if mktemp(path.as_mut_ptr() as *mut c_char) == ptr::null_mut() {
                    return Err(Error::last_os_error().raw_os_error().unwrap())
                }

                let mut sockaddr = sockaddr_un {
                    sun_family: libc::AF_UNIX as c_ushort,
                    sun_path: [ 0; 108 ],
                };
                libc::strncpy(sockaddr.sun_path.as_mut_ptr(),
                              path.as_ptr() as *const c_char,
                              sockaddr.sun_path.len() as size_t);

                let len = mem::size_of::<c_short>() + (libc::strlen(sockaddr.sun_path.as_ptr()) as usize);
                if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as c_uint) == 0 {
                    break
                }

                let errno = Error::last_os_error().raw_os_error().unwrap();
                if errno != libc::EINVAL {
                    return Err(errno)
                }
            }

            if libc::listen(fd, 10) != 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            Ok((UnixOneShotServer {
                fd: fd,
            }, String::from_utf8(CStr::from_ptr(path.as_ptr() as *const c_char).to_bytes().to_owned()).unwrap()))
        }
    }

    pub fn accept(self) -> Result<(UnixReceiver, Vec<u8>, Vec<UnixSender>),c_int> {
        unsafe {
            let mut sockaddr = mem::uninitialized();
            let mut sockaddr_len = mem::uninitialized();
            let client_fd = libc::accept(self.fd, &mut sockaddr, &mut sockaddr_len);
            if client_fd < 0 {
                return Err(Error::last_os_error().raw_os_error().unwrap())
            }

            let receiver = UnixReceiver {
                fd: client_fd,
            };
            let (data, senders) = try!(receiver.recv());
            Ok((receiver, data, senders))
        }
    }
}

// FFI stuff follows:

const MSG_WAITALL: c_int = 0x100;
const SCM_RIGHTS: c_int = 0x01;

extern {
    fn mktemp(template: *mut c_char) -> *mut c_char;
    fn recvmsg(socket: c_int, message: *mut msghdr, flags: c_int) -> ssize_t;
    fn sendmsg(socket: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
    fn socketpair(domain: c_int, socket_type: c_int, protocol: c_int, sv: *mut c_int) -> c_int;
}

#[repr(C)]
struct msghdr {
    msg_name: *mut c_void,
    msg_namelen: socklen_t,
    msg_iov: *mut iovec,
    msg_iovlen: size_t,
    msg_control: *mut c_void,
    msg_controllen: size_t,
    msg_flags: c_int,
}

#[repr(C)]
struct iovec {
    iov_base: *mut c_char,
    iov_len: size_t,
}

#[cfg(target_os="linux")]
#[repr(C)]
struct cmsghdr {
    cmsg_len: size_t,
    cmsg_level: c_int,
    cmsg_type: c_int,
}

<|endoftext|>


<commit_before>// spell-checker:ignore (URL) appspot

use crate::numeric::*;

pub(crate) trait Basis {
    const BASIS: &'static [u64];
}

impl Basis for Montgomery<u64> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
    //  discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
}

impl Basis for Montgomery<u32> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
    //  discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[
        4230279247111683200,
        14694767155120705706,
        16641139526367750375,
    ];
}

#[derive(Eq, PartialEq)]
pub(crate) enum Result {
    Prime,
    Pseudoprime,
    Composite(u64),
}

impl Result {
    pub(crate) fn is_prime(&self) -> bool {
        *self == Result::Prime
    }
}

// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
    use self::Result::*;

    let n = m.modulus();
    debug_assert!(n > 1);
    debug_assert!(n % 2 != 0);

    // n-1 = r 2ⁱ
    let i = (n - 1).trailing_zeros();
    let r = (n - 1) >> i;

    let one = m.one();
    let minus_one = m.minus_one();

    for _a in A::BASIS.iter() {
        let _a = _a % n;
        if _a == 0 {
            break;
        }

        let a = m.from_u64(_a);

        // x = a^r mod n
        let mut x = m.pow(a, r);

        {
            // y = ((x²)²...)² i times = x ^ (2ⁱ) = a ^ (r 2ⁱ) = x ^ (n - 1)
            let mut y = x;
            for _ in 0..i {
                y = m.mul(y, y)
            }
            if y != one {
                return Pseudoprime;
            };
        }

        if x == one || x == minus_one {
            continue;
        }

        loop {
            let y = m.mul(x, x);
            if y == one {
                return Composite(gcd(m.to_u64(x) - 1, m.modulus()));
            }
            if y == minus_one {
                // This basis element is not a witness of `n` being composite.
                // Keep looking.
                break;
            }
            x = y;
        }
    }

    Prime
}

// Used by build.rs' tests and debug assertions
#[allow(dead_code)]
pub(crate) fn is_prime(n: u64) -> bool {
    if n < 2 {
        false
    } else if n % 2 == 0 {
        n == 2
    } else {
        test::<Montgomery<u64>>(Montgomery::new(n)).is_prime()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::numeric::{Arithmetic, Montgomery};
    use quickcheck::quickcheck;
    use std::iter;
    const LARGEST_U64_PRIME: u64 = 0xFFFFFFFFFFFFFFC5;

    fn primes() -> impl Iterator<Item = u64> {
        iter::once(2).chain(odd_primes())
    }

    fn odd_primes() -> impl Iterator<Item = u64> {
        use crate::table::{NEXT_PRIME, P_INVS_U64};
        P_INVS_U64
            .iter()
            .map(|(p, _, _)| *p)
            .chain(iter::once(NEXT_PRIME))
    }

    #[test]
    fn largest_prime() {
        assert!(is_prime(LARGEST_U64_PRIME));
    }

    #[test]
    fn largest_composites() {
        for i in LARGEST_U64_PRIME + 1..=u64::MAX {
            assert!(!is_prime(i), "2⁶⁴ - {} reported prime", u64::MAX - i + 1);
        }
    }

    #[test]
    fn two() {
        assert!(is_prime(2));
    }

    fn first_primes<A: Arithmetic + Basis>() {
        for p in odd_primes() {
            assert!(test(A::new(p)).is_prime(), "{} reported composite", p);
        }
    }

    #[test]
    fn first_primes_32() {
        first_primes::<Montgomery<u32>>()
    }

    #[test]
    fn first_primes_64() {
        first_primes::<Montgomery<u64>>()
    }

    #[test]
    fn one() {
        assert!(!is_prime(1));
    }
    #[test]
    fn zero() {
        assert!(!is_prime(0));
    }

    fn first_composites<A: Arithmetic + Basis>() {
        for (p, q) in primes().zip(odd_primes()) {
            for i in p + 1..q {
                assert!(!is_prime(i), "{} reported prime", i);
            }
        }
    }

    #[test]
    fn first_composites_32() {
        first_composites::<Montgomery<u32>>()
    }

    #[test]
    fn first_composites_64() {
        first_composites::<Montgomery<u64>>()
    }

    #[test]
    fn issue_1556() {
        // 10 425 511 = 2441 × 4271
        assert!(!is_prime(10_425_511));
    }

    fn small_semiprimes<A: Arithmetic + Basis>() {
        for p in odd_primes() {
            for q in odd_primes().take_while(|q| *q <= p) {
                let n = p * q;
                let m = A::new(n);
                assert!(!test(m).is_prime(), "{} = {} × {} reported prime", n, p, q);
            }
        }
    }

    #[test]
    fn small_semiprimes_32() {
        small_semiprimes::<Montgomery<u32>>()
    }

    #[test]
    fn small_semiprimes_64() {
        small_semiprimes::<Montgomery<u64>>()
    }

    quickcheck! {
        fn composites(i: u64, j: u64) -> bool {
            i < 2 || j < 2 || !is_prime(i*j)
        }
    }
}
<commit_msg>factor::miller_rabin: Squash another bug!  >:3<commit_after>// spell-checker:ignore (URL) appspot

use crate::numeric::*;

pub(crate) trait Basis {
    const BASIS: &'static [u64];
}

impl Basis for Montgomery<u64> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
    //  discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
}

impl Basis for Montgomery<u32> {
    // Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
    //  discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
    #[allow(clippy::unreadable_literal)]
    const BASIS: &'static [u64] = &[
        4230279247111683200,
        14694767155120705706,
        16641139526367750375,
    ];
}

#[derive(Eq, PartialEq)]
pub(crate) enum Result {
    Prime,
    Pseudoprime,
    Composite(u64),
}

impl Result {
    pub(crate) fn is_prime(&self) -> bool {
        *self == Result::Prime
    }
}

// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
// (some) dividers; it will fail to factor strong pseudoprimes.
#[allow(clippy::many_single_char_names)]
pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
    use self::Result::*;

    let n = m.modulus();
    debug_assert!(n > 1);
    debug_assert!(n % 2 != 0);

    // n-1 = r 2ⁱ
    let i = (n - 1).trailing_zeros();
    let r = (n - 1) >> i;

    let one = m.one();
    let minus_one = m.minus_one();

    for _a in A::BASIS.iter() {
        let _a = _a % n;
        if _a == 0 {
            continue;
        }

        let a = m.from_u64(_a);

        // x = a^r mod n
        let mut x = m.pow(a, r);

        {
            // y = ((x²)²...)² i times = x ^ (2ⁱ) = a ^ (r 2ⁱ) = x ^ (n - 1)
            let mut y = x;
            for _ in 0..i {
                y = m.mul(y, y)
            }
            if y != one {
                return Pseudoprime;
            };
        }

        if x == one || x == minus_one {
            continue;
        }

        loop {
            let y = m.mul(x, x);
            if y == one {
                return Composite(gcd(m.to_u64(x) - 1, m.modulus()));
            }
            if y == minus_one {
                // This basis element is not a witness of `n` being composite.
                // Keep looking.
                break;
            }
            x = y;
        }
    }

    Prime
}

// Used by build.rs' tests and debug assertions
#[allow(dead_code)]
pub(crate) fn is_prime(n: u64) -> bool {
    if n < 2 {
        false
    } else if n % 2 == 0 {
        n == 2
    } else {
        test::<Montgomery<u64>>(Montgomery::new(n)).is_prime()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::numeric::{Arithmetic, Montgomery};
    use quickcheck::quickcheck;
    use std::iter;
    const LARGEST_U64_PRIME: u64 = 0xFFFFFFFFFFFFFFC5;

    fn primes() -> impl Iterator<Item = u64> {
        iter::once(2).chain(odd_primes())
    }

    fn odd_primes() -> impl Iterator<Item = u64> {
        use crate::table::{NEXT_PRIME, P_INVS_U64};
        P_INVS_U64
            .iter()
            .map(|(p, _, _)| *p)
            .chain(iter::once(NEXT_PRIME))
    }

    #[test]
    fn largest_prime() {
        assert!(is_prime(LARGEST_U64_PRIME));
    }

    #[test]
    fn largest_composites() {
        for i in LARGEST_U64_PRIME + 1..=u64::MAX {
            assert!(!is_prime(i), "2⁶⁴ - {} reported prime", u64::MAX - i + 1);
        }
    }

    #[test]
    fn two() {
        assert!(is_prime(2));
    }

    fn first_primes<A: Arithmetic + Basis>() {
        for p in odd_primes() {
            assert!(test(A::new(p)).is_prime(), "{} reported composite", p);
        }
    }

    #[test]
    fn first_primes_32() {
        first_primes::<Montgomery<u32>>()
    }

    #[test]
    fn first_primes_64() {
        first_primes::<Montgomery<u64>>()
    }

    #[test]
    fn one() {
        assert!(!is_prime(1));
    }
    #[test]
    fn zero() {
        assert!(!is_prime(0));
    }

    fn first_composites<A: Arithmetic + Basis>() {
        for (p, q) in primes().zip(odd_primes()) {
            for i in p + 1..q {
                assert!(!is_prime(i), "{} reported prime", i);
            }
        }
    }

    #[test]
    fn first_composites_32() {
        first_composites::<Montgomery<u32>>()
    }

    #[test]
    fn first_composites_64() {
        first_composites::<Montgomery<u64>>()
    }

    #[test]
    fn issue_1556() {
        // 10 425 511 = 2441 × 4271
        assert!(!is_prime(10_425_511));
    }

    fn small_semiprimes<A: Arithmetic + Basis>() {
        for p in odd_primes() {
            for q in odd_primes().take_while(|q| *q <= p) {
                let n = p * q;
                let m = A::new(n);
                assert!(!test(m).is_prime(), "{} = {} × {} reported prime", n, p, q);
            }
        }
    }

    #[test]
    fn small_semiprimes_32() {
        small_semiprimes::<Montgomery<u32>>()
    }

    #[test]
    fn small_semiprimes_64() {
        small_semiprimes::<Montgomery<u64>>()
    }

    quickcheck! {
        fn composites(i: u64, j: u64) -> bool {
            i < 2 || j < 2 || !is_prime(i*j)
        }
    }
}
<|endoftext|>


<commit_before>extern crate sfml;
extern crate nalgebra as na;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, Texture, Sprite, Color};

use na::{Vec2};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.clear();

        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32,
    shipTexture: Texture
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        let mut t = Texture::new_from_file("plane.png")
            .expect("Cannot create Texture");
        t.set_smooth(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height,
            shipTexture: t
        }
    }

    fn clear(&mut self) {
        self.win.clear(&Color::black());
    }
}

struct Boid<'a> {
    pos: Vec2<f32>,
    vel: Vec2<f32>,
    acc: Vec2<f32>,
    sprite: Sprite<'a>,
    maxSpeed: f32,
    maxSteer: f32
}

impl<'a> Boid<'a> {

    fn new(env: SFMLEnv) -> Boid<'a> {
        let mut s = Sprite::new_with_texture(env.shipTexture).expect("Cannot create ship sprite.");
        let rect = s.get_local_bounds();
        s.set_origin2f(rect.width / 2.0,
                       rect.height / 2.0);
        Boid {
            pos: Vec2::new(0.0, 0.0),
            vel: Vec2::new(0.0, 0.0),
            acc: Vec2::new(0.0, 0.0),
            sprite: s,
            maxSpeed: 5.0,
            maxSteer: 0.2
        }
    }

}
<commit_msg>it compiles<commit_after>extern crate sfml;
extern crate nalgebra as na;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, RenderTarget, Texture, Sprite, Color};

use na::{Vec2};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.clear();

        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32,
    shipTexture: Texture
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        let mut t = Texture::new_from_file("plane.png")
            .expect("Cannot create Texture");
        t.set_smooth(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height,
            shipTexture: t
        }
    }

    fn clear(&mut self) {
        self.win.clear(&Color::black());
    }
}

struct Boid<'a> {
    pos: Vec2<f32>,
    vel: Vec2<f32>,
    acc: Vec2<f32>,
    sprite: Sprite<'a>,
    maxSpeed: f32,
    maxSteer: f32
}

impl<'a> Boid<'a> {

    fn new(env: &'a SFMLEnv) -> Boid<'a> {
        let mut s = Sprite::new_with_texture(&env.shipTexture).expect("Cannot create ship sprite.");
        let rect = s.get_local_bounds();
        s.set_origin2f(rect.width / 2.0,
                       rect.height / 2.0);
        Boid {
            pos: Vec2::new(0.0, 0.0),
            vel: Vec2::new(0.0, 0.0),
            acc: Vec2::new(0.0, 0.0),
            sprite: s,
            maxSpeed: 5.0,
            maxSteer: 0.2
        }
    }

}
<|endoftext|>


<commit_before>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

extern crate extra;
use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;

/// Returns Some(`rem`) if the line is a horizontal rule, with `rem` being the
/// buf after the hrule. Otherwise returns None.
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut buf = buf;

    // Skip up to three leading spaces.
    //
    // We don't need to care about tabs here as in this position they are
    // equivalent to 4 spaces, which means we would not parse this as a
    // hrule.
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces

    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}
<commit_msg>Doc: Returns -> return<commit_after>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

extern crate extra;
use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;

/// Return Some(`rem`) if the line is a horizontal rule, with `rem` being the
/// buf after the hrule. Otherwise return None.
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut buf = buf;

    // Skip up to three leading spaces.
    //
    // We don't need to care about tabs here as in this position they are
    // equivalent to 4 spaces, which means we would not parse this as a
    // hrule.
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces

    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}
<|endoftext|>


<commit_before>extern crate find_folder;
extern crate conrod;

use conrod::backend::piston::{self, Window, WindowEvents, OpenGL};
use conrod::backend::piston::event::UpdateEvent;
use db;

const WIDTH: u32 = 1280;
const HEIGHT: u32 = 720;
const BUTTON_W: f64 = 150.0;
const BUTTON_H: f64 = 30.0;

#[derive(Clone)]
enum Screen {
    Title,
    Play,
    Options,
    ChooseTeam,
    Battle,
}

/// App struct, which contains important data
///     screen:         screen that gets drawn
///     label_color:    color of labels (text)
///     bg_color:       background color
///     pokedex:        currently used pokedex
///     pkmn_team:      current team
///     sel_pkmn:       currently selected pokemon
#[derive(Clone)]
struct App {
    screen: Screen,
    label_color: conrod::Color,
    bg_color: conrod::Color,
    pokedex: db::pokedex::Pokedex,
    pkmn_team: Vec<db::pokemon_token::PokemonToken>,
    sel_pkmn: Option<db::pokemon_token::PokemonToken>,
}

impl App {
    fn new() -> Self {
        App {
            screen: Screen::Title,
            label_color: conrod::color::BLACK,
            bg_color: conrod::color::WHITE,
            pokedex: db::pokedex::Pokedex::new(),
            pkmn_team: Vec::new(),
            sel_pkmn: None,
        }
    }

    fn set_screen(mut self, screen: Screen) {
        self.screen = screen
    }

    fn get_screen(&self) -> Screen {
        self.clone().screen
    }

    fn get_team(&self) -> Vec<db::pokemon_token::PokemonToken> {
        self.clone().pkmn_team
    }
}

pub fn draw_window() {
    // Construct the window.
    let mut window: Window =
        piston::window::WindowSettings::new("PokemonBattleArena", [WIDTH, HEIGHT])
            .opengl(OpenGL::V3_2)
            .vsync(true)
            .samples(4)
            .exit_on_esc(true)
            .build()
            .unwrap_or_else(|e| { panic!("Failed to build window: {}", e) });

    // Create the event loop.
    let mut events = WindowEvents::new();

    // Construct the `Ui`.
    let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

    // Create Ids for every used widget
    let ids = Ids::new(ui.widget_id_generator());

    // Add a font from file
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap_or_else(
        |e| { panic!("Failed to find folder: {}", e) }
    );
    let font_path = assets.join("fonts/arial/arial.ttf");
    ui.fonts.insert_from_file(font_path).unwrap_or_else(
        |e| { panic!("Failed to get font: {}", e) }
    );

    // No text to draw -> create an empty text texture cache.
    let mut text_texture_cache = piston::window::GlyphCache::new(&mut window, WIDTH, HEIGHT);

    // The image map describing each of our widget->image mappings (in this case none)
    let image_map = conrod::image::Map::new();

    let mut app = App::new();

    // Poll events from the window.
    while let Some(event) = window.next_event(&mut events) {
        // Convert the piston event to a conrod event.
        if let Some(e) = piston::window::convert_event(event.clone(), &window) {
            ui.handle_event(e);
        }

        event.update(|_| {
            use conrod::{widget, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget};

            let mut ui = &mut ui.set_widgets();

            // Create new empty canvas
            widget::Canvas::new().color(app.bg_color).set(ids.canvas, ui);

            // draws Title-Screen
            // Contains:    Play-Button
            //              Options-Button
            //              Exit-Button
            if let Screen::Title = app.screen {
                // Play button
                // Shows Play-Screen when clicked
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Play")
                    .label_color(app.label_color)
                    .middle_of(ids.canvas)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_play, ui)
                    .was_clicked()
                {
                    println!("Play");
                    app.screen = Screen::Play;
                }

                // Options button
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Options")
                    .label_color(app.label_color)
                    .down_from(ids.button_play, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_options, ui)
                    .was_clicked()
                {
                    app.screen = Screen::Options;
                    println!("Options");
                }

                // Exit button
                // closes the window
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Exit")
                    .label_color(app.label_color)
                    .down_from(ids.button_options, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_exit, ui)
                    .was_clicked()
                {
                    ::std::process::exit(0);
                }
            }

            // draws Play-Screen
            // Contains:    Singleplayer-Button
            //              Multiplayer-Button
            //              Back-Button
            if let Screen::Play = app.screen {
                // Singleplayer button
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Singleplayer")
                    .label_color(app.label_color)
                    .middle_of(ids.canvas)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_sp, ui)
                    .was_clicked()
                {
                    app.screen = Screen::ChooseTeam;
                    println!("Singleplayer");
                }

                // Multiplayer button
                // not implemented yet
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Multiplayer")
                    .label_color(app.label_color)
                    .down_from(ids.button_sp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_mp, ui)
                    .was_clicked()
                {
                    println!("Multiplayer");
                }

                // Back button
                // returns to previous screen
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .down_from(ids.button_mp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Title;
                }
            }

            // draws Options-Screen
            if let Screen::Options = app.screen {
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .down_from(ids.button_mp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Title;
                }
            }

            // Draws Choose Team Screen
            // IDEAS:   - pictures of pokemon
            //          - filter gen/type (get pokedex with only specific type/gen)
            //          - search ( fn that gives Vec with pokemon that have certain string in name)
            if let Screen::ChooseTeam = app.screen {

                // ===============================================================
                // = Scrollable List from which the Player can select their team =
                // ===============================================================
                let pokedex_entries = app.pokedex.get_entries();
                let num_items = pokedex_entries.len();
                let item_h = 32.0;

                let (mut events, scrollbar) = widget::ListSelect::single(num_items, item_h)
                    .scrollbar_next_to()
                    .w_h(200.0, 650.0)
                    .mid_left_with_margin_on(ids.canvas, 25.0)
                    .scrollbar_width(15.0)
                    .set(ids.s_list_pkmn, ui);

                // Instantiate the scrollbar for the list.
                if let Some(s) = scrollbar { s.set(ui); }

                // Create Vec with all the pokemon names to be displayed
                let mut pkmn_names = Vec::new();
                for pokemon in pokedex_entries {
                    pkmn_names.push(pokemon.get_name());
                }

                // Handle the `ListSelect`s events.
                while let Some(event) = events.next(ui, |i| ::std::collections::HashSet::<usize>::new().contains(&i)) {
                    use conrod::widget::list_select::Event;

                    match event {
                        // For the `Item` events we instantiate the `List`'s items.
                        Event::Item(item) => {
                            let label = &pkmn_names[item.i];

                            // each button with the respective pokemon name as label
                            let button = widget::Button::new()
                                .border(0.0)
                                .color(conrod::color::LIGHT_GREY)
                                .label(label)
                                .label_color(app.label_color);
                            item.set(button, ui);
                        },

                        // Add pokemon to team when button is pressed
                        Event::Selection(selection) => {
                            println!("selected index (PokeDex): {:?}", selection);

                            app.sel_pkmn = Some(
                                db::pokemon_token::PokemonToken::from_model(
                                    app.pokedex.pokemon_by_id(selection + 1).unwrap()
                                )
                            );
                        }
                        _ => {},
                    }
                }

                // =====================================
                // = List that shows the player's team =
                // =====================================
                let (mut events, _) = widget::ListSelect::single(6, 650.0/6.0)
                    .w_h(200.0, 650.0)
                    .mid_right_with_margin_on(ids.canvas, 25.0)
                    .set(ids.s_list_team, ui);

                let mut team_names = Vec::with_capacity(6);
                for pokemon in &app.pkmn_team {
                    team_names.push(pokemon.get_name());
                }

                // Handle the `ListSelect`s events.
                while let Some(event) = events.next(ui, |i| ::std::collections::HashSet::<usize>::new().contains(&i)) {
                    use conrod::widget::list_select::Event;

                    match event {
                        // For the `Item` events we instantiate the `List`'s items.
                        Event::Item(item) => {
                            // `label` is either the name of the pokemon (if available)
                            // or - (if not)
                            let label = if &team_names.len() > &item.i {
                                &team_names[item.i]
                            } else {
                                "-"
                            };

                            // each list item is a button with `label` as label
                            let button = widget::Button::new()
                                .border(0.0)
                                .color(conrod::color::LIGHT_GREY)
                                .label(label)
                                .label_color(app.label_color);
                            item.set(button, ui);
                        },

                        // Remove pokemon from team when button is pressed
                        //
                        // TODO:
                        //  Change functionality such that the selected pokemon is displayed
                        //  in the middle of the screen (with stats, etc)
                        Event::Selection(selection) => {
                            println!("selected index (Team): {:?}", selection);
                            app.sel_pkmn = Some(app.pkmn_team[selection].clone());
                            app.pkmn_team.remove(selection);
                        }
                        // Do nothing for every other event
                        _ => {},
                    }
                }

                // ===================================
                // = Description of selected Pokemon =
                // ===================================
                let stats = match app.sel_pkmn {
                    None => "No Pokemon Selected".to_string(),
                    Some(ref pkmn) => {
                        let types = match pkmn.get_types() {
                            (type1, db::enums::types::undefined) => type1.to_string(),
                            (type1, type2) => [type1.to_string(), "/".to_string(), type2.to_string()].concat().to_string(),
                        };

                        [
                            "#",
                            &pkmn.get_id().to_string(),
                            " ",
                            &pkmn.get_name(),
                            "\n\nType: ",
                            &types,
                            "\n",
                            &pkmn.get_description()
                        ].concat()
                    }
                };

                widget::Text::new(&stats)
                    .color(app.label_color)
                    .middle_of(ids.canvas)
                    .align_text_middle()
                    .line_spacing(10.0)
                    .set(ids.text_sel_pkmn, ui);

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Select")
                    .label_color(app.label_color)
                    .mid_bottom_with_margin(35.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_select, ui)
                    .was_clicked()
                {
                    println!("Select");

                    match app.sel_pkmn.clone() {
                        Some(pkmn) => {
                            app.pkmn_team.push(pkmn.clone());
                            app.sel_pkmn = None;
                        }
                        None => println!("Error: No Pokemon selected"),
                    };
                }

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .bottom_left_with_margins(35.0, 250.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Play;
                }

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Fight")
                    .label_color(app.label_color)
                    .bottom_right_with_margins(35.0, 250.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_fight, ui)
                    .was_clicked()
                {
                    // temporaryly goes back to title screen
                    println!("Fight");
                    app.screen = Screen::Title;
                }
            }
        });

        window.draw_2d(&event, |c, g| {
            if let Some(primitives) = ui.draw_if_changed() {
                fn texture_from_image<T>(img: &T) -> &T { img };
                piston::window::draw(c, g, primitives,
                                     &mut text_texture_cache,
                                     &image_map,
                                     texture_from_image);
            }
        });
    }
}

widget_ids! {
    struct Ids {
        // *** canvas ***
        canvas,

        // *** buttons ***
        button_play,
        button_options,
        button_exit,
        button_sp,
        button_mp,
        button_back,
        button_fight,
        button_select,

        // *** selection_list ***
        s_list_pkmn,
        s_list_team,

        // *** text ***
        text_sel_pkmn,
    }
}
<commit_msg>Added ability to remove pokemon from team<commit_after>extern crate find_folder;
extern crate conrod;

use conrod::backend::piston::{self, Window, WindowEvents, OpenGL};
use conrod::backend::piston::event::UpdateEvent;
use db;

const WIDTH: u32 = 1280;
const HEIGHT: u32 = 720;
const BUTTON_W: f64 = 150.0;
const BUTTON_H: f64 = 30.0;

#[derive(Clone)]
enum Screen {
    Title,
    Play,
    Options,
    ChooseTeam,
    Battle,
}

/// App struct, which contains important data
///     screen:         screen that gets drawn
///     label_color:    color of labels (text)
///     bg_color:       background color
///     pokedex:        currently used pokedex
///     pkmn_team:      current team
///     sel_pkmn:       currently selected pokemon
#[derive(Clone)]
struct App {
    screen: Screen,
    label_color: conrod::Color,
    bg_color: conrod::Color,
    pokedex: db::pokedex::Pokedex,
    pkmn_team: Vec<db::pokemon_token::PokemonToken>,
    sel_pkmn: (Option<db::pokemon_token::PokemonToken>, Option<usize>),
}

impl App {
    fn new() -> Self {
        App {
            screen: Screen::Title,
            label_color: conrod::color::BLACK,
            bg_color: conrod::color::WHITE,
            pokedex: db::pokedex::Pokedex::new(),
            pkmn_team: Vec::new(),
            sel_pkmn: (None, None),
        }
    }

    fn set_screen(mut self, screen: Screen) {
        self.screen = screen
    }

    fn get_screen(&self) -> Screen {
        self.clone().screen
    }

    fn get_team(&self) -> Vec<db::pokemon_token::PokemonToken> {
        self.clone().pkmn_team
    }
}

pub fn draw_window() {
    // Construct the window.
    let mut window: Window =
        piston::window::WindowSettings::new("PokemonBattleArena", [WIDTH, HEIGHT])
            .opengl(OpenGL::V3_2)
            .vsync(true)
            .samples(4)
            .exit_on_esc(true)
            .build()
            .unwrap_or_else(|e| { panic!("Failed to build window: {}", e) });

    // Create the event loop.
    let mut events = WindowEvents::new();

    // Construct the `Ui`.
    let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

    // Create Ids for every used widget
    let ids = Ids::new(ui.widget_id_generator());

    // Add a font from file
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap_or_else(
        |e| { panic!("Failed to find folder: {}", e) }
    );
    let font_path = assets.join("fonts/arial/arial.ttf");
    ui.fonts.insert_from_file(font_path).unwrap_or_else(
        |e| { panic!("Failed to get font: {}", e) }
    );

    // No text to draw -> create an empty text texture cache.
    let mut text_texture_cache = piston::window::GlyphCache::new(&mut window, WIDTH, HEIGHT);

    // The image map describing each of our widget->image mappings (in this case none)
    let image_map = conrod::image::Map::new();

    let mut app = App::new();

    // Poll events from the window.
    while let Some(event) = window.next_event(&mut events) {
        // Convert the piston event to a conrod event.
        if let Some(e) = piston::window::convert_event(event.clone(), &window) {
            ui.handle_event(e);
        }

        event.update(|_| {
            use conrod::{widget, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget};

            let mut ui = &mut ui.set_widgets();

            // Create new empty canvas
            widget::Canvas::new().color(app.bg_color).set(ids.canvas, ui);

            // draws Title-Screen
            // Contains:    Play-Button
            //              Options-Button
            //              Exit-Button
            if let Screen::Title = app.screen {
                // Play button
                // Shows Play-Screen when clicked
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Play")
                    .label_color(app.label_color)
                    .middle_of(ids.canvas)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_play, ui)
                    .was_clicked()
                {
                    println!("Play");
                    app.screen = Screen::Play;
                }

                // Options button
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Options")
                    .label_color(app.label_color)
                    .down_from(ids.button_play, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_options, ui)
                    .was_clicked()
                {
                    app.screen = Screen::Options;
                    println!("Options");
                }

                // Exit button
                // closes the window
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Exit")
                    .label_color(app.label_color)
                    .down_from(ids.button_options, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_exit, ui)
                    .was_clicked()
                {
                    ::std::process::exit(0);
                }
            }

            // draws Play-Screen
            // Contains:    Singleplayer-Button
            //              Multiplayer-Button
            //              Back-Button
            if let Screen::Play = app.screen {
                // Singleplayer button
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Singleplayer")
                    .label_color(app.label_color)
                    .middle_of(ids.canvas)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_sp, ui)
                    .was_clicked()
                {
                    app.screen = Screen::ChooseTeam;
                    println!("Singleplayer");
                }

                // Multiplayer button
                // not implemented yet
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Multiplayer")
                    .label_color(app.label_color)
                    .down_from(ids.button_sp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_mp, ui)
                    .was_clicked()
                {
                    println!("Multiplayer");
                }

                // Back button
                // returns to previous screen
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .down_from(ids.button_mp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Title;
                }
            }

            // draws Options-Screen
            if let Screen::Options = app.screen {
                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .down_from(ids.button_mp, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Title;
                }
            }

            // Draws Choose Team Screen
            // IDEAS:   - pictures of pokemon
            //          - filter gen/type (get pokedex with only specific type/gen)
            //          - search ( fn that gives Vec with pokemon that have certain string in name)
            if let Screen::ChooseTeam = app.screen {

                // ===============================================================
                // = Scrollable List from which the Player can select their team =
                // ===============================================================
                let pokedex_entries = app.pokedex.get_entries();
                let num_items = pokedex_entries.len();
                let item_h = 32.0;

                let (mut events, scrollbar) = widget::ListSelect::single(num_items, item_h)
                    .scrollbar_next_to()
                    .w_h(200.0, 650.0)
                    .mid_left_with_margin_on(ids.canvas, 25.0)
                    .scrollbar_width(15.0)
                    .set(ids.s_list_pkmn, ui);

                // Instantiate the scrollbar for the list.
                if let Some(s) = scrollbar { s.set(ui); }

                // Create Vec with all the pokemon names to be displayed
                let mut pkmn_names = Vec::new();
                for pokemon in pokedex_entries {
                    pkmn_names.push(pokemon.get_name());
                }

                // Handle the `ListSelect`s events.
                while let Some(event) = events.next(ui, |i| ::std::collections::HashSet::<usize>::new().contains(&i)) {
                    use conrod::widget::list_select::Event;

                    match event {
                        // For the `Item` events we instantiate the `List`'s items.
                        Event::Item(item) => {
                            let label = &pkmn_names[item.i];

                            // each button with the respective pokemon name as label
                            let button = widget::Button::new()
                                .border(0.0)
                                .color(conrod::color::LIGHT_GREY)
                                .label(label)
                                .label_color(app.label_color);
                            item.set(button, ui);
                        },

                        // Add pokemon to team when button is pressed
                        Event::Selection(selection) => {
                            println!("selected index (PokeDex): {:?}", selection);

                            app.sel_pkmn = (
                                Some(
                                    db::pokemon_token::PokemonToken::from_model(
                                        app.pokedex.pokemon_by_id(selection + 1).unwrap()
                                    )
                                ),
                                None
                            );
                        }
                        _ => {},
                    }
                }

                // =====================================
                // = List that shows the player's team =
                // =====================================
                let (mut events, _) = widget::ListSelect::single(6, 650.0/6.0)
                    .w_h(200.0, 650.0)
                    .mid_right_with_margin_on(ids.canvas, 25.0)
                    .set(ids.s_list_team, ui);

                let mut team_names = Vec::with_capacity(6);
                for pokemon in &app.pkmn_team {
                    team_names.push(pokemon.get_name());
                }

                // Handle the `ListSelect`s events.
                while let Some(event) = events.next(ui, |i| ::std::collections::HashSet::<usize>::new().contains(&i)) {
                    use conrod::widget::list_select::Event;

                    match event {
                        // For the `Item` events we instantiate the `List`'s items.
                        Event::Item(item) => {
                            // `label` is either the name of the pokemon (if available)
                            // or - (if not)
                            let label = if &team_names.len() > &item.i {
                                &team_names[item.i]
                            } else {
                                "-"
                            };

                            // each list item is a button with `label` as label
                            let button = widget::Button::new()
                                .border(0.0)
                                .color(conrod::color::LIGHT_GREY)
                                .label(label)
                                .label_color(app.label_color);
                            item.set(button, ui);
                        },

                        // Remove pokemon from team when button is pressed
                        //
                        // TODO:
                        //  Change functionality such that the selected pokemon is displayed
                        //  in the middle of the screen (with stats, etc)
                        Event::Selection(selection) => {
                            println!("selected index (Team): {:?}", selection);
                            app.sel_pkmn = (Some(app.pkmn_team[selection].clone()), Some(selection));
                        }
                        // Do nothing for every other event
                        _ => {},
                    }
                }

                // ===================================
                // = Description of selected Pokemon =
                // ===================================
                let stats = match app.sel_pkmn.0 {
                    None => "No Pokemon Selected".to_string(),
                    Some(ref pkmn) => {
                        let types = match pkmn.get_types() {
                            (type1, db::enums::types::undefined) => type1.to_string(),
                            (type1, type2) => [type1.to_string(), "/".to_string(), type2.to_string()].concat().to_string(),
                        };

                        [
                            "#",
                            &pkmn.get_id().to_string(),
                            " ",
                            &pkmn.get_name(),
                            "\n\nType: ",
                            &types,
                            "\n",
                            &pkmn.get_description()
                        ].concat()
                    }
                };

                widget::Text::new(&stats)
                    .color(app.label_color)
                    .middle_of(ids.canvas)
                    .align_text_middle()
                    .line_spacing(10.0)
                    .set(ids.text_sel_pkmn, ui);

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Select")
                    .label_color(app.label_color)
                    .mid_bottom_with_margin(50.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_select, ui)
                    .was_clicked()
                {
                    println!("Select");

                    match app.sel_pkmn.0.clone() {
                        Some(pkmn) => {
                            app.pkmn_team.push(pkmn.clone());
                            app.sel_pkmn = (None, None);
                        }
                        None => println!("Error: No Pokemon selected"),
                    };
                }

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Remove")
                    .label_color(app.label_color)
                    .down_from(ids.button_select, 0.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_remove, ui)
                    .was_clicked()
                {
                    println!("Remove");
                    if let Some(i) = app.sel_pkmn.1 {
                        app.pkmn_team.remove(i);
                        app.sel_pkmn = (None, None);
                    } else {
                        println!("Error: No Pokemon at this position")
                    }
                }

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Back")
                    .label_color(app.label_color)
                    .bottom_left_with_margins(35.0, 250.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_back, ui)
                    .was_clicked()
                {
                    println!("Back");
                    app.screen = Screen::Play;
                }

                if widget::Button::new()
                    .border(1.0)
                    .color(app.bg_color)
                    .label("Fight")
                    .label_color(app.label_color)
                    .bottom_right_with_margins(35.0, 250.0)
                    .w_h(BUTTON_W, BUTTON_H)
                    .set(ids.button_fight, ui)
                    .was_clicked()
                {
                    // temporaryly goes back to title screen
                    println!("Fight");
                    app.screen = Screen::Title;
                }
            }
        });

        window.draw_2d(&event, |c, g| {
            if let Some(primitives) = ui.draw_if_changed() {
                fn texture_from_image<T>(img: &T) -> &T { img };
                piston::window::draw(c, g, primitives,
                                     &mut text_texture_cache,
                                     &image_map,
                                     texture_from_image);
            }
        });
    }
}

widget_ids! {
    struct Ids {
        // *** canvas ***
        canvas,

        // *** buttons ***
        button_play,
        button_options,
        button_exit,
        button_sp,
        button_mp,
        button_back,
        button_fight,
        button_select,
        button_remove,

        // *** selection_list ***
        s_list_pkmn,
        s_list_team,

        // *** text ***
        text_sel_pkmn,
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use aarch64_esr_decoder::{decode, Decoded, FieldInfo};
use std::num::ParseIntError;
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> String {
    if let Ok(esr) = parse_number(esr) {
        let decoded = decode(esr);
        if let Ok(decoded) = &decoded {
            show_decoded(esr, decoded);
        }
        format!("{:?}", decoded)
    } else {
        "Invalid ESR".to_string()
    }
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    cell.set_text_content(contents);
    Ok(cell)
}

fn show_decoded(esr: u64, decoded: &Decoded) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    table.set_inner_html("");

    // First row has ESR in binary
    let row = document.create_element("tr")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // Top-level description
    let row = document.create_element("tr")?;
    let cell = make_cell(&document, decoded.description.as_deref(), 64)?;
    row.append_child(&cell)?;
    table.append_child(&row)?;

    // Top-level field names
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| Some(field.name))?;
    table.append_child(&row)?;

    // Top-level field descriptions
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| {
        field
            .decoded
            .as_ref()
            .and_then(|decoded| decoded.description.clone())
    })?;
    table.append_child(&row)?;

    Ok(())
}

fn add_field_cells<F, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    get_contents: F,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    S: Deref<Target = str>,
{
    let mut last = 64;
    for field in fields {
        if field.start + field.width != last {
            // Add a filler
            let cell = make_cell(document, None, last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(document, get_contents(field).as_deref(), field.width)?;
        row.append_child(&cell)?;
        last = field.start;
    }
    Ok(())
}

/// Parse a decimal or hexadecimal number.
fn parse_number(s: &str) -> Result<u64, ParseIntError> {
    if s.starts_with("0x") {
        u64::from_str_radix(&s[2..], 16)
    } else {
        s.parse()
    }
}
<commit_msg>Include field values with names.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use aarch64_esr_decoder::{decode, Decoded, FieldInfo};
use std::num::ParseIntError;
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> String {
    if let Ok(esr) = parse_number(esr) {
        let decoded = decode(esr);
        if let Ok(decoded) = &decoded {
            show_decoded(esr, decoded);
        }
        format!("{:?}", decoded)
    } else {
        "Invalid ESR".to_string()
    }
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    cell.set_text_content(contents);
    Ok(cell)
}

fn show_decoded(esr: u64, decoded: &Decoded) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    table.set_inner_html("");

    // First row has ESR in binary
    let row = document.create_element("tr")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // Top-level description
    let row = document.create_element("tr")?;
    let cell = make_cell(&document, decoded.description.as_deref(), 64)?;
    row.append_child(&cell)?;
    table.append_child(&row)?;

    // Top-level field names and values
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| {
        Some(field.to_string())
    })?;
    table.append_child(&row)?;

    // Top-level field descriptions
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| {
        field
            .decoded
            .as_ref()
            .and_then(|decoded| decoded.description.clone())
    })?;
    table.append_child(&row)?;

    Ok(())
}

fn add_field_cells<F, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    get_contents: F,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    S: Deref<Target = str>,
{
    let mut last = 64;
    for field in fields {
        if field.start + field.width != last {
            // Add a filler
            let cell = make_cell(document, None, last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(document, get_contents(field).as_deref(), field.width)?;
        row.append_child(&cell)?;
        last = field.start;
    }
    Ok(())
}

/// Parse a decimal or hexadecimal number.
fn parse_number(s: &str) -> Result<u64, ParseIntError> {
    if s.starts_with("0x") {
        u64::from_str_radix(&s[2..], 16)
    } else {
        s.parse()
    }
}
<|endoftext|>