<commit_before>use crossbeam_queue::SegQueue;
use latch::Latch;
use std::any::Any;
use std::cell::UnsafeCell;
use std::mem;
use unwind;

pub(super) enum JobResult<T> {
    None,
    Ok(T),
    Panic(Box<Any + Send>),
}

/// A `Job` is used to advertise work for other threads that they may
/// want to steal. In accordance with time honored tradition, jobs are
/// arranged in a deque, so that thieves can take from the top of the
/// deque while the main worker manages the bottom of the deque. This
/// deque is managed by the `thread_pool` module.
pub(super) trait Job {
    /// Unsafe: this may be called from a different thread than the one
    /// which scheduled the job, so the implementer must ensure the
    /// appropriate traits are met, whether `Send`, `Sync`, or both.
    unsafe fn execute(this: *const Self);
}

/// Effectively a Job trait object. Each JobRef **must** be executed
/// exactly once, or else data may leak.
///
/// Internally, we store the job's data in a `*const ()` pointer.  The
/// true type is something like `*const StackJob<...>`, but we hide
/// it. We also carry the "execute fn" from the `Job` trait.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) struct JobRef {
    pointer: *const (),
    execute_fn: unsafe fn(*const ()),
}

unsafe impl Send for JobRef {}
unsafe impl Sync for JobRef {}

impl JobRef {
    /// Unsafe: caller asserts that `data` will remain valid until the
    /// job is executed.
    pub(super) unsafe fn new<T>(data: *const T) -> JobRef
    where
        T: Job,
    {
        let fn_ptr: unsafe fn(*const T) = <T as Job>::execute;

        // erase types:
        JobRef {
            pointer: data as *const (),
            execute_fn: mem::transmute(fn_ptr),
        }
    }

    #[inline]
    pub(super) unsafe fn execute(&self) {
        (self.execute_fn)(self.pointer)
    }
}

/// A job that will be owned by a stack slot. This means that when it
/// executes it need not free any heap data, the cleanup occurs when
/// the stack frame is later popped.  The function parameter indicates
/// `true` if the job was stolen -- executed on a different thread.
pub(super) struct StackJob<'a, L, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    pub(super) latch: &'a mut L,
    func: UnsafeCell<Option<F>>,
    result: UnsafeCell<JobResult<R>>,
}

impl<'a, L, F, R> StackJob<'a, L, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    pub(super) fn new(func: F, latch: &'a mut L) -> StackJob<'a, L, F, R> {
        StackJob {
            latch,
            func: UnsafeCell::new(Some(func)),
            result: UnsafeCell::new(JobResult::None),
        }
    }

    pub(super) unsafe fn as_job_ref(&self) -> JobRef {
        JobRef::new(self)
    }

    pub(super) unsafe fn run_inline(self, stolen: bool) -> R {
        self.func.into_inner().unwrap()(stolen)
    }

    pub(super) unsafe fn into_result(self) -> R {
        self.result.into_inner().into_return_value()
    }
}

impl<'a, L, F, R> Job for StackJob<'a, L, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    unsafe fn execute(this: *const Self) {
        let this = &*this;
        let abort = unwind::AbortIfPanic;
        let func = (*this.func.get()).take().unwrap();
        (*this.result.get()) = match unwind::halt_unwinding(|| func(true)) {
            Ok(x) => JobResult::Ok(x),
            Err(x) => JobResult::Panic(x),
        };
        this.latch.set();
        mem::forget(abort);
    }
}

/// Represents a job stored in the heap. Used to implement
/// `scope`. Unlike `StackJob`, when executed, `HeapJob` simply
/// invokes a closure, which then triggers the appropriate logic to
/// signal that the job executed.
///
/// (Probably `StackJob` should be refactored in a similar fashion.)
pub(super) struct HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    job: UnsafeCell<Option<BODY>>,
}

impl<BODY> HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    pub(super) fn new(func: BODY) -> Self {
        HeapJob {
            job: UnsafeCell::new(Some(func)),
        }
    }

    /// Creates a `JobRef` from this job -- note that this hides all
    /// lifetimes, so it is up to you to ensure that this JobRef
    /// doesn't outlive any data that it closes over.
    pub(super) unsafe fn as_job_ref(self: Box<Self>) -> JobRef {
        let this: *const Self = mem::transmute(self);
        JobRef::new(this)
    }
}

impl<BODY> Job for HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    unsafe fn execute(this: *const Self) {
        let this: Box<Self> = mem::transmute(this);
        let job = (*this.job.get()).take().unwrap();
        job();
    }
}

impl<T> JobResult<T> {
    /// Convert the `JobResult` for a job that has finished (and hence
    /// its JobResult is populated) into its return value.
    ///
    /// NB. This will panic if the job panicked.
    pub(super) fn into_return_value(self) -> T {
        match self {
            JobResult::None => unreachable!(),
            JobResult::Ok(x) => x,
            JobResult::Panic(x) => unwind::resume_unwinding(x),
        }
    }
}

/// Indirect queue to provide FIFO job priority.
pub(super) struct JobFifo {
    inner: SegQueue<JobRef>,
}

impl JobFifo {
    pub(super) fn new() -> Self {
        JobFifo {
            inner: SegQueue::new(),
        }
    }

    pub(super) unsafe fn push(&self, job_ref: JobRef) -> JobRef {
        // A little indirection ensures that spawns are always prioritized in FIFO order.  The
        // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front
        // (FIFO), but either way they will end up popping from the front of this queue.
        self.inner.push(job_ref);
        JobRef::new(self)
    }
}

impl Job for JobFifo {
    unsafe fn execute(this: *const Self) {
        // We "execute" a queue by executing its first job, FIFO.
        (*this).inner.pop().expect("job in fifo queue").execute()
    }
}
<commit_msg>Added lifetime bound.<commit_after>use crossbeam_queue::SegQueue;
use latch::Latch;
use std::any::Any;
use std::cell::UnsafeCell;
use std::mem;
use unwind;

pub(super) enum JobResult<T> {
    None,
    Ok(T),
    Panic(Box<Any + Send>),
}

/// A `Job` is used to advertise work for other threads that they may
/// want to steal. In accordance with time honored tradition, jobs are
/// arranged in a deque, so that thieves can take from the top of the
/// deque while the main worker manages the bottom of the deque. This
/// deque is managed by the `thread_pool` module.
pub(super) trait Job {
    /// Unsafe: this may be called from a different thread than the one
    /// which scheduled the job, so the implementer must ensure the
    /// appropriate traits are met, whether `Send`, `Sync`, or both.
    unsafe fn execute(this: *const Self);
}

/// Effectively a Job trait object. Each JobRef **must** be executed
/// exactly once, or else data may leak.
///
/// Internally, we store the job's data in a `*const ()` pointer.  The
/// true type is something like `*const StackJob<...>`, but we hide
/// it. We also carry the "execute fn" from the `Job` trait.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) struct JobRef {
    pointer: *const (),
    execute_fn: unsafe fn(*const ()),
}

unsafe impl Send for JobRef {}
unsafe impl Sync for JobRef {}

impl JobRef {
    /// Unsafe: caller asserts that `data` will remain valid until the
    /// job is executed.
    pub(super) unsafe fn new<T>(data: *const T) -> JobRef
    where
        T: Job,
    {
        let fn_ptr: unsafe fn(*const T) = <T as Job>::execute;

        // erase types:
        JobRef {
            pointer: data as *const (),
            execute_fn: mem::transmute(fn_ptr),
        }
    }

    #[inline]
    pub(super) unsafe fn execute(&self) {
        (self.execute_fn)(self.pointer)
    }
}

/// A job that will be owned by a stack slot. This means that when it
/// executes it need not free any heap data, the cleanup occurs when
/// the stack frame is later popped.  The function parameter indicates
/// `true` if the job was stolen -- executed on a different thread.
pub(super) struct StackJob<'a, L: 'a, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    pub(super) latch: &'a mut L,
    func: UnsafeCell<Option<F>>,
    result: UnsafeCell<JobResult<R>>,
}

impl<'a, L, F, R> StackJob<'a, L, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    pub(super) fn new(func: F, latch: &'a mut L) -> StackJob<'a, L, F, R> {
        StackJob {
            latch,
            func: UnsafeCell::new(Some(func)),
            result: UnsafeCell::new(JobResult::None),
        }
    }

    pub(super) unsafe fn as_job_ref(&self) -> JobRef {
        JobRef::new(self)
    }

    pub(super) unsafe fn run_inline(self, stolen: bool) -> R {
        self.func.into_inner().unwrap()(stolen)
    }

    pub(super) unsafe fn into_result(self) -> R {
        self.result.into_inner().into_return_value()
    }
}

impl<'a, L, F, R> Job for StackJob<'a, L, F, R>
where
    L: Latch + Sync,
    F: FnOnce(bool) -> R + Send,
    R: Send,
{
    unsafe fn execute(this: *const Self) {
        let this = &*this;
        let abort = unwind::AbortIfPanic;
        let func = (*this.func.get()).take().unwrap();
        (*this.result.get()) = match unwind::halt_unwinding(|| func(true)) {
            Ok(x) => JobResult::Ok(x),
            Err(x) => JobResult::Panic(x),
        };
        this.latch.set();
        mem::forget(abort);
    }
}

