<commit_before>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;
pub type kpaddr_t = u64;
pub type kssize_t = i64;
pub type domainset_t = __c_anonymous_domainset;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }

    pub struct sockcred2 {
        pub sc_version: ::c_int,
        pub sc_pid: ::pid_t,
        pub sc_uid: ::uid_t,
        pub sc_euid: ::uid_t,
        pub sc_gid: ::gid_t,
        pub sc_egid: ::gid_t,
        pub sc_ngroups: ::c_int,
        pub sc_groups: [::gid_t; 1],
    }

    pub struct kvm_page {
        pub kp_version: ::u_int,
        pub kp_paddr: ::kpaddr_t,
        pub kp_kmap_vaddr: ::kvaddr_t,
        pub kp_dmap_vaddr: ::kvaddr_t,
        pub kp_prot: ::vm_prot_t,
        pub kp_offset: ::off_t,
        pub kp_len: ::size_t,
    }

    pub struct __c_anonymous_domainset {
        _priv: [::uintptr_t; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const RAND_MAX: ::c_int = 0x7fff_ffff;
pub const ELAST: ::c_int = 97;

pub const KF_TYPE_EVENTFD: ::c_int = 13;

/// max length of devicename
pub const SPECNAMELEN: ::c_int = 255;
pub const KI_NSPARE_PTR: usize = 5;

/// domainset policies
pub const DOMAINSET_POLICY_INVALID: ::c_int = 0;
pub const DOMAINSET_POLICY_ROUNDROBIN: ::c_int = 1;
pub const DOMAINSET_POLICY_FIRSTTOUCH: ::c_int = 2;
pub const DOMAINSET_POLICY_PREFER: ::c_int = 3;
pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4;

f! {
    pub fn SOCKCRED2SIZE(ngrps: usize) -> usize {
        let ngrps = if ngrps > 0 {
            ngrps - 1
        } else {
            0
        };
        ::mem::size_of::<sockcred2>() + ::mem::size_of::<::gid_t>() * ngrps
    }
}

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
    pub fn setproctitle_fast(fmt: *const ::c_char, ...);
    pub fn timingsafe_bcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
    pub fn timingsafe_memcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;

    pub fn cpuset_getdomain(
        level: ::cpulevel_t,
        which: ::cpuwhich_t,
        id: ::id_t,
        setsize: ::size_t,
        mask: *mut ::domainset_t,
        policy: *mut ::c_int,
    ) -> ::c_int;
    pub fn cpuset_setdomain(
        level: ::cpulevel_t,
        which: ::cpuwhich_t,
        id: ::id_t,
        setsize: ::size_t,
        mask: *const ::domainset_t,
        policy: ::c_int,
    ) -> ::c_int;
}

#[link(name = "kvm")]
extern "C" {
    pub fn kvm_kerndisp(kd: *mut ::kvm_t) -> ::kssize_t;
}

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

cfg_if! {
    if #[cfg(target_arch = "x86_64")] {
        mod x86_64;
        pub use self::x86_64::*;
    }
}
<commit_msg>freebsd 13 add copy_file_range api compatible with linux's glibc wrapper<commit_after>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;
pub type kpaddr_t = u64;
pub type kssize_t = i64;
pub type domainset_t = __c_anonymous_domainset;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }

    pub struct sockcred2 {
        pub sc_version: ::c_int,
        pub sc_pid: ::pid_t,
        pub sc_uid: ::uid_t,
        pub sc_euid: ::uid_t,
        pub sc_gid: ::gid_t,
        pub sc_egid: ::gid_t,
        pub sc_ngroups: ::c_int,
        pub sc_groups: [::gid_t; 1],
    }

    pub struct kvm_page {
        pub kp_version: ::u_int,
        pub kp_paddr: ::kpaddr_t,
        pub kp_kmap_vaddr: ::kvaddr_t,
        pub kp_dmap_vaddr: ::kvaddr_t,
        pub kp_prot: ::vm_prot_t,
        pub kp_offset: ::off_t,
        pub kp_len: ::size_t,
    }

    pub struct __c_anonymous_domainset {
        _priv: [::uintptr_t; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const RAND_MAX: ::c_int = 0x7fff_ffff;
pub const ELAST: ::c_int = 97;

pub const KF_TYPE_EVENTFD: ::c_int = 13;

/// max length of devicename
pub const SPECNAMELEN: ::c_int = 255;
pub const KI_NSPARE_PTR: usize = 5;

/// domainset policies
pub const DOMAINSET_POLICY_INVALID: ::c_int = 0;
pub const DOMAINSET_POLICY_ROUNDROBIN: ::c_int = 1;
pub const DOMAINSET_POLICY_FIRSTTOUCH: ::c_int = 2;
pub const DOMAINSET_POLICY_PREFER: ::c_int = 3;
pub const DOMAINSET_POLICY_INTERLEAVE: ::c_int = 4;

f! {
    pub fn SOCKCRED2SIZE(ngrps: usize) -> usize {
        let ngrps = if ngrps > 0 {
            ngrps - 1
        } else {
            0
        };
        ::mem::size_of::<sockcred2>() + ::mem::size_of::<::gid_t>() * ngrps
    }
}

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
    pub fn setproctitle_fast(fmt: *const ::c_char, ...);
    pub fn timingsafe_bcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
    pub fn timingsafe_memcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;

    pub fn cpuset_getdomain(
        level: ::cpulevel_t,
        which: ::cpuwhich_t,
        id: ::id_t,
        setsize: ::size_t,
        mask: *mut ::domainset_t,
        policy: *mut ::c_int,
    ) -> ::c_int;
    pub fn cpuset_setdomain(
        level: ::cpulevel_t,
        which: ::cpuwhich_t,
        id: ::id_t,
        setsize: ::size_t,
        mask: *const ::domainset_t,
        policy: ::c_int,
    ) -> ::c_int;

    pub fn copy_file_range(
        infd: ::c_int,
        inoffp: *mut ::off_t,
        outfd: ::c_int,
        outoffp: *mut ::off_t,
        len: ::size_t,
        flags: ::c_uint,
    ) -> ::ssize_t;
}

#[link(name = "kvm")]
extern "C" {
    pub fn kvm_kerndisp(kd: *mut ::kvm_t) -> ::kssize_t;
}

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

cfg_if! {
    if #[cfg(target_arch = "x86_64")] {
        mod x86_64;
        pub use self::x86_64::*;
    }
}
<|endoftext|>


<commit_before>use kay::{Actor, CDict, CVec, ID, Individual, Recipient, Fate, ActorSystem, Swarm};
use core::geometry::AnyShape;
use descartes::Band;
use super::{Lane, TransferLane, Interaction, InteractionKind, OverlapKind};

pub mod trip;