/// Represents a job stored in the heap. Used to implement
/// `scope`. Unlike `StackJob`, when executed, `HeapJob` simply
/// invokes a closure, which then triggers the appropriate logic to
/// signal that the job executed.
///
/// (Probably `StackJob` should be refactored in a similar fashion.)
pub(super) struct HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    job: UnsafeCell<Option<BODY>>,
}

impl<BODY> HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    pub(super) fn new(func: BODY) -> Self {
        HeapJob {
            job: UnsafeCell::new(Some(func)),
        }
    }

    /// Creates a `JobRef` from this job -- note that this hides all
    /// lifetimes, so it is up to you to ensure that this JobRef
    /// doesn't outlive any data that it closes over.
    pub(super) unsafe fn as_job_ref(self: Box<Self>) -> JobRef {
        let this: *const Self = mem::transmute(self);
        JobRef::new(this)
    }
}

impl<BODY> Job for HeapJob<BODY>
where
    BODY: FnOnce() + Send,
{
    unsafe fn execute(this: *const Self) {
        let this: Box<Self> = mem::transmute(this);
        let job = (*this.job.get()).take().unwrap();
        job();
    }
}

impl<T> JobResult<T> {
    /// Convert the `JobResult` for a job that has finished (and hence
    /// its JobResult is populated) into its return value.
    ///
    /// NB. This will panic if the job panicked.
    pub(super) fn into_return_value(self) -> T {
        match self {
            JobResult::None => unreachable!(),
            JobResult::Ok(x) => x,
            JobResult::Panic(x) => unwind::resume_unwinding(x),
        }
    }
}

/// Indirect queue to provide FIFO job priority.
pub(super) struct JobFifo {
    inner: SegQueue<JobRef>,
}

impl JobFifo {
    pub(super) fn new() -> Self {
        JobFifo {
            inner: SegQueue::new(),
        }
    }

    pub(super) unsafe fn push(&self, job_ref: JobRef) -> JobRef {
        // A little indirection ensures that spawns are always prioritized in FIFO order.  The
        // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front
        // (FIFO), but either way they will end up popping from the front of this queue.
        self.inner.push(job_ref);
        JobRef::new(self)
    }
}

impl Job for JobFifo {
    unsafe fn execute(this: *const Self) {
        // We "execute" a queue by executing its first job, FIFO.
        (*this).inner.pop().expect("job in fifo queue").execute()
    }
}
<|endoftext|>


<commit_before>s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    #[repr(align(16))]
    pub struct max_align_t {
        priv_: [f32; 8]
    }
}

s! {
    pub struct ucontext_t {
        pub uc_flags: ::c_ulong,
        pub uc_link: *mut ucontext_t,
        pub uc_stack: ::stack_t,
        pub uc_sigmask: ::sigset_t,
        pub uc_mcontext: mcontext_t,
    }

    #[repr(align(16))]
    pub struct mcontext_t {
        pub fault_address: ::c_ulonglong,
        pub regs: [::c_ulonglong; 31],
        pub sp: ::c_ulonglong,
        pub pc: ::c_ulonglong,
        pub pstate: ::c_ulonglong,
        // nested arrays to get the right size/length while being able to
        // auto-derive traits like Debug
        __reserved: [[u64; 32]; 16],
    }

    #[repr(align(16))]
    pub struct user_fpsimd_struct {
        pub vregs: [[u64; 2]; 32],
        pub fpsr: ::c_uint,
        pub fpcr: ::c_uint,
    }

    #[repr(align(8))]
    pub struct clone_args {
        pub flags: ::c_ulonglong,
        pub pidfd: ::c_ulonglong,
        pub child_tid: ::c_ulonglong,
        pub parent_tid: ::c_ulonglong,
        pub exit_signal: ::c_ulonglong,
        pub stack: ::c_ulonglong,
        pub stack_size: ::c_ulonglong,
        pub tls: ::c_ulonglong,
        pub set_tid: ::c_ulonglong,
        pub set_tid_size: ::c_ulonglong,
        pub cgroup: ::c_ulonglong,
    }
}
<commit_msg>Auto merge of #3001 - dtolnay-contrib:aarch64, r=JohnTitor<commit_after>s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    #[repr(align(16))]
    pub struct max_align_t {
        priv_: [f32; 8]
    }
}

s! {
    pub struct ucontext_t {
        pub uc_flags: ::c_ulong,
        pub uc_link: *mut ucontext_t,
        pub uc_stack: ::stack_t,
        pub uc_sigmask: ::sigset_t,
        pub uc_mcontext: mcontext_t,
    }

    #[repr(align(16))]
    pub struct mcontext_t {
        pub fault_address: ::c_ulonglong,
        pub regs: [::c_ulonglong; 31],
        pub sp: ::c_ulonglong,
        pub pc: ::c_ulonglong,
        pub pstate: ::c_ulonglong,
        // nested arrays to get the right size/length while being able to
        // auto-derive traits like Debug
        __reserved: [[u64; 32]; 16],
    }

    #[repr(align(16))]
    pub struct user_fpsimd_struct {
        pub vregs: [[u64; 2]; 32],
        pub fpsr: ::c_uint,
        pub fpcr: ::c_uint,
    }

    #[repr(align(8))]
    pub struct clone_args {
        pub flags: ::c_ulonglong,
        pub pidfd: ::c_ulonglong,
        pub child_tid: ::c_ulonglong,
        pub parent_tid: ::c_ulonglong,
        pub exit_signal: ::c_ulonglong,
        pub stack: ::c_ulonglong,
        pub stack_size: ::c_ulonglong,
        pub tls: ::c_ulonglong,
        pub set_tid: ::c_ulonglong,
        pub set_tid_size: ::c_ulonglong,
        pub cgroup: ::c_ulonglong,
    }
}

extern "C" {
    pub fn getcontext(ucp: *mut ucontext_t) -> ::c_int;
    pub fn setcontext(ucp: *const ucontext_t) -> ::c_int;
    pub fn makecontext(ucp: *mut ucontext_t, func: extern "C" fn(), argc: ::c_int, ...);
    pub fn swapcontext(uocp: *mut ucontext_t, ucp: *const ucontext_t) -> ::c_int;
}
<|endoftext|>


<commit_before>use libimagstore::store::EntryHeader;

use error::{LinkError, LinkErrorKind};
use link::{Link, Links};
use result::Result;

pub fn get_links(header: &EntryHeader) -> Result<Links> {
    unimplemented!()
}

pub fn set_links(header: &mut EntryHeader, links: Links) -> Result<Links> {
    unimplemented!()
}

pub fn add_link(header: &mut EntryHeader, link: Link) -> Result<()> {
    unimplemented!()
}

<commit_msg>Implement internal::get_links()<commit_after>use libimagstore::store::EntryHeader;

use error::{LinkError, LinkErrorKind};
use link::{Link, Links};
use result::Result;

use toml::Value;

pub fn get_links(header: &EntryHeader) -> Result<Links> {
    process_rw_result(header.read("imag.links"))
}

pub fn set_links(header: &mut EntryHeader, links: Links) -> Result<Links> {
    unimplemented!()
}

pub fn add_link(header: &mut EntryHeader, link: Link) -> Result<()> {
    unimplemented!()
}

<|endoftext|>


<commit_before>use crate::descriptor::DescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::reflect::file::dynamic::DynamicFileDescriptor;
use crate::reflect::file::fds::FdsBuilder;
use crate::reflect::file::index::FileIndex;
use crate::reflect::file::index::FileIndexMessageEntry;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::GeneratedFileDescriptor;
use crate::reflect::MessageDescriptor;
use std::collections::HashSet;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;

pub(crate) mod dynamic;
pub(crate) mod fds;
pub(crate) mod generated;
pub(crate) mod index;

#[derive(Clone, Debug)]
pub(crate) enum FileDescriptorImpl {
    Generated(&'static GeneratedFileDescriptor),
    Dynamic(Arc<DynamicFileDescriptor>),
}

impl PartialEq for FileDescriptorImpl {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (FileDescriptorImpl::Generated(a), FileDescriptorImpl::Generated(b)) => {
                *a as *const GeneratedFileDescriptor == *b as *const GeneratedFileDescriptor
            }
            (FileDescriptorImpl::Dynamic(a), FileDescriptorImpl::Dynamic(b)) => Arc::ptr_eq(a, b),
            _ => false,
        }
    }
}

impl Hash for FileDescriptorImpl {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            FileDescriptorImpl::Generated(g) => {
                Hash::hash(&(*g as *const GeneratedFileDescriptor), state)
            }
            FileDescriptorImpl::Dynamic(a) => {
                Hash::hash(&(&**a as *const DynamicFileDescriptor), state)
            }
        }
    }
}

impl Eq for FileDescriptorImpl {}

/// Reflection for objects defined in `.proto` file (messages, enums, etc).
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileDescriptor {
    pub(crate) imp: FileDescriptorImpl,
}