#[derive(Compact, Clone, Default)]
pub struct PathfindingInfo{
    pub as_destination: Option<Destination>,
    pub hops_from_landmark: u8,
    pub learned_landmark_from: Option<ID>,
    pub routes: CDict<Destination, RoutingInfo>,
    pub routes_changed: bool,
    pub tell_to_forget_next_tick: CVec<Destination>,
    pub query_routes_next_tick: bool,
    pub routing_timeout: u16
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Destination{
    pub landmark: ID,
    pub node: ID
}

impl Destination{
    fn landmark(landmark: ID) -> Self {Destination{landmark: landmark, node: landmark}}
    pub fn is_landmark(&self) -> bool {self.landmark == self.node}
    pub fn landmark_destination(&self) -> Self{Self::landmark(self.landmark)}
}

#[derive(Copy, Clone, Debug)]
pub struct RoutingInfo{
    pub outgoing_idx: u8,
    pub distance: f32,
    distance_hops: u8,
    learned_from: ID,
    fresh: bool
}

use ::core::ui::Add;

pub fn on_build(lane: &mut Lane) {
    lane.pathfinding_info.as_destination = None;
    ::core::ui::UserInterface::id() << Add::Interactable3d(lane.id(), AnyShape::Band(Band::new(lane.path.clone(), 3.0)), 5);
}

const MIN_LANDMARK_INCOMING : usize = 3;
const ROUTING_TIMEOUT_AFTER_CHANGE : u16 = 20;

pub fn tick(lane: &mut Lane) {
    if let Some(as_destination) = lane.pathfinding_info.as_destination {
        for successor in successors(lane) {
            successor << JoinLandmark{
                from: lane.id(),
                join_as: Destination{
                    landmark: as_destination.landmark,
                    node: successor
                },
                hops_from_landmark: lane.pathfinding_info.hops_from_landmark + 1
            }
        }
    } else if predecessors(lane).count() >= MIN_LANDMARK_INCOMING {
        lane.pathfinding_info = PathfindingInfo{
            as_destination: Some(Destination::landmark(lane.id())),
            hops_from_landmark: 0,
            learned_landmark_from: Some(lane.id()),
            routes: CDict::new(),
            routes_changed: true,
            query_routes_next_tick: false,
            tell_to_forget_next_tick: CVec::new(),
            routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE
        }
    }

    if lane.pathfinding_info.routing_timeout > 0 {
        lane.pathfinding_info.routing_timeout -= 1;
    } else {
        if lane.pathfinding_info.query_routes_next_tick {
            for successor in successors(lane) {
                successor << QueryRoutes{requester: lane.id(), is_transfer: false};
            }
            lane.pathfinding_info.query_routes_next_tick = false;
        }

        if !lane.pathfinding_info.tell_to_forget_next_tick.is_empty() {
            for (_, predecessor, _) in predecessors(lane) {
                predecessor << ForgetRoutes{
                    forget: lane.pathfinding_info.tell_to_forget_next_tick.clone(),
                    from: lane.id()
                }
            }
            lane.pathfinding_info.tell_to_forget_next_tick.clear();
        }

        if lane.pathfinding_info.routes_changed {
            for (_, predecessor, is_transfer) in predecessors(lane) {
                let self_cost = if is_transfer {0.0} else {lane.length};
                predecessor << ShareRoutes{
                    new_routes: lane.pathfinding_info.routes.pairs().filter_map(
                        |(&destination, &RoutingInfo{distance, distance_hops, ..})|
                        if true /*fresh*/ {Some((destination, (distance + self_cost, distance_hops + 1)))} else {None}
                    ).chain(lane.pathfinding_info.as_destination.map(|destination|
                        (destination, (self_cost, 0))
                    )).collect(),
                    from: lane.id()
                };
            }
            for routing_info in lane.pathfinding_info.routes.values_mut() {
                routing_info.fresh = false;
            }
            lane.pathfinding_info.routes_changed = false;
        }
    }
}

#[allow(needless_lifetimes)]
fn successors<'a>(lane: &'a Lane) -> impl Iterator<Item=ID> + 'a{
    lane.interactions.iter().filter_map(|interaction|
        match *interaction {
            Interaction{partner_lane, kind: InteractionKind::Overlap{kind: OverlapKind::Transfer, ..}, ..}
            | Interaction{partner_lane, kind: InteractionKind::Next{..}, ..} => {
                Some(partner_lane)
            },
            _ => None
        }
    )
}

#[allow(needless_lifetimes)]
fn predecessors<'a>(lane: &'a Lane) -> impl Iterator<Item=(u8, ID, bool)> + 'a{
    lane.interactions.iter().enumerate().filter_map(|(i, interaction)|
        match *interaction {
            Interaction{partner_lane, kind: InteractionKind::Overlap{kind: OverlapKind::Transfer, ..}, ..} => {
                Some((i as u8, partner_lane, true))
            },
            Interaction{partner_lane, kind: InteractionKind::Previous{..}, ..} => {
                Some((i as u8, partner_lane, false))
            },
            _ => None
        }
    )
}

#[derive(Copy, Clone)]
pub struct JoinLandmark{
    from: ID,
    join_as: Destination,
    hops_from_landmark: u8
}

const IDEAL_LANDMARK_RADIUS : u8 = 3;

impl Recipient<JoinLandmark> for Lane {
     fn receive(&mut self, msg: &JoinLandmark) -> Fate {match *msg{
         JoinLandmark{join_as, hops_from_landmark, from} => {
            let join = self.pathfinding_info.as_destination.map(|self_destination|
                join_as != self_destination && (
                    if self_destination.is_landmark() {
                        hops_from_landmark < IDEAL_LANDMARK_RADIUS
                        && join_as.landmark.instance_id < self.id().instance_id
                    } else {
                        hops_from_landmark < self.pathfinding_info.hops_from_landmark
                        || self.pathfinding_info.learned_landmark_from.map(|learned_from| learned_from == from).unwrap_or(false)
                    }
                )
            ).unwrap_or(true);
            if join {
                self.pathfinding_info = PathfindingInfo{
                    as_destination: Some(join_as),
                    learned_landmark_from: Some(from),
                    hops_from_landmark: hops_from_landmark,
                    routes: CDict::new(),
                    routes_changed: true,
                    query_routes_next_tick: true,
                    tell_to_forget_next_tick: self.pathfinding_info.routes.keys().cloned()
                        .chain(self.pathfinding_info.as_destination.into_iter()).collect(),
                    routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE
                };
            }
            Fate::Live
         }
     }}
}

impl Recipient<JoinLandmark> for TransferLane {
     fn receive(&mut self, msg: &JoinLandmark) -> Fate {match *msg{
         JoinLandmark{join_as, hops_from_landmark, from} => {
            self.other_side(from) << JoinLandmark{
                join_as: Destination{
                    landmark: join_as.landmark,
                    node: self.other_side(from)
                },
                hops_from_landmark: hops_from_landmark,
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub struct QueryRoutes{requester: ID, is_transfer: bool}

impl Recipient<QueryRoutes> for Lane {
    fn receive(&mut self, msg: &QueryRoutes) -> Fate {match *msg{
        QueryRoutes{requester, is_transfer} => {
            let self_cost = if is_transfer {0.0} else {self.length};
            requester << ShareRoutes{
                new_routes: self.pathfinding_info.routes.pairs().map(
                    |(&destination, &RoutingInfo{distance, distance_hops, ..})|
                    (destination, (distance + self_cost, distance_hops + 1))
                ).chain(self.pathfinding_info.as_destination.map(|destination|
                    (destination, (self_cost, 0))
                )).collect(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

impl Recipient<QueryRoutes> for TransferLane {
    fn receive(&mut self, msg: &QueryRoutes) -> Fate {match *msg{
        QueryRoutes{requester, ..} => {
            self.other_side(requester) << QueryRoutes{requester: self.id(), is_transfer: true};
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
pub struct ShareRoutes{
    new_routes: CDict<Destination, (f32, u8)>,
    from: ID
}

impl Recipient<ShareRoutes> for Lane {
    fn receive(&mut self, msg: &ShareRoutes) -> Fate {match *msg{
        ShareRoutes{ref new_routes, from} => {
            if let Some(from_interaction_idx) = self.interactions.iter().position(|interaction| interaction.partner_lane == from) {
                for (&destination, &(new_distance, new_distance_hops)) in new_routes.pairs() {
                    if destination.is_landmark() || new_distance_hops <= IDEAL_LANDMARK_RADIUS
                    || self.pathfinding_info.as_destination.map(
                        |self_destination| self_destination.landmark == destination.landmark
                    ).unwrap_or(false) {
                        let insert = self.pathfinding_info.routes.get_mru(destination).map(
                            |&RoutingInfo{distance, ..}| new_distance < distance
                        ).unwrap_or(true);
                        if insert {
                            self.pathfinding_info.routes.insert(destination, RoutingInfo{
                                distance: new_distance,
                                distance_hops: new_distance_hops,
                                outgoing_idx: from_interaction_idx as u8,
                                learned_from: from,
                                fresh: true
                            });
                            self.pathfinding_info.routes_changed = true;
                        }
                    }
                }
            } else {
                println!("{:?} not yet connected to {:?}", self.id(), from);
            }
            Fate::Live
        }
    }}
}

const LANE_CHANGE_COST_LEFT : f32 = 5.0;
const LANE_CHANGE_COST_RIGHT : f32 = 3.0;

impl Recipient<ShareRoutes> for TransferLane {
    fn receive(&mut self, msg: &ShareRoutes) -> Fate {match *msg{
        ShareRoutes{ref new_routes, from} => {
            self.other_side(from) << ShareRoutes{
                new_routes: new_routes.pairs().map(|(&destination, &(distance, hops))|
                    (destination, (distance + if from == self.left.expect("should have left").0 {
                        LANE_CHANGE_COST_RIGHT
                    } else {
                        LANE_CHANGE_COST_LEFT
                    }, hops))
                ).collect(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
pub struct ForgetRoutes{
    forget: CVec<Destination>,
    from: ID
}

impl Recipient<ForgetRoutes> for Lane {
    fn receive(&mut self, msg: &ForgetRoutes) -> Fate {match *msg{
        ForgetRoutes{ref forget, from} => {
            let mut forgotten = CVec::<Destination>::new();
            for destination_to_forget in forget.iter() {
                let forget = if let Some(routing_info) = self.pathfinding_info.routes.get(*destination_to_forget) {
                    routing_info.learned_from == from
                } else {false};
                if forget {
                    self.pathfinding_info.routes.remove(*destination_to_forget);
                    forgotten.push(*destination_to_forget);
                }
            }
            self.pathfinding_info.tell_to_forget_next_tick = forgotten;
            Fate::Live
        }
    }}
}

impl Recipient<ForgetRoutes> for TransferLane {
    fn receive(&mut self, msg: &ForgetRoutes) -> Fate {match *msg{
        ForgetRoutes{ref forget, from} => {
            self.other_side(from) << ForgetRoutes{
                forget: forget.clone(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub struct QueryAsDestination{requester: ID}
#[derive(Copy, Clone)]
pub struct TellAsDestination{id: ID, as_destination: Option<Destination>}

impl Recipient<QueryAsDestination> for Lane {
    fn receive(&mut self, msg: &QueryAsDestination) -> Fate {match *msg{
        QueryAsDestination{requester} => {
            requester << TellAsDestination{
                id: self.id(),
                as_destination: self.pathfinding_info.as_destination
            };
            Fate::Live
        }
    }}
}

use kay::ToRandom;

pub fn setup(system: &mut ActorSystem) {
    system.add_inbox::<JoinLandmark, Swarm<Lane>>();
    system.add_inbox::<JoinLandmark, Swarm<TransferLane>>();
    system.add_inbox::<QueryRoutes, Swarm<Lane>>();
    system.add_inbox::<QueryRoutes, Swarm<TransferLane>>();
    system.add_inbox::<ShareRoutes, Swarm<Lane>>();
    system.add_inbox::<ShareRoutes, Swarm<TransferLane>>();
    system.add_inbox::<ForgetRoutes, Swarm<Lane>>();
    system.add_inbox::<ForgetRoutes, Swarm<TransferLane>>();
    system.add_inbox::<QueryAsDestination, Swarm<Lane>>();
    system.add_inbox::<ToRandom<::core::ui::Event3d>, Swarm<Lane>>();

    trip::setup(system);
}<commit_msg>Disable existing Debug UI Elements representing lanes #20<commit_after>use kay::{Actor, CDict, CVec, ID, Individual, Recipient, Fate, ActorSystem, Swarm};
use core::geometry::AnyShape;
use descartes::Band;
use super::{Lane, TransferLane, Interaction, InteractionKind, OverlapKind};

pub mod trip;

#[derive(Compact, Clone, Default)]
pub struct PathfindingInfo{
    pub as_destination: Option<Destination>,
    pub hops_from_landmark: u8,
    pub learned_landmark_from: Option<ID>,
    pub routes: CDict<Destination, RoutingInfo>,
    pub routes_changed: bool,
    pub tell_to_forget_next_tick: CVec<Destination>,
    pub query_routes_next_tick: bool,
    pub routing_timeout: u16
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Destination{
    pub landmark: ID,
    pub node: ID
}

impl Destination{
    fn landmark(landmark: ID) -> Self {Destination{landmark: landmark, node: landmark}}
    pub fn is_landmark(&self) -> bool {self.landmark == self.node}
    pub fn landmark_destination(&self) -> Self{Self::landmark(self.landmark)}
}

#[derive(Copy, Clone, Debug)]
pub struct RoutingInfo{
    pub outgoing_idx: u8,
    pub distance: f32,
    distance_hops: u8,
    learned_from: ID,
    fresh: bool
}

use ::core::ui::Add;
const DEBUG_CARS_ON_LANES : bool  = false;

pub fn on_build(lane: &mut Lane) {
    lane.pathfinding_info.as_destination = None;
    if DEBUG_CARS_ON_LANES {
        ::core::ui::UserInterface::id() << Add::Interactable3d(lane.id(), AnyShape::Band(Band::new(lane.path.clone(), 3.0)), 5);
    }
}

const MIN_LANDMARK_INCOMING : usize = 3;
const ROUTING_TIMEOUT_AFTER_CHANGE : u16 = 20;

pub fn tick(lane: &mut Lane) {
    if let Some(as_destination) = lane.pathfinding_info.as_destination {
        for successor in successors(lane) {
            successor << JoinLandmark{
                from: lane.id(),
                join_as: Destination{
                    landmark: as_destination.landmark,
                    node: successor
                },
                hops_from_landmark: lane.pathfinding_info.hops_from_landmark + 1
            }
        }
    } else if predecessors(lane).count() >= MIN_LANDMARK_INCOMING {
        lane.pathfinding_info = PathfindingInfo{
            as_destination: Some(Destination::landmark(lane.id())),
            hops_from_landmark: 0,
            learned_landmark_from: Some(lane.id()),
            routes: CDict::new(),
            routes_changed: true,
            query_routes_next_tick: false,
            tell_to_forget_next_tick: CVec::new(),
            routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE
        }
    }

    if lane.pathfinding_info.routing_timeout > 0 {
        lane.pathfinding_info.routing_timeout -= 1;
    } else {
        if lane.pathfinding_info.query_routes_next_tick {
            for successor in successors(lane) {
                successor << QueryRoutes{requester: lane.id(), is_transfer: false};
            }
            lane.pathfinding_info.query_routes_next_tick = false;
        }

        if !lane.pathfinding_info.tell_to_forget_next_tick.is_empty() {
            for (_, predecessor, _) in predecessors(lane) {
                predecessor << ForgetRoutes{
                    forget: lane.pathfinding_info.tell_to_forget_next_tick.clone(),
                    from: lane.id()
                }
            }
            lane.pathfinding_info.tell_to_forget_next_tick.clear();
        }

        if lane.pathfinding_info.routes_changed {
            for (_, predecessor, is_transfer) in predecessors(lane) {
                let self_cost = if is_transfer {0.0} else {lane.length};
                predecessor << ShareRoutes{
                    new_routes: lane.pathfinding_info.routes.pairs().filter_map(
                        |(&destination, &RoutingInfo{distance, distance_hops, ..})|
                        if true /*fresh*/ {Some((destination, (distance + self_cost, distance_hops + 1)))} else {None}
                    ).chain(lane.pathfinding_info.as_destination.map(|destination|
                        (destination, (self_cost, 0))
                    )).collect(),
                    from: lane.id()
                };
            }
            for routing_info in lane.pathfinding_info.routes.values_mut() {
                routing_info.fresh = false;
            }
            lane.pathfinding_info.routes_changed = false;
        }
    }
}

#[allow(needless_lifetimes)]
fn successors<'a>(lane: &'a Lane) -> impl Iterator<Item=ID> + 'a{
    lane.interactions.iter().filter_map(|interaction|
        match *interaction {
            Interaction{partner_lane, kind: InteractionKind::Overlap{kind: OverlapKind::Transfer, ..}, ..}
            | Interaction{partner_lane, kind: InteractionKind::Next{..}, ..} => {
                Some(partner_lane)
            },
            _ => None
        }
    )
}

#[allow(needless_lifetimes)]
fn predecessors<'a>(lane: &'a Lane) -> impl Iterator<Item=(u8, ID, bool)> + 'a{
    lane.interactions.iter().enumerate().filter_map(|(i, interaction)|
        match *interaction {
            Interaction{partner_lane, kind: InteractionKind::Overlap{kind: OverlapKind::Transfer, ..}, ..} => {
                Some((i as u8, partner_lane, true))
            },
            Interaction{partner_lane, kind: InteractionKind::Previous{..}, ..} => {
                Some((i as u8, partner_lane, false))
            },
            _ => None
        }
    )
}

#[derive(Copy, Clone)]
pub struct JoinLandmark{
    from: ID,
    join_as: Destination,
    hops_from_landmark: u8
}

const IDEAL_LANDMARK_RADIUS : u8 = 3;

impl Recipient<JoinLandmark> for Lane {
     fn receive(&mut self, msg: &JoinLandmark) -> Fate {match *msg{
         JoinLandmark{join_as, hops_from_landmark, from} => {
            let join = self.pathfinding_info.as_destination.map(|self_destination|
                join_as != self_destination && (
                    if self_destination.is_landmark() {
                        hops_from_landmark < IDEAL_LANDMARK_RADIUS
                        && join_as.landmark.instance_id < self.id().instance_id
                    } else {
                        hops_from_landmark < self.pathfinding_info.hops_from_landmark
                        || self.pathfinding_info.learned_landmark_from.map(|learned_from| learned_from == from).unwrap_or(false)
                    }
                )
            ).unwrap_or(true);
            if join {
                self.pathfinding_info = PathfindingInfo{
                    as_destination: Some(join_as),
                    learned_landmark_from: Some(from),
                    hops_from_landmark: hops_from_landmark,
                    routes: CDict::new(),
                    routes_changed: true,
                    query_routes_next_tick: true,
                    tell_to_forget_next_tick: self.pathfinding_info.routes.keys().cloned()
                        .chain(self.pathfinding_info.as_destination.into_iter()).collect(),
                    routing_timeout: ROUTING_TIMEOUT_AFTER_CHANGE
                };
            }
            Fate::Live
         }
     }}
}

impl Recipient<JoinLandmark> for TransferLane {
     fn receive(&mut self, msg: &JoinLandmark) -> Fate {match *msg{
         JoinLandmark{join_as, hops_from_landmark, from} => {
            self.other_side(from) << JoinLandmark{
                join_as: Destination{
                    landmark: join_as.landmark,
                    node: self.other_side(from)
                },
                hops_from_landmark: hops_from_landmark,
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub struct QueryRoutes{requester: ID, is_transfer: bool}

impl Recipient<QueryRoutes> for Lane {
    fn receive(&mut self, msg: &QueryRoutes) -> Fate {match *msg{
        QueryRoutes{requester, is_transfer} => {
            let self_cost = if is_transfer {0.0} else {self.length};
            requester << ShareRoutes{
                new_routes: self.pathfinding_info.routes.pairs().map(
                    |(&destination, &RoutingInfo{distance, distance_hops, ..})|
                    (destination, (distance + self_cost, distance_hops + 1))
                ).chain(self.pathfinding_info.as_destination.map(|destination|
                    (destination, (self_cost, 0))
                )).collect(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

impl Recipient<QueryRoutes> for TransferLane {
    fn receive(&mut self, msg: &QueryRoutes) -> Fate {match *msg{
        QueryRoutes{requester, ..} => {
            self.other_side(requester) << QueryRoutes{requester: self.id(), is_transfer: true};
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
pub struct ShareRoutes{
    new_routes: CDict<Destination, (f32, u8)>,
    from: ID
}

impl Recipient<ShareRoutes> for Lane {
    fn receive(&mut self, msg: &ShareRoutes) -> Fate {match *msg{
        ShareRoutes{ref new_routes, from} => {
            if let Some(from_interaction_idx) = self.interactions.iter().position(|interaction| interaction.partner_lane == from) {
                for (&destination, &(new_distance, new_distance_hops)) in new_routes.pairs() {
                    if destination.is_landmark() || new_distance_hops <= IDEAL_LANDMARK_RADIUS
                    || self.pathfinding_info.as_destination.map(
                        |self_destination| self_destination.landmark == destination.landmark
                    ).unwrap_or(false) {
                        let insert = self.pathfinding_info.routes.get_mru(destination).map(
                            |&RoutingInfo{distance, ..}| new_distance < distance
                        ).unwrap_or(true);
                        if insert {
                            self.pathfinding_info.routes.insert(destination, RoutingInfo{
                                distance: new_distance,
                                distance_hops: new_distance_hops,
                                outgoing_idx: from_interaction_idx as u8,
                                learned_from: from,
                                fresh: true
                            });
                            self.pathfinding_info.routes_changed = true;
                        }
                    }
                }
            } else {
                println!("{:?} not yet connected to {:?}", self.id(), from);
            }
            Fate::Live
        }
    }}
}

const LANE_CHANGE_COST_LEFT : f32 = 5.0;
const LANE_CHANGE_COST_RIGHT : f32 = 3.0;

impl Recipient<ShareRoutes> for TransferLane {
    fn receive(&mut self, msg: &ShareRoutes) -> Fate {match *msg{
        ShareRoutes{ref new_routes, from} => {
            self.other_side(from) << ShareRoutes{
                new_routes: new_routes.pairs().map(|(&destination, &(distance, hops))|
                    (destination, (distance + if from == self.left.expect("should have left").0 {
                        LANE_CHANGE_COST_RIGHT
                    } else {
                        LANE_CHANGE_COST_LEFT
                    }, hops))
                ).collect(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Compact, Clone)]
pub struct ForgetRoutes{
    forget: CVec<Destination>,
    from: ID
}

impl Recipient<ForgetRoutes> for Lane {
    fn receive(&mut self, msg: &ForgetRoutes) -> Fate {match *msg{
        ForgetRoutes{ref forget, from} => {
            let mut forgotten = CVec::<Destination>::new();
            for destination_to_forget in forget.iter() {
                let forget = if let Some(routing_info) = self.pathfinding_info.routes.get(*destination_to_forget) {
                    routing_info.learned_from == from
                } else {false};
                if forget {
                    self.pathfinding_info.routes.remove(*destination_to_forget);
                    forgotten.push(*destination_to_forget);
                }
            }
            self.pathfinding_info.tell_to_forget_next_tick = forgotten;
            Fate::Live
        }
    }}
}

impl Recipient<ForgetRoutes> for TransferLane {
    fn receive(&mut self, msg: &ForgetRoutes) -> Fate {match *msg{
        ForgetRoutes{ref forget, from} => {
            self.other_side(from) << ForgetRoutes{
                forget: forget.clone(),
                from: self.id()
            };
            Fate::Live
        }
    }}
}

#[derive(Copy, Clone)]
pub struct QueryAsDestination{requester: ID}
#[derive(Copy, Clone)]
pub struct TellAsDestination{id: ID, as_destination: Option<Destination>}

impl Recipient<QueryAsDestination> for Lane {
    fn receive(&mut self, msg: &QueryAsDestination) -> Fate {match *msg{
        QueryAsDestination{requester} => {
            requester << TellAsDestination{
                id: self.id(),
                as_destination: self.pathfinding_info.as_destination
            };
            Fate::Live
        }
    }}
}

use kay::ToRandom;

pub fn setup(system: &mut ActorSystem) {
    system.add_inbox::<JoinLandmark, Swarm<Lane>>();
    system.add_inbox::<JoinLandmark, Swarm<TransferLane>>();
    system.add_inbox::<QueryRoutes, Swarm<Lane>>();
    system.add_inbox::<QueryRoutes, Swarm<TransferLane>>();
    system.add_inbox::<ShareRoutes, Swarm<Lane>>();
    system.add_inbox::<ShareRoutes, Swarm<TransferLane>>();
    system.add_inbox::<ForgetRoutes, Swarm<Lane>>();
    system.add_inbox::<ForgetRoutes, Swarm<TransferLane>>();
    system.add_inbox::<QueryAsDestination, Swarm<Lane>>();
    system.add_inbox::<ToRandom<::core::ui::Event3d>, Swarm<Lane>>();

    trip::setup(system);
}<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/99_Bottles_of_Beer
use std::string::String;

#[cfg(not(test))]
fn main() {
	for num_bottles in std::iter::range_step_inclusive(99, 1, -1) {
        let num_bottles=num_bottles as uint;

		println!("{}",bottles_line(num_bottles as uint, true));
		println!("{}",bottles_line(num_bottles as uint, false));
		println!("Take one down, pass it around...");
		println!("{}",bottles_line(num_bottles - 1, true).as_slice());
		println!("-----------------------------------");
	}
}

fn bottles_line(num_bottles: uint, on_the_wall: bool) -> String {
	// the format! macro uses a built in internationalization formatting language
	// check out the docs for std::fmt
	let mut ln=format!("{0, plural, =0{No bottles} =1{One bottle} other{# bottles}} of beer",
                                                                                num_bottles);

	if on_the_wall {
		ln.push_str(" on the wall!");
	}

	ln.push_str("\n");
    ln
}

#[test]
fn gen_bottle_line() {
    let ln=bottles_line(42, false);
    let ln2=bottles_line(42, true);

    assert_eq!(ln.as_slice(),"42 bottles of beer\n");
    assert_eq!(ln2.as_slice(),"42 bottles of beer on the wall!\n");
}
<commit_msg>removed redundant casts and as_slice()<commit_after>// Implements http://rosettacode.org/wiki/99_Bottles_of_Beer
use std::string::String;

#[cfg(not(test))]
fn main() {
	for num_bottles in std::iter::range_step_inclusive(99, 1, -1) {
        let num_bottles=num_bottles as uint;

		println!("{}",bottles_line(num_bottles, true));
		println!("{}",bottles_line(num_bottles, false));
		println!("Take one down, pass it around...");
		println!("{}",bottles_line(num_bottles - 1, true));
		println!("-----------------------------------");
	}
}

fn bottles_line(num_bottles: uint, on_the_wall: bool) -> String {
	// the format! macro uses a built in internationalization formatting language
	// check out the docs for std::fmt
	let mut ln=format!("{0, plural, =0{No bottles} =1{One bottle} other{# bottles}} of beer",
                                                                                num_bottles);

	if on_the_wall {
		ln.push_str(" on the wall!");
	}

	ln.push_str("\n");
    ln
}

#[test]
fn gen_bottle_line() {
    let ln=bottles_line(42, false);
    let ln2=bottles_line(42, true);

    assert_eq!(ln.as_slice(),"42 bottles of beer\n");
    assert_eq!(ln2.as_slice(),"42 bottles of beer on the wall!\n");
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::convert::From;

use std::io::Error as IOError;

#[derive(Clone, Copy, Debug)]
pub enum StoreErrorKind {
    IdNotFound,
    OutOfMemory,
    // maybe more
}

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::IdNotFound  => "ID not found",
        &StoreErrorKind::OutOfMemory => "Out of Memory",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            cause: cause,
        }
    }

    pub fn err_type(&self) -> StoreErrorKind {
        self.err_type.clone()
    }

}

impl Debug for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{:?}]: caused by: {:?}",
                    self.err_type, self.cause));
        Ok(())
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", store_error_type_as_str(&self.err_type.clone())));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<commit_msg>Derive Debug for StoreError<commit_after>use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::convert::From;

use std::io::Error as IOError;

#[derive(Clone, Copy, Debug)]
pub enum StoreErrorKind {
    IdNotFound,
    OutOfMemory,
    // maybe more
}

fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
    match e {
        &StoreErrorKind::IdNotFound  => "ID not found",
        &StoreErrorKind::OutOfMemory => "Out of Memory",
    }
}

impl Display for StoreErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", store_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct StoreError {
    err_type: StoreErrorKind,
    cause: Option<Box<Error>>,
}

impl StoreError {

    pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
        -> StoreError
    {
        StoreError {
            err_type: errtype,
            cause: cause,
        }
    }

    pub fn err_type(&self) -> StoreErrorKind {
        self.err_type.clone()
    }

}

impl Display for StoreError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", store_error_type_as_str(&self.err_type.clone())));
        Ok(())
    }

}

impl Error for StoreError {

    fn description(&self) -> &str {
        store_error_type_as_str(&self.err_type.clone())
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}

<|endoftext|>


<commit_before>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    CreateStoreDirDenied    => "Creating store directory implicitely denied",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    FileNotWritten          => "File corresponding to ID could not be written to",
    FileNotSeeked           => "File corresponding to ID could not be seeked",
    FileNotRemoved          => "File corresponding to ID could not be removed",
    FileNotRenamed          => "File corresponding to ID could not be renamed",
    FileNotCopied           => "File could not be copied",
    DirNotCreated           => "Directory/Directories could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",
    StoreIdHandlingError    => "StoreId handling error",
    StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed",
    StoreIdBuildFromFullPathError => "Building StoreId from full file path failed",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_result_helper!(StoreError, StoreErrorKind);
generate_option_helper!(StoreError, StoreErrorKind);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<commit_msg>Add error kind if StoreId has no base part<commit_after>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    CreateStoreDirDenied    => "Creating store directory implicitely denied",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    FileNotWritten          => "File corresponding to ID could not be written to",
    FileNotSeeked           => "File corresponding to ID could not be seeked",
    FileNotRemoved          => "File corresponding to ID could not be removed",
    FileNotRenamed          => "File corresponding to ID could not be renamed",
    FileNotCopied           => "File could not be copied",
    DirNotCreated           => "Directory/Directories could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",
    StoreIdHandlingError    => "StoreId handling error",
    StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed",
    StoreIdBuildFromFullPathError => "Building StoreId from full file path failed",
    StoreIdHasNoBaseError   => "StoreId has no 'base' part",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_result_helper!(StoreError, StoreErrorKind);
generate_option_helper!(StoreError, StoreErrorKind);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<|endoftext|>


<commit_before>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    ))
                )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    ))
                )),
                InstCell(ADD),
                InstCell(RTN)
            ))
        )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    ))
                )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    ))
                )),
                InstCell(ADD),
                InstCell(RTN)
            )),
            InstCell(AP)
        )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(2)),AtomCell(SInt(1))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(2))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(1))
                        ))
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RTN)
                ))
                InstCell(AP),
                InstCell(RTN)
            ))
            InstCell(AP)
        ))
    )
}<commit_msg>Fix misplaced parens in integration target<commit_after>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    )),
                InstCell(ADD),
                InstCell(RTN)
            ))
        ))
    )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(2))
                    ))
                )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(SInt(1)), AtomCell(SInt(1))
                    ))
                )),
                InstCell(ADD),
                InstCell(RTN)
            )),
            InstCell(AP)
        )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(2)),AtomCell(SInt(1))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(2))
                        ))
                    InstCell(LD), ListCell(box list!(
                        AtomCell(SInt(1)),AtomCell(SInt(1))
                        ))
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RTN)
                ))
                InstCell(AP),
                InstCell(RTN)
            ))
            InstCell(AP)
        ))
    )
}<|endoftext|>


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