impl FileDescriptor {
    fn get_index(&self) -> &FileIndex {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.index,
            FileDescriptorImpl::Dynamic(d) => &d.index,
        }
    }

    pub(crate) fn get_message_index_entry(&self, index: usize) -> &FileIndexMessageEntry {
        &self.get_index().messages[index]
    }

    pub(crate) fn get_message_proto(&self, index: usize) -> &DescriptorProto {
        self.get_message_index_entry(index)
            .path
            .eval(self.get_proto())
            .unwrap()
    }

    /// Find message by name relative to the package.
    ///
    /// Only search in the current file, not in any dependencies.
    pub fn get_message_by_package_relative_name(&self, name: &str) -> MessageDescriptor {
        let index = self.get_index().message_by_name_to_package[name];
        MessageDescriptor::new(self.clone(), index)
    }

    /// This function is called from generated code, it is not stable, and should not be called.
    pub fn new_generated_2(generated: &'static GeneratedFileDescriptor) -> FileDescriptor {
        FileDescriptor {
            imp: FileDescriptorImpl::Generated(generated),
        }
    }

    /// Dynamic message created from [`FileDescriptorProto`] without generated files.
    pub fn new_dynamic(
        proto: FileDescriptorProto,
        dependencies: Vec<FileDescriptor>,
    ) -> FileDescriptor {
        FileDescriptor {
            imp: FileDescriptorImpl::Dynamic(Arc::new(DynamicFileDescriptor::new(
                proto,
                dependencies,
            ))),
        }
    }

    /// Create a set of file descriptors from individual file descriptors.
    pub fn new_dynamic_fds(protos: Vec<FileDescriptorProto>) -> Vec<FileDescriptor> {
        FdsBuilder::build(protos)
    }

    /// `.proto` data for this file.
    pub fn get_proto(&self) -> &FileDescriptorProto {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.proto,
            FileDescriptorImpl::Dynamic(d) => &d.proto,
        }
    }

    fn get_deps(&self) -> &[FileDescriptor] {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.dependencies,
            FileDescriptorImpl::Dynamic(d) => &d.dependencies,
        }
    }

    fn get_all_files(&self) -> Vec<&FileDescriptor> {
        let mut r = Vec::new();
        let mut visited = HashSet::new();

        let mut stack = Vec::new();
        stack.push(self);
        while let Some(file) = stack.pop() {
            if !visited.insert(file) {
                continue;
            }

            r.push(file);
            stack.extend(file.get_deps());
        }

        r
    }

    pub(crate) fn find_message_or_enum_proto_in_all_files<'a>(
        &'a self,
        full_name: &str,
    ) -> Option<(String, MessageOrEnum<'a>)> {
        // sanity check
        assert!(!full_name.starts_with("."));
        for file in self.get_all_files() {
            // sanity check
            let package = file.get_proto().get_package();
            assert!(!package.starts_with("."));

            let name_to_package = if package.is_empty() {
                full_name
            } else {
                let after_package = &full_name[package.len()..];
                if !after_package.starts_with(".") {
                    continue;
                }
                &after_package[1..]
            };

            if let Some(me) = find_message_or_enum(file.get_proto(), name_to_package) {
                return Some(me);
            }
        }
        None
    }
}

#[cfg(test)]
mod test {
    use crate::descriptor;

    #[test]
    fn eq() {
        assert!(descriptor::file_descriptor() == descriptor::file_descriptor().clone());
    }
}
<commit_msg>Some docs<commit_after>use crate::descriptor::DescriptorProto;
use crate::descriptor::FileDescriptorProto;
use crate::reflect::file::dynamic::DynamicFileDescriptor;
use crate::reflect::file::fds::FdsBuilder;
use crate::reflect::file::index::FileIndex;
use crate::reflect::file::index::FileIndexMessageEntry;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::GeneratedFileDescriptor;
use crate::reflect::MessageDescriptor;
use std::collections::HashSet;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;

pub(crate) mod dynamic;
pub(crate) mod fds;
pub(crate) mod generated;
pub(crate) mod index;

#[derive(Clone, Debug)]
pub(crate) enum FileDescriptorImpl {
    Generated(&'static GeneratedFileDescriptor),
    Dynamic(Arc<DynamicFileDescriptor>),
}

impl PartialEq for FileDescriptorImpl {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (FileDescriptorImpl::Generated(a), FileDescriptorImpl::Generated(b)) => {
                *a as *const GeneratedFileDescriptor == *b as *const GeneratedFileDescriptor
            }
            (FileDescriptorImpl::Dynamic(a), FileDescriptorImpl::Dynamic(b)) => Arc::ptr_eq(a, b),
            _ => false,
        }
    }
}

impl Hash for FileDescriptorImpl {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            FileDescriptorImpl::Generated(g) => {
                Hash::hash(&(*g as *const GeneratedFileDescriptor), state)
            }
            FileDescriptorImpl::Dynamic(a) => {
                Hash::hash(&(&**a as *const DynamicFileDescriptor), state)
            }
        }
    }
}

impl Eq for FileDescriptorImpl {}

/// Reflection for objects defined in `.proto` file (messages, enums, etc).
///
/// The object is refcounted: clone is shallow.
///
/// The equality performs pointer comparison: two clones of the same `FileDescriptor`
/// objects are equal, but two `FileDescriptor` objects created from the same `FileDescriptorProto`
/// objects are **not** equal.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileDescriptor {
    pub(crate) imp: FileDescriptorImpl,
}

impl FileDescriptor {
    fn get_index(&self) -> &FileIndex {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.index,
            FileDescriptorImpl::Dynamic(d) => &d.index,
        }
    }

    pub(crate) fn get_message_index_entry(&self, index: usize) -> &FileIndexMessageEntry {
        &self.get_index().messages[index]
    }

    pub(crate) fn get_message_proto(&self, index: usize) -> &DescriptorProto {
        self.get_message_index_entry(index)
            .path
            .eval(self.get_proto())
            .unwrap()
    }

    /// Find message by name relative to the package.
    ///
    /// Only search in the current file, not in any dependencies.
    pub fn get_message_by_package_relative_name(&self, name: &str) -> MessageDescriptor {
        let index = self.get_index().message_by_name_to_package[name];
        MessageDescriptor::new(self.clone(), index)
    }

    /// This function is called from generated code, it is not stable, and should not be called.
    #[doc(hidden)]
    // TODO: rename
    pub fn new_generated_2(generated: &'static GeneratedFileDescriptor) -> FileDescriptor {
        FileDescriptor {
            imp: FileDescriptorImpl::Generated(generated),
        }
    }

    /// Dynamic message created from [`FileDescriptorProto`] without generated files.
    pub fn new_dynamic(
        proto: FileDescriptorProto,
        dependencies: Vec<FileDescriptor>,
    ) -> FileDescriptor {
        FileDescriptor {
            imp: FileDescriptorImpl::Dynamic(Arc::new(DynamicFileDescriptor::new(
                proto,
                dependencies,
            ))),
        }
    }

    /// Create a set of file descriptors from individual file descriptors.
    pub fn new_dynamic_fds(protos: Vec<FileDescriptorProto>) -> Vec<FileDescriptor> {
        FdsBuilder::build(protos)
    }

    /// `.proto` data for this file.
    pub fn get_proto(&self) -> &FileDescriptorProto {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.proto,
            FileDescriptorImpl::Dynamic(d) => &d.proto,
        }
    }

    fn get_deps(&self) -> &[FileDescriptor] {
        match &self.imp {
            FileDescriptorImpl::Generated(g) => &g.dependencies,
            FileDescriptorImpl::Dynamic(d) => &d.dependencies,
        }
    }

    fn get_all_files(&self) -> Vec<&FileDescriptor> {
        let mut r = Vec::new();
        let mut visited = HashSet::new();

        let mut stack = Vec::new();
        stack.push(self);
        while let Some(file) = stack.pop() {
            if !visited.insert(file) {
                continue;
            }

            r.push(file);
            stack.extend(file.get_deps());
        }

        r
    }

    pub(crate) fn find_message_or_enum_proto_in_all_files<'a>(
        &'a self,
        full_name: &str,
    ) -> Option<(String, MessageOrEnum<'a>)> {
        // sanity check
        assert!(!full_name.starts_with("."));
        for file in self.get_all_files() {
            // sanity check
            let package = file.get_proto().get_package();
            assert!(!package.starts_with("."));

            let name_to_package = if package.is_empty() {
                full_name
            } else {
                let after_package = &full_name[package.len()..];
                if !after_package.starts_with(".") {
                    continue;
                }
                &after_package[1..]
            };

            if let Some(me) = find_message_or_enum(file.get_proto(), name_to_package) {
                return Some(me);
            }
        }
        None
    }
}

#[cfg(test)]
mod test {
    use crate::descriptor;

    #[test]
    fn eq() {
        assert!(descriptor::file_descriptor() == descriptor::file_descriptor().clone());
    }
}
<|endoftext|>


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