//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
//!
//! `Lrc` is an alias of either Rc or Arc.
//!
//! `Lock` is a mutex.
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_queries) is true,
//! `RefCell` otherwise.
//!
//! `RwLock` is a read-write lock.
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true,
//! `RefCell` otherwise.
//!
//! `LockCell` is a thread safe version of `Cell`, with `set` and `get` operations.
//! It can never deadlock. It uses `Cell` when
//! cfg!(parallel_queries) is false, otherwise it is a `Lock`.
//!
//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false.
//!
//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
//! depending on the value of cfg!(parallel_queries).

use std::cmp::Ordering;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt;
use owning_ref::{Erased, OwningRef};

cfg_if! {
    if #[cfg(not(parallel_queries))] {
        pub auto trait Send {}
        pub auto trait Sync {}

        impl<T: ?Sized> Send for T {}
        impl<T: ?Sized> Sync for T {}

        #[macro_export]
        macro_rules! rustc_erase_owner {
            ($v:expr) => {
                $v.erase_owner()
            }
        }

        pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;

        pub use std::rc::Rc as Lrc;
        pub use std::cell::Ref as ReadGuard;
        pub use std::cell::RefMut as WriteGuard;
        pub use std::cell::RefMut as LockGuard;

        use std::cell::RefCell as InnerRwLock;
        use std::cell::RefCell as InnerLock;

        use std::cell::Cell;

        #[derive(Debug)]
        pub struct MTLock<T>(T);

        impl<T> MTLock<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                MTLock(inner)
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> &mut T {
                &mut self.0
            }

            #[inline(always)]
            pub fn lock(&self) -> &T {
                &self.0
            }

            #[inline(always)]
            pub fn borrow(&self) -> &T {
                &self.0
            }

            #[inline(always)]
            pub fn borrow_mut(&self) -> &T {
                &self.0
            }
        }

        // FIXME: Probably a bad idea (in the threaded case)
        impl<T: Clone> Clone for MTLock<T> {
            #[inline]
            fn clone(&self) -> Self {
                MTLock(self.0.clone())
            }
        }

        pub struct LockCell<T>(Cell<T>);

        impl<T> LockCell<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                LockCell(Cell::new(inner))
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0.into_inner()
            }

            #[inline(always)]
            pub fn set(&self, new_inner: T) {
                self.0.set(new_inner);
            }

            #[inline(always)]
            pub fn get(&self) -> T where T: Copy {
                self.0.get()
            }

            #[inline(always)]
            pub fn set_mut(&mut self, new_inner: T) {
                self.0.set(new_inner);
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> T where T: Copy {
                self.0.get()
            }
        }

        impl<T> LockCell<Option<T>> {
            #[inline(always)]
            pub fn take(&self) -> Option<T> {
                unsafe { (*self.0.as_ptr()).take() }
            }
        }
    } else {
        pub use std::marker::Send as Send;
        pub use std::marker::Sync as Sync;

        pub use parking_lot::RwLockReadGuard as ReadGuard;
        pub use parking_lot::RwLockWriteGuard as WriteGuard;

        pub use parking_lot::MutexGuard as LockGuard;

        pub use std::sync::Arc as Lrc;

        pub use self::Lock as MTLock;

        use parking_lot::Mutex as InnerLock;
        use parking_lot::RwLock as InnerRwLock;

        pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;

        /// This makes locks panic if they are already held.
        /// It is only useful when you are running in a single thread
        const ERROR_CHECKING: bool = false;

        #[macro_export]
        macro_rules! rustc_erase_owner {
            ($v:expr) => {{
                let v = $v;
                ::rustc_data_structures::sync::assert_send_val(&v);
                v.erase_send_sync_owner()
            }}
        }

        pub struct LockCell<T>(Lock<T>);

        impl<T> LockCell<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                LockCell(Lock::new(inner))
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0.into_inner()
            }

            #[inline(always)]
            pub fn set(&self, new_inner: T) {
                *self.0.lock() = new_inner;
            }

            #[inline(always)]
            pub fn get(&self) -> T where T: Copy {
                *self.0.lock()
            }

            #[inline(always)]
            pub fn set_mut(&mut self, new_inner: T) {
                *self.0.get_mut() = new_inner;
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> T where T: Copy {
                *self.0.get_mut()
            }
        }

        impl<T> LockCell<Option<T>> {
            #[inline(always)]
            pub fn take(&self) -> Option<T> {
                self.0.lock().take()
            }
        }
    }
}

pub fn assert_sync<T: ?Sized + Sync>() {}
pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {}
pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {}

impl<T: Copy + Debug> Debug for LockCell<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("LockCell")
            .field("value", &self.get())
            .finish()
    }
}

impl<T:Default> Default for LockCell<T> {
    /// Creates a `LockCell<T>`, with the `Default` value for T.
    #[inline]
    fn default() -> LockCell<T> {
        LockCell::new(Default::default())
    }
}

impl<T:PartialEq + Copy> PartialEq for LockCell<T> {
    #[inline]
    fn eq(&self, other: &LockCell<T>) -> bool {
        self.get() == other.get()
    }
}

impl<T:Eq + Copy> Eq for LockCell<T> {}

impl<T:PartialOrd + Copy> PartialOrd for LockCell<T> {
    #[inline]
    fn partial_cmp(&self, other: &LockCell<T>) -> Option<Ordering> {
        self.get().partial_cmp(&other.get())
    }

    #[inline]
    fn lt(&self, other: &LockCell<T>) -> bool {
        self.get() < other.get()
    }

    #[inline]
    fn le(&self, other: &LockCell<T>) -> bool {
        self.get() <= other.get()
    }

    #[inline]
    fn gt(&self, other: &LockCell<T>) -> bool {
        self.get() > other.get()
    }