use std::collections::HashMap;

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub enum GenMode {
  /** Generate Vendored-style dependencies.
   *
   * This mode assumes that files are vendored (into vendor/), and generates BUILD files
   * accordingly
   */
  Vendored,

  /**
   * Generate Remote-style dependencies.
   *
   * This mode assumes that files are not locally vendored, and generates a workspace-level
   * function that can bring them in.
   */
  Remote,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CargoToml {
  /**
   * The raze settings (the only part of the Cargo.toml we care about.
   */
  pub raze: RazeSettings,
}

#[derive(Debug, Clone, Deserialize)]
pub struct RazeSettings {
  /** The path to the Cargo.toml working directory. */ pub workspace_path: String,

  /**
   * The platform target to generate BUILD rules for.
   *
   * This comes in the form of a "triple", such as "x86_64-unknown-linux-gnu"
   */
  #[serde(default = "default_target")]
  pub target: String,

  /** Any crate-specific configuration. See CrateSetings for details. */
  #[serde(default)]
  pub crates: HashMap<String, HashMap<String, CrateSettings>>,

  /**
   * Prefix for generated Bazel workspaces (from workspace_rules)
   *
   * This is only useful with remote genmode. It prefixes the names of the workspaces for
   * dependencies (@PREFIX_crateName_crateVersion) as well as the name of the repository function
   * generated in crates.bzl (PREFIX_fetch_remote_crates()).
   *
   * TODO(acmcarther): Does this have a non-bazel analogue?
   */
  #[serde(default = "default_gen_workspace_prefix")]
  pub gen_workspace_prefix: String,

  /** How to generate the dependencies. See GenMode for details. */
  #[serde(default = "default_genmode")]
  pub genmode: GenMode,
}

fn default_target() -> String {
  "x86_64-unknown-linux-gnu".to_owned()
}

fn default_gen_workspace_prefix() -> String {
  "raze".to_owned()
}

fn default_genmode() -> GenMode {
  GenMode::Vendored
}

#[derive(Debug, Clone, Deserialize)]
pub struct CrateSettings {
  /**
   * Dependencies to be added to a crate.
   *
   * Importantly, the format of dependency references depends on the genmode.
   * Remote: @{gen_workspace_prefix}__{dep_name}__{dep_version_sanitized}/:{dep_name}
   * Vendored: //{workspace_path}/vendor/{dep_name}-{dep_version}:{dep_name}
   *
   * In addition, the added deps must be accessible from a remote workspace under Remote GenMode.
   * Usually, this means they _also_ need to be remote, but a "local" build path prefixed with
   * "@", in the form "@//something_local" may work.
   */
  #[serde(default)]
  pub additional_deps: Vec<String>,

  /**
   * Dependencies to be removed from a crate, in the form "//etc".
   *
   * Importantly, the format of dependency references depends on the gen mode.
   * Remote: @{gen_workspace_prefix}__{dep_name}__{dep_version_sanitized}/:{dep_name}
   * Vendored: //{workspace_path}/vendor/{dep_name}-{dep_version}:{dep_name}
   */
  #[serde(default)]
  pub skipped_deps: Vec<String>,

  /**
   * Library targets that should be aliased in the root BUILD file.
   *
   * This is useful to facilitate using binary utility crates, such as bindgen, as part of genrules.
   */
  #[serde(default)]
  pub extra_aliased_targets: Vec<String>,

  /** Flags to be added to the crate compilation process, in the form "--flag". */
  #[serde(default)]
  pub additional_flags: Vec<String>,

  /**
   * Whether or not to generate the build script that goes with this crate.
   *
   * Many build scripts will not function, as they will still be built hermetically. However, build
   * scripts that merely generate files into OUT_DIR may be fully functional.
   */
  #[serde(default = "default_gen_buildrs")]
  pub gen_buildrs: bool,

  /**
   * The verbatim `data` clause to be included for the generated build targets.
   *
   * N.B. Build scripts are always provided all crate files for their `data` attr.
   */
  #[serde(default = "default_data_attr")]
  pub data_attr: Option<String>,
}

fn default_gen_buildrs() -> bool {
  false
}

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

use std::collections::HashMap;

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub enum GenMode {
  /** Generate Vendored-style dependencies.
   *
   * This mode assumes that files are vendored (into vendor/), and generates BUILD files
   * accordingly
   */
  Vendored,

  /**
   * Generate Remote-style dependencies.
   *
   * This mode assumes that files are not locally vendored, and generates a workspace-level
   * function that can bring them in.
   */
  Remote,
}

#[derive(Debug, Clone, Deserialize)]
pub struct CargoToml {
  /**
   * The raze settings (the only part of the Cargo.toml we care about.
   */
  pub raze: RazeSettings,
}

#[derive(Debug, Clone, Deserialize)]
pub struct RazeSettings {
  /** The path to the Cargo.toml working directory. */ pub workspace_path: String,

  /**
   * The platform target to generate BUILD rules for.
   *
   * This comes in the form of a "triple", such as "x86_64-unknown-linux-gnu"
   */
  #[serde(default = "default_target")]
  pub target: String,

  /** Any crate-specific configuration. See CrateSetings for details. */
  #[serde(default)]
  pub crates: HashMap<String, HashMap<String, CrateSettings>>,

  /**
   * Prefix for generated Bazel workspaces (from workspace_rules)
   *
   * This is only useful with remote genmode. It prefixes the names of the workspaces for
   * dependencies (@PREFIX_crateName_crateVersion) as well as the name of the repository function
   * generated in crates.bzl (PREFIX_fetch_remote_crates()).
   *
   * TODO(acmcarther): Does this have a non-bazel analogue?
   */
  #[serde(default = "default_gen_workspace_prefix")]
  pub gen_workspace_prefix: String,

  /** How to generate the dependencies. See GenMode for details. */
  #[serde(default = "default_genmode")]
  pub genmode: GenMode,
}

fn default_target() -> String {
  "x86_64-unknown-linux-gnu".to_owned()
}

fn default_gen_workspace_prefix() -> String {
  "raze".to_owned()
}

fn default_genmode() -> GenMode {
  GenMode::Vendored
}

#[derive(Debug, Clone, Deserialize)]
pub struct CrateSettings {
  /**
   * Dependencies to be added to a crate.
   *
   * Importantly, the format of dependency references depends on the genmode.
   * Remote: @{gen_workspace_prefix}__{dep_name}__{dep_version_sanitized}/:{dep_name}
   * Vendored: //{workspace_path}/vendor/{dep_name}-{dep_version}:{dep_name}
   *
   * In addition, the added deps must be accessible from a remote workspace under Remote GenMode.
   * Usually, this means they _also_ need to be remote, but a "local" build path prefixed with
   * "@", in the form "@//something_local" may work.
   */
  #[serde(default)]
  pub additional_deps: Vec<String>,

  /**
   * Dependencies to be removed from a crate, in the form "{dep-name}-{dep-version}"
   *
   * This is applied during Cargo analysis, so it uses Cargo-style labeling
   */
  #[serde(default)]
  pub skipped_deps: Vec<String>,

  /**
   * Library targets that should be aliased in the root BUILD file.
   *
   * This is useful to facilitate using binary utility crates, such as bindgen, as part of genrules.
   */
  #[serde(default)]
  pub extra_aliased_targets: Vec<String>,

  /** Flags to be added to the crate compilation process, in the form "--flag". */
  #[serde(default)]
  pub additional_flags: Vec<String>,

  /**
   * Whether or not to generate the build script that goes with this crate.
   *
   * Many build scripts will not function, as they will still be built hermetically. However, build
   * scripts that merely generate files into OUT_DIR may be fully functional.
   */
  #[serde(default = "default_gen_buildrs")]
  pub gen_buildrs: bool,

  /**
   * The verbatim `data` clause to be included for the generated build targets.
   *
   * N.B. Build scripts are always provided all crate files for their `data` attr.
   */
  #[serde(default = "default_data_attr")]
  pub data_attr: Option<String>,
}

fn default_gen_buildrs() -> bool {
  false
}

fn default_data_attr() -> Option<String> {
  None
}
<|endoftext|>


<commit_before>use std::{fmt, iter, ptr};

// ////////////////////////////////////////////////////////////////////////////
// SkipNode
// ////////////////////////////////////////////////////////////////////////////

/// SkipNodes are make up the SkipList.  The SkipList owns the first head-node
/// (which has no value) and each node has ownership of the next node through
/// `next`.
///
/// The node has a `level` which corresponds to how 'high' the node reaches, and
/// this should be equal to the length of the vector of links.  There is a
/// corresponding vector of link lengths which is used to reach a particular
/// index.
///
/// Lastly, each node contains a link to the immediately previous node in case
/// one needs to parse the list backwards.
///
/// In cases where the value is not applicable, `None` should be used.  In
/// particular, as there is no tail node, the value of `next` in the last node
/// should be `None`.
#[derive(Clone, Debug)]
pub struct SkipNode<V> {
    // key and value should never be None, with the sole exception being the
    // head node.
    pub value: Option<V>,
    // how high the node reaches.  This should be equal to the vector length.
    pub level: usize,
    // The immediately next element (and owns that next node).
    pub next: Option<Box<SkipNode<V>>>,
    // The immediately previous element.
    pub prev: Option<*mut SkipNode<V>>,
    // Vector of links to the next node at the respective level.  This vector
    // *must* be of length `self.level + 1`.  links[0] stores a pointer to the
    // same node as next.
    pub links: Vec<Option<*mut SkipNode<V>>>,
    // The corresponding length of each link
    pub links_len: Vec<usize>,
}

// ///////////////////////////////////////////////
// Inherent methods
// ///////////////////////////////////////////////

impl<V> SkipNode<V> {
    /// Create a new head node.
    pub fn head(total_levels: usize) -> Self {
        SkipNode {
            value: None,
            level: total_levels - 1,
            next: None,
            prev: None,
            links: iter::repeat(None).take(total_levels).collect(),
            links_len: iter::repeat(0).take(total_levels).collect(),
        }
    }

    /// Create a new SkipNode with the given value.  The values of `prev` and
    /// `next` will all be `None` and have to be adjusted.
    pub fn new(value: V, level: usize) -> Self {
        SkipNode {
            value: Some(value),
            level,
            next: None,
            prev: None,
            links: iter::repeat(None).take(level + 1).collect(),
            links_len: iter::repeat(0).take(level + 1).collect(),
        }
    }

    /// Consumes the node returning the value it contains.
    pub fn into_inner(mut self) -> Option<V> {
        self.value.take()
    }

    /// Returns `true` is the node is a head-node.
    pub fn is_head(&self) -> bool {
        self.prev.is_none()
    }
}

impl<V> Drop for SkipNode<V> {
    fn drop(&mut self) {
        while let Some(mut node) = self.next.take() {
            self.next = node.next.take();
        }
    }
}

// ///////////////////////////////////////////////
// Trait implementation
// ///////////////////////////////////////////////

impl<V> fmt::Display for SkipNode<V>
where
    V: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref v) = self.value {
            write!(f, "{}", v)
        } else {
            Ok(())
        }
    }
}