    #[inline]
    fn ge(&self, other: &LockCell<T>) -> bool {
        self.get() >= other.get()
    }
}

impl<T:Ord + Copy> Ord for LockCell<T> {
    #[inline]
    fn cmp(&self, other: &LockCell<T>) -> Ordering {
        self.get().cmp(&other.get())
    }
}

#[derive(Debug)]
pub struct Lock<T>(InnerLock<T>);

impl<T> Lock<T> {
    #[inline(always)]
    pub fn new(inner: T) -> Self {
        Lock(InnerLock::new(inner))
    }

    #[inline(always)]
    pub fn into_inner(self) -> T {
        self.0.into_inner()
    }

    #[inline(always)]
    pub fn get_mut(&mut self) -> &mut T {
        self.0.get_mut()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn lock(&self) -> LockGuard<T> {
        if ERROR_CHECKING {
            self.0.try_lock().expect("lock was already held")
        } else {
            self.0.lock()
        }
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn lock(&self) -> LockGuard<T> {
        self.0.borrow_mut()
    }

    #[inline(always)]
    pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
        f(&mut *self.lock())
    }

    #[inline(always)]
    pub fn borrow(&self) -> LockGuard<T> {
        self.lock()
    }

    #[inline(always)]
    pub fn borrow_mut(&self) -> LockGuard<T> {
        self.lock()
    }
}

impl<T: Default> Default for Lock<T> {
    #[inline]
    fn default() -> Self {
        Lock::new(T::default())
    }
}

// FIXME: Probably a bad idea
impl<T: Clone> Clone for Lock<T> {
    #[inline]
    fn clone(&self) -> Self {
        Lock::new(self.borrow().clone())
    }
}

#[derive(Debug)]
pub struct RwLock<T>(InnerRwLock<T>);

impl<T> RwLock<T> {
    #[inline(always)]
    pub fn new(inner: T) -> Self {
        RwLock(InnerRwLock::new(inner))
    }

    #[inline(always)]
    pub fn into_inner(self) -> T {
        self.0.into_inner()
    }

    #[inline(always)]
    pub fn get_mut(&mut self) -> &mut T {
        self.0.get_mut()
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn read(&self) -> ReadGuard<T> {
        self.0.borrow()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn read(&self) -> ReadGuard<T> {
        if ERROR_CHECKING {
            self.0.try_read().expect("lock was already held")
        } else {
            self.0.read()
        }
    }

    #[inline(always)]
    pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
        f(&*self.read())
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn try_write(&self) -> Result<WriteGuard<T>, ()> {
        self.0.try_borrow_mut().map_err(|_| ())
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn try_write(&self) -> Result<WriteGuard<T>, ()> {
        self.0.try_write().ok_or(())
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn write(&self) -> WriteGuard<T> {
        self.0.borrow_mut()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn write(&self) -> WriteGuard<T> {
        if ERROR_CHECKING {
            self.0.try_write().expect("lock was already held")
        } else {
            self.0.write()
        }
    }

    #[inline(always)]
    pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
        f(&mut *self.write())
    }

    #[inline(always)]
    pub fn borrow(&self) -> ReadGuard<T> {
        self.read()
    }

    #[inline(always)]
    pub fn borrow_mut(&self) -> WriteGuard<T> {
        self.write()
    }
}

// FIXME: Probably a bad idea
impl<T: Clone> Clone for RwLock<T> {
    #[inline]
    fn clone(&self) -> Self {
        RwLock::new(self.borrow().clone())
    }
}
<commit_msg>Add OneThread which only allows its inner value to be used in one thread<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
//!
//! `Lrc` is an alias of either Rc or Arc.
//!
//! `Lock` is a mutex.
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_queries) is true,
//! `RefCell` otherwise.
//!
//! `RwLock` is a read-write lock.
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true,
//! `RefCell` otherwise.
//!
//! `LockCell` is a thread safe version of `Cell`, with `set` and `get` operations.
//! It can never deadlock. It uses `Cell` when
//! cfg!(parallel_queries) is false, otherwise it is a `Lock`.
//!
//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false.
//!
//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
//! depending on the value of cfg!(parallel_queries).

use std::cmp::Ordering;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt;
use std;
use std::ops::{Deref, DerefMut};
use owning_ref::{Erased, OwningRef};

cfg_if! {
    if #[cfg(not(parallel_queries))] {
        pub auto trait Send {}
        pub auto trait Sync {}

        impl<T: ?Sized> Send for T {}
        impl<T: ?Sized> Sync for T {}

        #[macro_export]
        macro_rules! rustc_erase_owner {
            ($v:expr) => {
                $v.erase_owner()
            }
        }

        pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;

        pub use std::rc::Rc as Lrc;
        pub use std::cell::Ref as ReadGuard;
        pub use std::cell::RefMut as WriteGuard;
        pub use std::cell::RefMut as LockGuard;

        use std::cell::RefCell as InnerRwLock;
        use std::cell::RefCell as InnerLock;

        use std::cell::Cell;

        #[derive(Debug)]
        pub struct MTLock<T>(T);

        impl<T> MTLock<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                MTLock(inner)
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> &mut T {
                &mut self.0
            }

            #[inline(always)]
            pub fn lock(&self) -> &T {
                &self.0
            }

            #[inline(always)]
            pub fn borrow(&self) -> &T {
                &self.0
            }

            #[inline(always)]
            pub fn borrow_mut(&self) -> &T {
                &self.0
            }
        }

        // FIXME: Probably a bad idea (in the threaded case)
        impl<T: Clone> Clone for MTLock<T> {
            #[inline]
            fn clone(&self) -> Self {
                MTLock(self.0.clone())
            }
        }

        pub struct LockCell<T>(Cell<T>);

        impl<T> LockCell<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                LockCell(Cell::new(inner))
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0.into_inner()
            }

            #[inline(always)]
            pub fn set(&self, new_inner: T) {
                self.0.set(new_inner);
            }

            #[inline(always)]
            pub fn get(&self) -> T where T: Copy {
                self.0.get()
            }

            #[inline(always)]
            pub fn set_mut(&mut self, new_inner: T) {
                self.0.set(new_inner);
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> T where T: Copy {
                self.0.get()
            }
        }

        impl<T> LockCell<Option<T>> {
            #[inline(always)]
            pub fn take(&self) -> Option<T> {
                unsafe { (*self.0.as_ptr()).take() }
            }
        }
    } else {
        pub use std::marker::Send as Send;
        pub use std::marker::Sync as Sync;

        pub use parking_lot::RwLockReadGuard as ReadGuard;
        pub use parking_lot::RwLockWriteGuard as WriteGuard;

        pub use parking_lot::MutexGuard as LockGuard;

        pub use std::sync::Arc as Lrc;

        pub use self::Lock as MTLock;

        use parking_lot::Mutex as InnerLock;
        use parking_lot::RwLock as InnerRwLock;

        use std::thread;

        pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;

        /// This makes locks panic if they are already held.
        /// It is only useful when you are running in a single thread
        const ERROR_CHECKING: bool = false;

        #[macro_export]
        macro_rules! rustc_erase_owner {
            ($v:expr) => {{
                let v = $v;
                ::rustc_data_structures::sync::assert_send_val(&v);
                v.erase_send_sync_owner()
            }}
        }

        pub struct LockCell<T>(Lock<T>);

        impl<T> LockCell<T> {
            #[inline(always)]
            pub fn new(inner: T) -> Self {
                LockCell(Lock::new(inner))
            }

            #[inline(always)]
            pub fn into_inner(self) -> T {
                self.0.into_inner()
            }

            #[inline(always)]
            pub fn set(&self, new_inner: T) {
                *self.0.lock() = new_inner;
            }

            #[inline(always)]
            pub fn get(&self) -> T where T: Copy {
                *self.0.lock()
            }

            #[inline(always)]
            pub fn set_mut(&mut self, new_inner: T) {
                *self.0.get_mut() = new_inner;
            }

            #[inline(always)]
            pub fn get_mut(&mut self) -> T where T: Copy {
                *self.0.get_mut()
            }
        }

        impl<T> LockCell<Option<T>> {
            #[inline(always)]
            pub fn take(&self) -> Option<T> {
                self.0.lock().take()
            }
        }
    }
}

pub fn assert_sync<T: ?Sized + Sync>() {}
pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {}
pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {}

impl<T: Copy + Debug> Debug for LockCell<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("LockCell")
            .field("value", &self.get())
            .finish()
    }
}