// /////////////////////////////////
// Iterators
// /////////////////////////////////
// Since Iterators (currently) only pop from front and back,
// they can be shared by some data structures.
// There's no need for a dummy head (that contains no value) in the iterator.
// so the members are named first and last instaed of head/end to avoid confusion.

/// Consuming iterator.
pub struct IntoIter<T> {
    pub first: Option<Box<SkipNode<T>>>,
    pub last: *mut SkipNode<T>,
    pub size: usize,
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut popped_node = self.first.take()?;
        self.size -= 1;
        self.first = popped_node.next.take().map(|mut node| {
            node.prev = None;
            node
        });
        if self.first.is_none() {
            self.last = ptr::null_mut();
        }
        popped_node.into_inner()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

impl<T> DoubleEndedIterator for IntoIter<T> {
    fn next_back(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        assert!(!self.last.is_null());
        unsafe {
            let new_last = (*self.last).prev;
            let popped_node = match new_last {
                Some(new_last) => {
                    self.last = new_last;
                    (*new_last).next.take().unwrap()
                }
                None => self.first.take().unwrap(),
            };
            self.size -= 1;
            popped_node.into_inner()
        }
    }
}
<commit_msg>Iterator attributes should be public to crate.<commit_after>use std::{fmt, iter, ptr};

// ////////////////////////////////////////////////////////////////////////////
// SkipNode
// ////////////////////////////////////////////////////////////////////////////

/// SkipNodes are make up the SkipList.  The SkipList owns the first head-node
/// (which has no value) and each node has ownership of the next node through
/// `next`.
///
/// The node has a `level` which corresponds to how 'high' the node reaches, and
/// this should be equal to the length of the vector of links.  There is a
/// corresponding vector of link lengths which is used to reach a particular
/// index.
///
/// Lastly, each node contains a link to the immediately previous node in case
/// one needs to parse the list backwards.
///
/// In cases where the value is not applicable, `None` should be used.  In
/// particular, as there is no tail node, the value of `next` in the last node
/// should be `None`.
#[derive(Clone, Debug)]
pub struct SkipNode<V> {
    // key and value should never be None, with the sole exception being the
    // head node.
    pub value: Option<V>,
    // how high the node reaches.  This should be equal to the vector length.
    pub level: usize,
    // The immediately next element (and owns that next node).
    pub next: Option<Box<SkipNode<V>>>,
    // The immediately previous element.
    pub prev: Option<*mut SkipNode<V>>,
    // Vector of links to the next node at the respective level.  This vector
    // *must* be of length `self.level + 1`.  links[0] stores a pointer to the
    // same node as next.
    pub links: Vec<Option<*mut SkipNode<V>>>,
    // The corresponding length of each link
    pub links_len: Vec<usize>,
}

// ///////////////////////////////////////////////
// Inherent methods
// ///////////////////////////////////////////////

impl<V> SkipNode<V> {
    /// Create a new head node.
    pub fn head(total_levels: usize) -> Self {
        SkipNode {
            value: None,
            level: total_levels - 1,
            next: None,
            prev: None,
            links: iter::repeat(None).take(total_levels).collect(),
            links_len: iter::repeat(0).take(total_levels).collect(),
        }
    }

    /// Create a new SkipNode with the given value.  The values of `prev` and
    /// `next` will all be `None` and have to be adjusted.
    pub fn new(value: V, level: usize) -> Self {
        SkipNode {
            value: Some(value),
            level,
            next: None,
            prev: None,
            links: iter::repeat(None).take(level + 1).collect(),
            links_len: iter::repeat(0).take(level + 1).collect(),
        }
    }

    /// Consumes the node returning the value it contains.
    pub fn into_inner(mut self) -> Option<V> {
        self.value.take()
    }

    /// Returns `true` is the node is a head-node.
    pub fn is_head(&self) -> bool {
        self.prev.is_none()
    }
}

impl<V> Drop for SkipNode<V> {
    fn drop(&mut self) {
        while let Some(mut node) = self.next.take() {
            self.next = node.next.take();
        }
    }
}

// ///////////////////////////////////////////////
// Trait implementation
// ///////////////////////////////////////////////

impl<V> fmt::Display for SkipNode<V>
where
    V: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref v) = self.value {
            write!(f, "{}", v)
        } else {
            Ok(())
        }
    }
}

// /////////////////////////////////
// Iterators
// /////////////////////////////////
// Since Iterators (currently) only pop from front and back,
// they can be shared by some data structures.
// There's no need for a dummy head (that contains no value) in the iterator.
// so the members are named first and last instaed of head/end to avoid confusion.

/// Consuming iterator.
pub struct IntoIter<T> {
    pub(crate) first: Option<Box<SkipNode<T>>>,
    pub(crate) last: *mut SkipNode<T>,
    pub(crate) size: usize,
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut popped_node = self.first.take()?;
        self.size -= 1;
        self.first = popped_node.next.take().map(|mut node| {
            node.prev = None;
            node
        });
        if self.first.is_none() {
            self.last = ptr::null_mut();
        }
        popped_node.into_inner()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

impl<T> DoubleEndedIterator for IntoIter<T> {
    fn next_back(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        assert!(!self.last.is_null());
        unsafe {
            let new_last = (*self.last).prev;
            let popped_node = match new_last {
                Some(new_last) => {
                    self.last = new_last;
                    (*new_last).next.take().unwrap()
                }
                None => self.first.take().unwrap(),
            };
            self.size -= 1;
            popped_node.into_inner()
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    // Take the mod of some large number to a large power
    let value = mod_of_power(324322, 87234632, 3724);
    println!("{} {}", "324322^(87234632) mod 3724:", value);
}

/// Get the modulus of an integer raised to a power.
/// **Calculates the modulus using modular exponentiation.**
fn mod_of_power(value: i32, power: i32, modulus: i32) -> i32 {
    let mut x: i32 = 1;
    for i in 0..power {
        x = (x * value) % modulus;
    }
    x
}
<commit_msg>Updated modpow with improved testing<commit_after>fn main() {
    // Loop 100 times
    for i in 1..10 {
        // Take the mod of number to large power
        let pow = i * 10000000;
        let value = mod_of_power(324322, pow, 3724);
        println!("{}{}{} {}", "324322^(", pow, ") mod 3724 =", value);
    }
}

/// Get the modulus of an integer raised to a power.
/// **Calculates the modulus using modular exponentiation.**
fn mod_of_power(value: i32, power: i32, modulus: i32) -> i32 {
    let mut x: i32 = 1;
    for i in 0..power {
        x = (x * value) % modulus;
    }
    x
}

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

    #[test]
    fn mod_of_power_zero() {
        let value = mod_of_power(3, 0, 5);
        assert_eq!(1, value);
    }

    #[test]
    fn mod_of_power_known_power() {
        let value = mod_of_power(5, 3, 7);
        assert_eq!(6, value);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use futures::{Future};

use std::cell::{Cell, RefCell};
use std::rc::{Rc, Weak};
use std::sync::Arc;

use stack::Stack;

enum Slot<T> {
    Next(usize),
    Data(T),
}

struct Inner<T, E> {
    // A slab of futures that are being executed. Each slot in this vector is
    // either an active future or a pointer to the next empty slot. This is used
    // to get O(1) deallocation in the slab and O(1) allocation.
    //
    // The `next_future` field is the next slot in the `futures` array that's a
    // `Slot::Next` variant. If it points to the end of the array then the array
    // is full.
    futures: RefCell<Vec<Slot<Box<Future<Item=T, Error=E>>>>>,
    next_future: Cell<usize>,

    new_futures: RefCell<Vec<Box<Future<Item=T, Error=E>>>>,

    stack: Arc<Stack<usize>>,
    reaper: RefCell<Box<TaskReaper<T, E>>>,

    terminate_with: RefCell<Option<Result<(), E>>>,

    handle_count: Cell<usize>,
    task: RefCell<Option<::futures::task::Task>>,
}

#[must_use = "a TaskSet does nothing unless polled"]
pub struct TaskSet<T, E> {
    inner: Rc<Inner<T, E>>,
}

impl<T, E> TaskSet<T, E> where T: 'static, E: 'static {
    pub fn new(reaper: Box<TaskReaper<T, E>>)
               -> (TaskSetHandle<T, E>, TaskSet<T, E>)
        where E: 'static, T: 'static, E: ::std::fmt::Debug,
    {
        let inner = Rc::new(Inner {
            futures: RefCell::new(Vec::new()),
            next_future: Cell::new(0),
            new_futures: RefCell::new(Vec::new()),
            stack: Arc::new(Stack::new()),
            reaper: RefCell::new(reaper),
            terminate_with: RefCell::new(None),
            handle_count: Cell::new(1),
            task: RefCell::new(None),
        });

        let weak_inner = Rc::downgrade(&inner);

        let set = TaskSet {
            inner: inner,
        };

        let handle = TaskSetHandle {
            inner: weak_inner,
        };

        (handle, set)
    }
}

pub struct TaskSetHandle<T, E> {
    inner: Weak<Inner<T, E>>,
}

impl<T, E> Clone for TaskSetHandle<T, E> {
    fn clone(&self) -> TaskSetHandle<T, E> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.handle_count.set(inner.handle_count.get() + 1);
            }
        }
        TaskSetHandle {
            inner: self.inner.clone()
        }
    }
}

impl <T, E> Drop for TaskSetHandle<T, E> {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.handle_count.set(inner.handle_count.get() - 1);
            }
        }
    }
}

impl <T, E> TaskSetHandle<T, E> where T: 'static, E: 'static {
    pub fn add<F>(&mut self, promise: F)
        where F: Future<Item=T, Error=E> + 'static
    {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                rc_inner.new_futures.borrow_mut().push(Box::new(promise));

                match rc_inner.task.borrow_mut().take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }

    pub fn terminate(&mut self, result: Result<(), E>) {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                *rc_inner.terminate_with.borrow_mut() = Some(result);

                match rc_inner.task.borrow_mut().take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }
}

pub trait TaskReaper<T, E> where T: 'static, E: 'static
{
    fn task_succeeded(&mut self, _value: T) {}
    fn task_failed(&mut self, error: E);
}

impl <T, E> Future for TaskSet<T, E> where T: 'static, E: 'static {
    type Item = ();
    type Error = E;

    fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {

        match self.inner.terminate_with.borrow_mut().take() {
            None => (),
            Some(Ok(v)) => return Ok(::futures::Async::Ready(v)),
            Some(Err(e)) => return Err(e),
        }

        let new_futures = ::std::mem::replace(&mut *self.inner.new_futures.borrow_mut(), Vec::new());
        for future in new_futures {
            let added_idx = self.inner.next_future.get();
            if self.inner.next_future.get() == self.inner.futures.borrow().len() {
                self.inner.futures.borrow_mut().push(Slot::Data(future));
                self.inner.next_future.set(self.inner.next_future.get() + 1);
            } else {
                match ::std::mem::replace(&mut self.inner.futures.borrow_mut()[self.inner.next_future.get()],
                                          Slot::Data(future)) {
                    Slot::Next(next) => self.inner.next_future.set(next),
                    Slot::Data(_) => unreachable!(),
                }
            }

            self.inner.stack.push(added_idx);
        }

        let drain = self.inner.stack.drain();
        for idx in drain {
            match self.inner.futures.borrow_mut()[idx] {
                Slot::Next(_) => unreachable!(),
                Slot::Data(ref mut f) => {
                    let event = ::futures::task::UnparkEvent::new(self.inner.stack.clone(), idx);
                    match ::futures::task::with_unpark_event(event, || f.poll()) {
                        Ok(::futures::Async::NotReady) => continue,
                        Ok(::futures::Async::Ready(v)) => {
                            self.inner.reaper.borrow_mut().task_succeeded(v);
                        }
                        Err(e) => {
                            self.inner.reaper.borrow_mut().task_failed(e);
                        }
                    }
                }
            }
            self.inner.futures.borrow_mut()[idx] = Slot::Next(self.inner.next_future.get());
            self.inner.next_future.set(idx);
        }

        if self.inner.futures.borrow().len() == 0 && self.inner.handle_count.get() == 0 {
            Ok(::futures::Async::Ready(()))
        } else {
            *self.inner.task.borrow_mut() = Some(::futures::task::park());
            Ok(::futures::Async::NotReady)
        }
    }
}
<commit_msg>fix bug: account for new tasks being added during poll()<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use futures::{Future};

use std::cell::{Cell, RefCell};
use std::rc::{Rc, Weak};
use std::sync::Arc;

use stack::Stack;

enum Slot<T> {
    Next(usize),
    Data(T),
}

struct Inner<T, E> {
    // A slab of futures that are being executed. Each slot in this vector is
    // either an active future or a pointer to the next empty slot. This is used
    // to get O(1) deallocation in the slab and O(1) allocation.
    //
    // The `next_future` field is the next slot in the `futures` array that's a
    // `Slot::Next` variant. If it points to the end of the array then the array
    // is full.
    futures: RefCell<Vec<Slot<Box<Future<Item=T, Error=E>>>>>,
    next_future: Cell<usize>,

    new_futures: RefCell<Vec<Box<Future<Item=T, Error=E>>>>,

    stack: Arc<Stack<usize>>,
    reaper: RefCell<Box<TaskReaper<T, E>>>,

    terminate_with: RefCell<Option<Result<(), E>>>,

    handle_count: Cell<usize>,
    task: RefCell<Option<::futures::task::Task>>,
}

#[must_use = "a TaskSet does nothing unless polled"]
pub struct TaskSet<T, E> {
    inner: Rc<Inner<T, E>>,
}

impl<T, E> TaskSet<T, E> where T: 'static, E: 'static {
    pub fn new(reaper: Box<TaskReaper<T, E>>)
               -> (TaskSetHandle<T, E>, TaskSet<T, E>)
        where E: 'static, T: 'static, E: ::std::fmt::Debug,
    {
        let inner = Rc::new(Inner {
            futures: RefCell::new(Vec::new()),
            next_future: Cell::new(0),
            new_futures: RefCell::new(Vec::new()),
            stack: Arc::new(Stack::new()),
            reaper: RefCell::new(reaper),
            terminate_with: RefCell::new(None),
            handle_count: Cell::new(1),
            task: RefCell::new(None),
        });

        let weak_inner = Rc::downgrade(&inner);

        let set = TaskSet {
            inner: inner,
        };

        let handle = TaskSetHandle {
            inner: weak_inner,
        };

        (handle, set)
    }
}

pub struct TaskSetHandle<T, E> {
    inner: Weak<Inner<T, E>>,
}

impl<T, E> Clone for TaskSetHandle<T, E> {
    fn clone(&self) -> TaskSetHandle<T, E> {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.handle_count.set(inner.handle_count.get() + 1);
            }
        }
        TaskSetHandle {
            inner: self.inner.clone()
        }
    }
}

impl <T, E> Drop for TaskSetHandle<T, E> {
    fn drop(&mut self) {
        match self.inner.upgrade() {
            None => (),
            Some(inner) => {
                inner.handle_count.set(inner.handle_count.get() - 1);
            }
        }
    }
}

impl <T, E> TaskSetHandle<T, E> where T: 'static, E: 'static {
    pub fn add<F>(&mut self, promise: F)
        where F: Future<Item=T, Error=E> + 'static
    {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                rc_inner.new_futures.borrow_mut().push(Box::new(promise));

                match rc_inner.task.borrow_mut().take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }

    pub fn terminate(&mut self, result: Result<(), E>) {
        match self.inner.upgrade() {
            None => (),
            Some(rc_inner) => {
                *rc_inner.terminate_with.borrow_mut() = Some(result);

                match rc_inner.task.borrow_mut().take() {
                    Some(t) => t.unpark(),
                    None => (),
                }
            }
        }
    }
}

pub trait TaskReaper<T, E> where T: 'static, E: 'static
{
    fn task_succeeded(&mut self, _value: T) {}
    fn task_failed(&mut self, error: E);
}

impl <T, E> Future for TaskSet<T, E> where T: 'static, E: 'static {
    type Item = ();
    type Error = E;

    fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {

        match self.inner.terminate_with.borrow_mut().take() {
            None => (),
            Some(Ok(v)) => return Ok(::futures::Async::Ready(v)),
            Some(Err(e)) => return Err(e),
        }

        let new_futures = ::std::mem::replace(&mut *self.inner.new_futures.borrow_mut(), Vec::new());
        for future in new_futures {
            let added_idx = self.inner.next_future.get();
            if self.inner.next_future.get() == self.inner.futures.borrow().len() {
                self.inner.futures.borrow_mut().push(Slot::Data(future));
                self.inner.next_future.set(self.inner.next_future.get() + 1);
            } else {
                match ::std::mem::replace(&mut self.inner.futures.borrow_mut()[self.inner.next_future.get()],
                                          Slot::Data(future)) {
                    Slot::Next(next) => self.inner.next_future.set(next),
                    Slot::Data(_) => unreachable!(),
                }
            }

            self.inner.stack.push(added_idx);
        }

        let drain = self.inner.stack.drain();
        for idx in drain {
            match self.inner.futures.borrow_mut()[idx] {
                Slot::Next(_) => unreachable!(),
                Slot::Data(ref mut f) => {
                    let event = ::futures::task::UnparkEvent::new(self.inner.stack.clone(), idx);
                    match ::futures::task::with_unpark_event(event, || f.poll()) {
                        Ok(::futures::Async::NotReady) => continue,
                        Ok(::futures::Async::Ready(v)) => {
                            self.inner.reaper.borrow_mut().task_succeeded(v);
                        }
                        Err(e) => {
                            self.inner.reaper.borrow_mut().task_failed(e);
                        }
                    }
                }
            }
            self.inner.futures.borrow_mut()[idx] = Slot::Next(self.inner.next_future.get());
            self.inner.next_future.set(idx);
        }

        if self.inner.futures.borrow().len() == 0 && self.inner.handle_count.get() == 0 {
            Ok(::futures::Async::Ready(()))
        } else {
            let task = ::futures::task::park();
            if self.inner.new_futures.borrow().len() > 0 {
                // Some new futures got added when we called poll().
                task.unpark();
            }
            *self.inner.task.borrow_mut() = Some(task);
            Ok(::futures::Async::NotReady)
        }
    }
}
<|endoftext|>