impl<T:Default> Default for LockCell<T> {
    /// Creates a `LockCell<T>`, with the `Default` value for T.
    #[inline]
    fn default() -> LockCell<T> {
        LockCell::new(Default::default())
    }
}

impl<T:PartialEq + Copy> PartialEq for LockCell<T> {
    #[inline]
    fn eq(&self, other: &LockCell<T>) -> bool {
        self.get() == other.get()
    }
}

impl<T:Eq + Copy> Eq for LockCell<T> {}

impl<T:PartialOrd + Copy> PartialOrd for LockCell<T> {
    #[inline]
    fn partial_cmp(&self, other: &LockCell<T>) -> Option<Ordering> {
        self.get().partial_cmp(&other.get())
    }

    #[inline]
    fn lt(&self, other: &LockCell<T>) -> bool {
        self.get() < other.get()
    }

    #[inline]
    fn le(&self, other: &LockCell<T>) -> bool {
        self.get() <= other.get()
    }

    #[inline]
    fn gt(&self, other: &LockCell<T>) -> bool {
        self.get() > other.get()
    }

    #[inline]
    fn ge(&self, other: &LockCell<T>) -> bool {
        self.get() >= other.get()
    }
}

impl<T:Ord + Copy> Ord for LockCell<T> {
    #[inline]
    fn cmp(&self, other: &LockCell<T>) -> Ordering {
        self.get().cmp(&other.get())
    }
}

#[derive(Debug)]
pub struct Lock<T>(InnerLock<T>);

impl<T> Lock<T> {
    #[inline(always)]
    pub fn new(inner: T) -> Self {
        Lock(InnerLock::new(inner))
    }

    #[inline(always)]
    pub fn into_inner(self) -> T {
        self.0.into_inner()
    }

    #[inline(always)]
    pub fn get_mut(&mut self) -> &mut T {
        self.0.get_mut()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn lock(&self) -> LockGuard<T> {
        if ERROR_CHECKING {
            self.0.try_lock().expect("lock was already held")
        } else {
            self.0.lock()
        }
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn lock(&self) -> LockGuard<T> {
        self.0.borrow_mut()
    }

    #[inline(always)]
    pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
        f(&mut *self.lock())
    }

    #[inline(always)]
    pub fn borrow(&self) -> LockGuard<T> {
        self.lock()
    }

    #[inline(always)]
    pub fn borrow_mut(&self) -> LockGuard<T> {
        self.lock()
    }
}

impl<T: Default> Default for Lock<T> {
    #[inline]
    fn default() -> Self {
        Lock::new(T::default())
    }
}

// FIXME: Probably a bad idea
impl<T: Clone> Clone for Lock<T> {
    #[inline]
    fn clone(&self) -> Self {
        Lock::new(self.borrow().clone())
    }
}

#[derive(Debug)]
pub struct RwLock<T>(InnerRwLock<T>);

impl<T> RwLock<T> {
    #[inline(always)]
    pub fn new(inner: T) -> Self {
        RwLock(InnerRwLock::new(inner))
    }

    #[inline(always)]
    pub fn into_inner(self) -> T {
        self.0.into_inner()
    }

    #[inline(always)]
    pub fn get_mut(&mut self) -> &mut T {
        self.0.get_mut()
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn read(&self) -> ReadGuard<T> {
        self.0.borrow()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn read(&self) -> ReadGuard<T> {
        if ERROR_CHECKING {
            self.0.try_read().expect("lock was already held")
        } else {
            self.0.read()
        }
    }

    #[inline(always)]
    pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
        f(&*self.read())
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn try_write(&self) -> Result<WriteGuard<T>, ()> {
        self.0.try_borrow_mut().map_err(|_| ())
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn try_write(&self) -> Result<WriteGuard<T>, ()> {
        self.0.try_write().ok_or(())
    }

    #[cfg(not(parallel_queries))]
    #[inline(always)]
    pub fn write(&self) -> WriteGuard<T> {
        self.0.borrow_mut()
    }

    #[cfg(parallel_queries)]
    #[inline(always)]
    pub fn write(&self) -> WriteGuard<T> {
        if ERROR_CHECKING {
            self.0.try_write().expect("lock was already held")
        } else {
            self.0.write()
        }
    }

    #[inline(always)]
    pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
        f(&mut *self.write())
    }

    #[inline(always)]
    pub fn borrow(&self) -> ReadGuard<T> {
        self.read()
    }

    #[inline(always)]
    pub fn borrow_mut(&self) -> WriteGuard<T> {
        self.write()
    }
}

// FIXME: Probably a bad idea
impl<T: Clone> Clone for RwLock<T> {
    #[inline]
    fn clone(&self) -> Self {
        RwLock::new(self.borrow().clone())
    }
}

/// A type which only allows its inner value to be used in one thread.
/// It will panic if it is used on multiple threads.
#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
pub struct OneThread<T> {
    #[cfg(parallel_queries)]
    thread: thread::ThreadId,
    inner: T,
}

unsafe impl<T> std::marker::Sync for OneThread<T> {}
unsafe impl<T> std::marker::Send for OneThread<T> {}

impl<T> OneThread<T> {
    #[inline(always)]
    fn check(&self) {
        #[cfg(parallel_queries)]
        assert_eq!(thread::current().id(), self.thread);
    }

    #[inline(always)]
    pub fn new(inner: T) -> Self {
        OneThread {
            #[cfg(parallel_queries)]
            thread: thread::current().id(),
            inner,
        }
    }

    #[inline(always)]
    pub fn into_inner(value: Self) -> T {
        value.check();
        value.inner
    }
}

impl<T> Deref for OneThread<T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.check();
        &self.inner
    }
}

impl<T> DerefMut for OneThread<T> {
    fn deref_mut(&mut self) -> &mut T {
        self.check();
        &mut self.inner
    }
}
<|endoftext|>