<commit_before>use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf;
use syntax::{
    ast::{self, edit::AstNodeEdit, NameOwner},
    AstNode, TextRange,
};
use test_utils::mark;

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    let module_def = ctx.sema.to_def(&module_ast)?;
    let parent_module = module_def.parent(ctx.db())?;

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let dir = match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name),
                    _ => String::new(),
                };
                format!("./{}{}.rs", dir, module_name)
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            builder.replace(module_ast.syntax().text_range(), format!("mod {};", module_name));

            let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }
}
<commit_msg>Fix #7712 retain visibility extracting mod to file<commit_after>use ast::{edit::IndentLevel, VisibilityOwner};
use ide_db::base_db::AnchoredPathBuf;
use syntax::{
    ast::{self, edit::AstNodeEdit, NameOwner},
    AstNode, TextRange,
};
use test_utils::mark;

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    let module_def = ctx.sema.to_def(&module_ast)?;
    let parent_module = module_def.parent(ctx.db())?;
    let vis_str =
        if let Some(v) = module_ast.visibility() { v.to_string() + " " } else { "".to_string() };

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let dir = match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name),
                    _ => String::new(),
                };
                format!("./{}{}.rs", dir, module_name)
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            builder.replace(
                module_ast.syntax().text_range(),
                format!("{}mod {};", vis_str, module_name),
            );

            let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_public() {
        check_assist(
            move_module_to_file,
            r#"
pub mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_public_crate() {
        check_assist(
            move_module_to_file,
            r#"
pub(crate) mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub(crate) mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }
}
<|endoftext|>


<commit_before>//! This is the wasm web-gui.
//! This file is only compiled for the wasm32 target.

#![cfg(target_arch = "wasm32")]
#![recursion_limit = "512"]

use ascii_hangman_backend::game::State;
use ascii_hangman_backend::Backend;
use ascii_hangman_backend::HangmanBackend;
use ascii_hangman_backend::{AUTHOR, CONF_TEMPLATE, TITLE, VERSION};
use wasm_bindgen::prelude::*;
use yew::events::KeyboardEvent;
use yew::prelude::*;
use yew::services::reader::{File, FileData, ReaderService, ReaderTask};
// Disable debugging code.
//use yew::services::ConsoleService;
use yew::services::DialogService;
use yew::{html, Component, ComponentLink, Html, InputData, ShouldRender};

#[derive(Debug)]
pub enum Scene {
    Playground(Backend),
    ConfigureGame,
    GameOver,
}

pub struct GuiState {
    config_text: String,
    guess: String,
}

pub struct Model {
    link: ComponentLink<Self>,
    reader: ReaderService,
    // Disable debugging code.
    //console: ConsoleService,
    filereader_tasks: Vec<ReaderTask>,
    scene: Scene,
    state: GuiState,
}

#[derive(Debug)]
pub enum Msg {
    SwitchTo(Scene),
    ConfigTextDelete,
    ConfigTextUpdate(String),
    ConfigReady,
    Files(Vec<File>),
    Loaded(FileData),
    UpdateGuess(String),
    Guess,
    Nope,
    NextRound,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let state = GuiState {
            config_text: String::from(CONF_TEMPLATE),
            guess: String::new(),
        };

        Model {
            link,
            reader: ReaderService::new(),
            // Disable debugging code.
            //console: ConsoleService::new(),
            filereader_tasks: vec![],
            scene: Scene::ConfigureGame,
            state,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        let mut new_scene = None;
        match &mut self.scene {
            Scene::Playground(ref mut app) => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                Msg::SwitchTo(Scene::GameOver) => {
                    new_scene = Some(Scene::GameOver);
                }
                Msg::UpdateGuess(val) => {
                    self.state.guess = val.chars().rev().take(1).collect();
                    // Disable debugging code.
                    //self.console.debug(&self.state.guess);
                }
                Msg::Guess => {
                    app.process_user_input(&self.state.guess);
                    self.state.guess = String::new();
                }
                Msg::Nope => {}
                unexpected => {
                    panic!(
                        "Unexpected message when configurations list shown: {:?}",
                        unexpected
                    );
                }
            },
            Scene::ConfigureGame => match msg {
                Msg::ConfigTextUpdate(val) => {
                    self.state.config_text = val;
                }
                Msg::ConfigTextDelete => {
                    self.state.config_text.clear();
                }
                Msg::SwitchTo(Scene::Playground(app)) => {
                    new_scene = Some(Scene::Playground(app));
                }

                Msg::SwitchTo(Scene::GameOver) => {
                    if DialogService::confirm("Do you really want to quit this game?") {
                        new_scene = Some(Scene::GameOver);
                    }
                }

                Msg::Loaded(file) => {
                    if let Ok(s) = std::str::from_utf8(&file.content) {
                        self.state.config_text.push_str(s);
                    } else {
                        DialogService::alert(&format!("Can not read text file: {}", file.name));
                    }
                }
                Msg::Files(files) => {
                    for file in files.into_iter() {
                        let task = {
                            let callback = self.link.callback(Msg::Loaded);
                            self.reader.read_file(file, callback).unwrap()
                        };
                        self.filereader_tasks.push(task);
                    }
                }
                Msg::ConfigReady => {
                    match Backend::new(self.state.config_text.as_str()) {
                        Ok(app) => {
                            self.link
                                .send_message(Msg::SwitchTo(Scene::Playground(app)));
                        }
                        Err(e) => {
                            DialogService::alert(&format!("Can not parse configuration:\n {}", e))
                        }
                    };
                }
                unexpected => {
                    panic!(
                        "Unexpected message during new config editing: {:?}",
                        unexpected
                    );
                }
            },
            Scene::GameOver => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                unexpected => {
                    panic!("Unexpected message for settings scene: {:?}", unexpected);
                }
            },
        }
        if let Some(new_scene) = new_scene.take() {
            self.scene = new_scene;
        }
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        let header = move || -> Html {
            html! {
 {TITLE}
 }
        };
        let footer = move || -> Html {
            html! {
             {"User Manual"}
            {", "}  {"Desktop Version"}
            {", "}  {"Documentation"}
            {", "}  {"Source Code"}
            {", Version "} {VERSION.unwrap()} {", "} {AUTHOR}   }
        };
        match self.scene {
            Scene::ConfigureGame => html! { <>
                {header()}

 {"Enter your secrets here:"}

                    <textarea class="conf-text"
                        placeholder=CONF_TEMPLATE
                        cols=80
                        rows=25
                        value=&self.state.config_text
                        oninput=self.link.callback(|e: InputData| Msg::ConfigTextUpdate(e.value)) />

 { "or load secrets from files: "}
                        {"Upload Files ..."}
                        <input class="custom-file-input" type="file" id="upload" multiple=true onchange=self.link.callback(move |value| {
                                let mut result = Vec::new();
                                if let ChangeData::Files(files) = value {
                                    let files = js_sys::try_iter(&files)
                                        .unwrap()
                                        .unwrap()
                                        .into_iter()
                                        .map(|v| File::from(v.unwrap()));
                                    result.extend(files);
                                }
                                Msg::Files(result)
                            })/>

                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigTextDelete)>{ "Delete Secrets" }</button>
                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigReady)>{ "Start Game" }</button>

                {footer()}
                </>
            },
            Scene::Playground(ref app) => {
                let secret = app.render_secret();
                let (cols, rows) = dimensions(&secret);
                let secret = secret.trim_end_matches("\n");
                let image = app.render_image();
                let image = image.trim_end_matches("\n");
                html! { <>
                    {header()}

                            <textarea class=("image")
                                placeholder="Image"
                                cols=format!("{}", &app.get_image_dimension().0)
                                rows=format!("{}", &app.get_image_dimension().1)
                                value=image
                                readonly=true
                            />

                            { app.render_game_lifes() } { " " }

                            { app.render_game_last_guess() }

                            <textarea class=("secret")
                                cols=cols+1
                                rows=rows
                                value=secret
                                readonly=true
                            />

                            { app.render_instructions() }
                            <input class="guess"
                                type="text"
                                autofocus=true
                                size=1
                                value=self.state.guess
                                oninput=self.link.callback(|e: InputData| Msg::UpdateGuess(e.value))
                                onkeypress=self.link.callback(|e: KeyboardEvent| {
                                   if e.key() == "Enter" { Msg::Guess } else { Msg::Nope }
                                }) />

                        <button disabled={app.get_state() == State::Ongoing || app.get_state() == State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::Guess)>{ "Continue Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "Reset Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::GameOver))>{ "End Game" }</button>

                    {footer()}
                    </>
                }
            }
            Scene::GameOver => html! { <>
                {header()}

 { "Bye bye!" }

                    <button onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "No, Continue Playing" }</button>

                {footer()}
                </>
            },
        }
    }
}

/// Returns the columns and lines of the smallest
/// grid that can display this multi-line string `s`.
pub fn dimensions(s: &str) -> (usize, usize) {
    let mut row = 0;
    let mut col = 0;
    for l in s.lines() {
        let c = l.chars().count();
        if c > col {
            col = c;
        };
        row += 1;
    }
    (col, row)
}

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Model>::new().mount_to_body();
}

#[cfg(test)]
mod tests {
    use super::*;
    use secret::Secret;
    #[test]
    fn test_dimensions() {
        let secret = Secret::new("Lorem ipsum dolor sit amet, consectetur adipiscing\
         elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\
         quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure\
         dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\
         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est\
         laborum.");

        //secret.disclose_all();

        assert_eq!(dimensions(format!("{}", secret).as_str()), (68, 22));
        //assert_eq!(format!("{}", secret), String::new());
    }
}
<commit_msg>add good bye insruction<commit_after>//! This is the wasm web-gui.
//! This file is only compiled for the wasm32 target.

#![cfg(target_arch = "wasm32")]
#![recursion_limit = "512"]

use ascii_hangman_backend::game::State;
use ascii_hangman_backend::Backend;
use ascii_hangman_backend::HangmanBackend;
use ascii_hangman_backend::{AUTHOR, CONF_TEMPLATE, TITLE, VERSION};
use wasm_bindgen::prelude::*;
use yew::events::KeyboardEvent;
use yew::prelude::*;
use yew::services::reader::{File, FileData, ReaderService, ReaderTask};
// Disable debugging code.
//use yew::services::ConsoleService;
use yew::services::DialogService;
use yew::{html, Component, ComponentLink, Html, InputData, ShouldRender};

#[derive(Debug)]
pub enum Scene {
    Playground(Backend),
    ConfigureGame,
    GameOver,
}

pub struct GuiState {
    config_text: String,
    guess: String,
}

pub struct Model {
    link: ComponentLink<Self>,
    reader: ReaderService,
    // Disable debugging code.
    //console: ConsoleService,
    filereader_tasks: Vec<ReaderTask>,
    scene: Scene,
    state: GuiState,
}

#[derive(Debug)]
pub enum Msg {
    SwitchTo(Scene),
    ConfigTextDelete,
    ConfigTextUpdate(String),
    ConfigReady,
    Files(Vec<File>),
    Loaded(FileData),
    UpdateGuess(String),
    Guess,
    Nope,
    NextRound,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let state = GuiState {
            config_text: String::from(CONF_TEMPLATE),
            guess: String::new(),
        };

        Model {
            link,
            reader: ReaderService::new(),
            // Disable debugging code.
            //console: ConsoleService::new(),
            filereader_tasks: vec![],
            scene: Scene::ConfigureGame,
            state,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        let mut new_scene = None;
        match &mut self.scene {
            Scene::Playground(ref mut app) => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                Msg::SwitchTo(Scene::GameOver) => {
                    new_scene = Some(Scene::GameOver);
                }
                Msg::UpdateGuess(val) => {
                    self.state.guess = val.chars().rev().take(1).collect();
                    // Disable debugging code.
                    //self.console.debug(&self.state.guess);
                }
                Msg::Guess => {
                    app.process_user_input(&self.state.guess);
                    self.state.guess = String::new();
                }
                Msg::Nope => {}
                unexpected => {
                    panic!(
                        "Unexpected message when configurations list shown: {:?}",
                        unexpected
                    );
                }
            },
            Scene::ConfigureGame => match msg {
                Msg::ConfigTextUpdate(val) => {
                    self.state.config_text = val;
                }
                Msg::ConfigTextDelete => {
                    self.state.config_text.clear();
                }
                Msg::SwitchTo(Scene::Playground(app)) => {
                    new_scene = Some(Scene::Playground(app));
                }

                Msg::SwitchTo(Scene::GameOver) => {
                    if DialogService::confirm("Do you really want to quit this game?") {
                        new_scene = Some(Scene::GameOver);
                    }
                }

                Msg::Loaded(file) => {
                    if let Ok(s) = std::str::from_utf8(&file.content) {
                        self.state.config_text.push_str(s);
                    } else {
                        DialogService::alert(&format!("Can not read text file: {}", file.name));
                    }
                }
                Msg::Files(files) => {
                    for file in files.into_iter() {
                        let task = {
                            let callback = self.link.callback(Msg::Loaded);
                            self.reader.read_file(file, callback).unwrap()
                        };
                        self.filereader_tasks.push(task);
                    }
                }
                Msg::ConfigReady => {
                    match Backend::new(self.state.config_text.as_str()) {
                        Ok(app) => {
                            self.link
                                .send_message(Msg::SwitchTo(Scene::Playground(app)));
                        }
                        Err(e) => {
                            DialogService::alert(&format!("Can not parse configuration:\n {}", e))
                        }
                    };
                }
                unexpected => {
                    panic!(
                        "Unexpected message during new config editing: {:?}",
                        unexpected
                    );
                }
            },
            Scene::GameOver => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                unexpected => {
                    panic!("Unexpected message for settings scene: {:?}", unexpected);
                }
            },
        }
        if let Some(new_scene) = new_scene.take() {
            self.scene = new_scene;
        }
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        let header = move || -> Html {
            html! {
 {TITLE}
 }
        };
        let footer = move || -> Html {
            html! {
             {"User Manual"}
            {", "}  {"Desktop Version"}
            {", "}  {"Documentation"}
            {", "}  {"Source Code"}
            {", Version "} {VERSION.unwrap()} {", "} {AUTHOR}   }
        };
        match self.scene {
            Scene::ConfigureGame => html! { <>
                {header()}

 {"Enter your secrets here:"}

                    <textarea class="conf-text"
                        placeholder=CONF_TEMPLATE
                        cols=80
                        rows=25
                        value=&self.state.config_text
                        oninput=self.link.callback(|e: InputData| Msg::ConfigTextUpdate(e.value)) />

 { "or load secrets from files: "}
                        {"Upload Files ..."}
                        <input class="custom-file-input" type="file" id="upload" multiple=true onchange=self.link.callback(move |value| {
                                let mut result = Vec::new();
                                if let ChangeData::Files(files) = value {
                                    let files = js_sys::try_iter(&files)
                                        .unwrap()
                                        .unwrap()
                                        .into_iter()
                                        .map(|v| File::from(v.unwrap()));
                                    result.extend(files);
                                }
                                Msg::Files(result)
                            })/>

                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigTextDelete)>{ "Delete Secrets" }</button>
                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigReady)>{ "Start Game" }</button>

                {footer()}
                </>
            },
            Scene::Playground(ref app) => {
                let secret = app.render_secret();
                let (cols, rows) = dimensions(&secret);
                let secret = secret.trim_end_matches("\n");
                let image = app.render_image();
                let image = image.trim_end_matches("\n");
                html! { <>
                    {header()}

                            <textarea class=("image")
                                placeholder="Image"
                                cols=format!("{}", &app.get_image_dimension().0)
                                rows=format!("{}", &app.get_image_dimension().1)
                                value=image
                                readonly=true
                            />

                            { app.render_game_lifes() } { " " }

                            { app.render_game_last_guess() }

                            <textarea class=("secret")
                                cols=cols+1
                                rows=rows
                                value=secret
                                readonly=true
                            />

                            { app.render_instructions() }
                            <input class="guess"
                                type="text"
                                autofocus=true
                                size=1
                                value=self.state.guess
                                oninput=self.link.callback(|e: InputData| Msg::UpdateGuess(e.value))
                                onkeypress=self.link.callback(|e: KeyboardEvent| {
                                   if e.key() == "Enter" { Msg::Guess } else { Msg::Nope }
                                }) />

                        <button disabled={app.get_state() == State::Ongoing || app.get_state() == State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::Guess)>{ "Continue Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "Reset Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::GameOver))>{ "End Game" }</button>

                    {footer()}
                    </>
                }
            }
            Scene::GameOver => html! { <>
                {header()}

 {"You can now close this window."}

 { "Bye bye!" }

                    <button onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "No, Continue Playing" }</button>

                {footer()}
                </>
            },
        }
    }
}

/// Returns the columns and lines of the smallest
/// grid that can display this multi-line string `s`.
pub fn dimensions(s: &str) -> (usize, usize) {
    let mut row = 0;
    let mut col = 0;
    for l in s.lines() {
        let c = l.chars().count();
        if c > col {
            col = c;
        };
        row += 1;
    }
    (col, row)
}

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Model>::new().mount_to_body();
}

#[cfg(test)]
mod tests {
    use super::*;
    use secret::Secret;
    #[test]
    fn test_dimensions() {
        let secret = Secret::new("Lorem ipsum dolor sit amet, consectetur adipiscing\
         elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\
         quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure\
         dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\
         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est\
         laborum.");

        //secret.disclose_all();

        assert_eq!(dimensions(format!("{}", secret).as_str()), (68, 22));
        //assert_eq!(format!("{}", secret), String::new());
    }
}
<|endoftext|>