<commit_before>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(btree_drain_filter)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(deque_range)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(container_error_extra)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(map_first_last)]
#![feature(map_into_keys_values)]
#![feature(negative_impls)]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;
}
<commit_msg>fix build issue due to stabilized feature<commit_after>//! # The Rust core allocation and collections library
//!
//! This library provides smart pointers and collections for managing
//! heap-allocated values.
//!
//! This library, like libcore, normally doesn’t need to be used directly
//! since its contents are re-exported in the [`std` crate](../std/index.html).
//! Crates that use the `#![no_std]` attribute however will typically
//! not depend on `std`, so they’d use this crate instead.
//!
//! ## Boxed values
//!
//! The [`Box`] type is a smart pointer type. There can only be one owner of a
//! [`Box`], and the owner can decide to mutate the contents, which live on the
//! heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`] type is a non-threadsafe reference-counted pointer type intended
//! for sharing memory within a thread. An [`Rc`] pointer wraps a type, `T`, and
//! only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using [`Box`]) is too
//! constraining for an application, and is often paired with the [`Cell`] or
//! [`RefCell`] types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`] type is the threadsafe equivalent of the [`Rc`] type. It
//! provides all the same functionality of [`Rc`], except it requires that the
//! contained type `T` is shareable. Additionally, [`Arc<T>`][`Arc`] is itself
//! sendable while [`Rc<T>`][`Rc`] is not.
//!
//! This type allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Collections
//!
//! Implementations of the most common general purpose data structures are
//! defined in this library. They are re-exported through the
//! [standard collections library](../std/collections/index.html).
//!
//! ## Heap interfaces
//!
//! The [`alloc`](alloc/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.
//!
//! [`Arc`]: sync
//! [`Box`]: boxed
//! [`Cell`]: core::cell
//! [`Rc`]: rc
//! [`RefCell`]: core::cell

#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
    html_root_url = "https://doc.rust-lang.org/nightly/",
    html_playground_url = "https://play.rust-lang.org/",
    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
    test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
)]
#![no_std]
#![needs_allocator]
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(btree_drain_filter)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
#![feature(deque_range)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(container_error_extra)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(map_first_last)]
#![feature(map_into_keys_values)]
#![feature(negative_impls)]
#![cfg_attr(bootstrap, feature(never_type))]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(optin_builtin_traits)]
#![feature(or_patterns)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(unicode_internals)]
#![feature(unsafe_block_in_unsafe_fn)]
#![feature(unsize)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
// Allow testing this library

#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
extern crate test;

// Module with internal macros used by other modules (needs to be included before other modules).
#[macro_use]
mod macros;

// Heaps provided for low-level allocation strategies

pub mod alloc;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed {
    pub use std::boxed::Box;
}
pub mod borrow;
pub mod collections;
pub mod fmt;
pub mod prelude;
pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
pub mod string;
#[cfg(target_has_atomic = "ptr")]
pub mod sync;
#[cfg(target_has_atomic = "ptr")]
pub mod task;
#[cfg(test)]
mod tests;
pub mod vec;

#[cfg(not(test))]
mod std {
    pub use core::ops; // RangeFull
}

#[doc(hidden)]
#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
pub mod __export {
    pub use core::format_args;
}
<|endoftext|>


<commit_before>#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;

use crate::fmt;
use crate::marker;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::mutex as sys;

/// A re-entrant mutual exclusion
///
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
    inner: sys::ReentrantMutex,
    data: T,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

impl<T> UnwindSafe for ReentrantMutex<T> {}
impl<T> RefUnwindSafe for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// Deref implementation.
///
/// # Mutability
///
/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
/// because implementation of the trait would violate Rust’s reference aliasing
/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
/// guarded data.
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ReentrantMutexGuard<'a, T: 'a> {
    // funny underscores due to how Deref currently works (it disregards field
    // privacy).
    __lock: &'a ReentrantMutex<T>,
}

impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe because it is required that `init` is called
    /// once this mutex is in its final resting place, and only then are the
    /// lock/unlock methods safe.
    pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
        ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
    }

    /// Initializes this mutex so it's ready for use.
    ///
    /// # Unsafety
    ///
    /// Unsafe to call more than once, and must be called after this will no
    /// longer move in memory.
    pub unsafe fn init(&self) {
        self.inner.init();
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the caller until it is available to acquire the mutex.
    /// Upon returning, the thread is the only thread with the mutex held. When the thread
    /// calling this method already holds the lock, the call shall succeed without
    /// blocking.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
        unsafe { self.inner.lock() }
        ReentrantMutexGuard::new(&self)
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned.
    ///
    /// This function does not block.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
        if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
    }
}

impl<T> Drop for ReentrantMutex<T> {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.inner.destroy() }
    }
}

impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
            None => {
                struct LockedPlaceholder;
                impl fmt::Debug for LockedPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                        f.write_str("<locked>")
                    }
                }

                f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
            }
        }
    }
}

impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
    fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> {
        ReentrantMutexGuard { __lock: lock }
    }
}

impl<T> Deref for ReentrantMutexGuard<'_, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.__lock.data
    }
}

impl<T> Drop for ReentrantMutexGuard<'_, T> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.__lock.inner.unlock();
        }
    }
}
<commit_msg>Remove workaround for deref issue that no longer exists.<commit_after>#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;

use crate::fmt;
use crate::marker;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::mutex as sys;

/// A re-entrant mutual exclusion
///
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
    inner: sys::ReentrantMutex,
    data: T,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

impl<T> UnwindSafe for ReentrantMutex<T> {}
impl<T> RefUnwindSafe for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// Deref implementation.
///
/// # Mutability
///
/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
/// because implementation of the trait would violate Rust’s reference aliasing
/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
/// guarded data.
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ReentrantMutexGuard<'a, T: 'a> {
    lock: &'a ReentrantMutex<T>,
}

impl<T> !marker::Send for ReentrantMutexGuard<'_, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe because it is required that `init` is called
    /// once this mutex is in its final resting place, and only then are the
    /// lock/unlock methods safe.
    pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
        ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
    }

    /// Initializes this mutex so it's ready for use.
    ///
    /// # Unsafety
    ///
    /// Unsafe to call more than once, and must be called after this will no
    /// longer move in memory.
    pub unsafe fn init(&self) {
        self.inner.init();
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the caller until it is available to acquire the mutex.
    /// Upon returning, the thread is the only thread with the mutex held. When the thread
    /// calling this method already holds the lock, the call shall succeed without
    /// blocking.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
        unsafe { self.inner.lock() }
        ReentrantMutexGuard::new(&self)
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned.
    ///
    /// This function does not block.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
        if unsafe { self.inner.try_lock() } { Some(ReentrantMutexGuard::new(&self)) } else { None }
    }
}

impl<T> Drop for ReentrantMutex<T> {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.inner.destroy() }
    }
}

impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
            None => {
                struct LockedPlaceholder;
                impl fmt::Debug for LockedPlaceholder {
                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                        f.write_str("<locked>")
                    }
                }

                f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
            }
        }
    }
}

impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
    fn new(lock: &'mutex ReentrantMutex<T>) -> ReentrantMutexGuard<'mutex, T> {
        ReentrantMutexGuard { lock }
    }
}

impl<T> Deref for ReentrantMutexGuard<'_, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.lock.data
    }
}

impl<T> Drop for ReentrantMutexGuard<'_, T> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.lock.inner.unlock();
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int};

pub const IUP_NOERROR: c_int = 0;

pub enum Ihandle {}

extern {
    pub fn IupOpen(argc: *const c_int, argv: *const *const *const c_char) -> c_int;
    pub fn IupShow(ih: *mut Ihandle) -> c_int;
    pub fn IupMainLoop() -> c_int;
    pub fn IupClose();
    pub fn IupLabel(title: *const c_char) -> *mut Ihandle;
    pub fn IupDialog(ih: *mut Ihandle) -> *mut Ihandle;
}
<commit_msg>add rest of iup.h to lib.rs<commit_after>//! Rust low level bindings for (IUP)[1] -- A Portable User Interface Toolkit
//!
//! [1]: http://www.tecgraf.puc-rio.br/iup/

// iup.h

// #include "iupkey.h"
// #include "iupdef.h"

extern crate libc;

use libc::{c_char, c_uchar, c_int, c_float, c_double, c_void};
use std::ffi::CString;

pub const IUP_NAME: &'static str         = "IUP - Portable User Interface";
pub const IUP_COPYRIGHT: &'static str    = "Copyright (C) 1994-2014 Tecgraf, PUC-Rio.";
pub const IUP_DESCRIPTION: &'static str  = "Multi-platform toolkit for building graphical user interfaces.";
pub const IUP_VERSION: &'static str      = "3.12"; /* bug fixes are reported only by IupVersion functions */
pub const IUP_VERSION_NUMBER: c_int      = 312000;
pub const IUP_VERSION_DATE: &'static str = "2014/11/19"; /* does not include bug fix releases */

pub enum Ihandle {}
pub type Icallback = Option<extern fn(ih: *mut Ihandle) -> c_int>;
pub type Iparamcb = Option<extern fn (dialog: *mut Ihandle, param_index: c_int, user_data: *mut c_void) -> c_int>;

extern {
    /************************************************************************/
    /*                        Main API                                      */
    /************************************************************************/
    pub fn IupOpen(argc: *const c_int, argv: *const *const *const c_char) -> c_int;
    pub fn IupClose();
    pub fn IupImageLibOpen();

    pub fn IupMainLoop() -> c_int;
    pub fn IupLoopStep() -> c_int;
    pub fn IupLoopStepWait() -> c_int;
    pub fn IupMainLoopLevel() -> c_int;
    pub fn IupFlush();
    pub fn IupExitLoop();

    pub fn IupRecordInput(filename: *const c_char, mode: c_int) -> c_int;
    pub fn IupPlayInput(filename: *const c_char) -> c_int;

    pub fn IupUpdate(ih: *mut Ihandle);
    pub fn IupUpdateChildren(ih: *mut Ihandle);
    pub fn IupRedraw(ih: *mut Ihandle, children: c_int);
    pub fn IupRefresh(ih: *mut Ihandle);
    pub fn IupRefreshChildren(ih: *mut Ihandle);

    pub fn IupHelp(url: *const c_char) -> c_int;
    pub fn IupLoad(filename: *const c_char) -> *mut c_char;
    pub fn IupLoadBuffer(buffer: *const c_char) -> *mut c_char;

    pub fn IupVersion() -> *mut c_char;
    pub fn IupVersionDate() -> *mut c_char;
    pub fn IupVersionNumber() -> c_int;

    pub fn IupSetLanguage(lng: *const c_char);
    pub fn IupGetLanguage() -> *mut c_char;
    pub fn IupSetLanguageString(name: *const c_char, str: *const c_char);
    pub fn IupStoreLanguageString(name: *const c_char, str: *const c_char);
    pub fn IupGetLanguageString(name: *const c_char) -> *mut c_char;
    pub fn IupSetLanguagePack(ih: *mut Ihandle);

    pub fn IupDestroy(ih: *mut Ihandle);
    pub fn IupDetach(child: *mut Ihandle);
    pub fn IupAppend(ih: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupInsert(ih: *mut Ihandle, ref_child: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetChild(ih: *mut Ihandle, pos: c_int) -> *mut Ihandle;
    pub fn IupGetChildPos(ih: *mut Ihandle, child: *mut Ihandle) -> c_int;
    pub fn IupGetChildCount(ih: *mut Ihandle) -> c_int;
    pub fn IupGetNextChild(ih: *mut Ihandle, child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetBrother(ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetParent(ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetDialog(ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetDialogChild(ih: *mut Ihandle, name: *const c_char) -> *mut Ihandle;
    pub fn IupReparent(ih: *mut Ihandle, new_parent: *mut Ihandle, ref_child: *mut Ihandle) -> c_int;

    pub fn IupPopup(ih: *mut Ihandle, x: c_int, y: c_int) -> c_int;
    pub fn IupShow(ih: *mut Ihandle) -> c_int;
    pub fn IupShowXY(ih: *mut Ihandle, x: c_int, y: c_int) -> c_int;
    pub fn IupHide(ih: *mut Ihandle) -> c_int;
    pub fn IupMap(ih: *mut Ihandle) -> c_int;
    pub fn IupUnmap(ih: *mut Ihandle);

    pub fn IupResetAttribute(ih: *mut Ihandle, name: *const c_char);
    pub fn IupGetAllAttributes(ih: *mut Ihandle, names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupSetAtt(handle_name: *const c_char, ih: *mut Ihandle, name: *const c_char, ...) -> *mut Ihandle;
    pub fn IupSetAttributes(ih: *mut Ihandle, str: *const c_char) -> *mut Ihandle;
    pub fn IupGetAttributes(ih: *mut Ihandle) -> *mut c_char;

    pub fn IupSetAttribute(ih: *mut Ihandle, name: *const c_char, value: *const c_char);
    pub fn IupSetStrAttribute(ih: *mut Ihandle, name: *const c_char, value: *const c_char);
    pub fn IupSetStrf(ih: *mut Ihandle, name: *const c_char, format: *const c_char, ...);
    pub fn IupSetInt(ih: *mut Ihandle, name: *const c_char, value: c_int);
    pub fn IupSetFloat(ih: *mut Ihandle, name: *const c_char, value: c_float);
    pub fn IupSetDouble(ih: *mut Ihandle, name: *const c_char, value: c_double);
    pub fn IupSetRGB(ih: *mut Ihandle, name: *const c_char, r: c_uchar, g: c_uchar, b: c_uchar);

    pub fn IupGetAttribute(ih: *mut Ihandle, name: *const c_char) -> *mut c_char;
    pub fn IupGetInt(ih: *mut Ihandle, name: *const c_char) -> c_int;
    pub fn IupGetInt2(ih: *mut Ihandle, name: *const c_char) -> c_int;
    pub fn IupGetIntInt(ih: *mut Ihandle, name: *const c_char, i1: *mut c_int, i2: *mut c_int) -> c_int;
    pub fn IupGetFloat(ih: *mut Ihandle, name: *const c_char) -> c_float;
    pub fn IupGetDouble(ih: *mut Ihandle, name: *const c_char) -> c_double;
    pub fn IupGetRGB(ih: *mut Ihandle, name: *const c_char, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);
    pub fn IupSetAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: *const c_char);
    pub fn IupSetStrAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: *const c_char);
    pub fn IupSetStrfId(ih: *mut Ihandle, name: *const c_char, id: c_int, format: *const c_char, ...);
    pub fn IupSetIntId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_int);
    pub fn IupSetFloatId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_float);
    pub fn IupSetDoubleId(ih: *mut Ihandle, name: *const c_char, id: c_int, value: c_double);
    pub fn IupSetRGBId(ih: *mut Ihandle, name: *const c_char, id: c_int, r: c_uchar, g: c_uchar, b: c_uchar);

    pub fn IupGetAttributeId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> *mut c_char;
    pub fn IupGetIntId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_int;
    pub fn IupGetFloatId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_float;
    pub fn IupGetDoubleId(ih: *mut Ihandle, name: *const c_char, id: c_int) -> c_double;
    pub fn IupGetRGBId(ih: *mut Ihandle, name: *const c_char, id: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);

    pub fn IupSetAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: *const c_char);
    pub fn IupSetStrAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: *const c_char);
    pub fn IupSetStrfId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, format: *const c_char, ...);
    pub fn IupSetIntId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_int);
    pub fn IupSetFloatId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_float);
    pub fn IupSetDoubleId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, value: c_double);
    pub fn IupSetRGBId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, r: c_uchar, g: c_uchar, b: c_uchar);

    pub fn IupGetAttributeId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> *mut c_char;
    pub fn IupGetIntId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_int;
    pub fn IupGetFloatId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_float;
    pub fn IupGetDoubleId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int) -> c_double;
    pub fn IupGetRGBId2(ih: *mut Ihandle, name: *const c_char, lin: c_int, col: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar);

    pub fn IupSetGlobal(name: *const c_char, value: *const c_char);
    pub fn IupSetStrGlobal(name: *const c_char, value: *const c_char);
    pub fn IupGetGlobal(name: *const c_char) -> *mut c_char;

    pub fn IupSetFocus(ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetFocus() -> *mut Ihandle;
    pub fn IupPreviousField(ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupNextField(ih: *mut Ihandle) -> *mut Ihandle;

    pub fn IupGetCallback(ih: *mut Ihandle, name: *const c_char) -> Icallback;
    pub fn IupSetCallback(ih: *mut Ihandle, name: *const c_char, func: Icallback) -> Icallback;
    pub fn IupSetCallbacks(ih: *mut Ihandle, name: *const c_char, func: Icallback, ...) -> *mut Ihandle;

    pub fn IupGetFunction(name: *const c_char) -> Icallback;
    pub fn IupSetFunction(name: *const c_char, func: Icallback) -> Icallback;

    pub fn IupGetHandle(name: *const c_char) -> *mut Ihandle;
    pub fn IupSetHandle(name: *const c_char, ih: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGetAllNames(names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupGetAllDialogs(names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupGetName(ih: *mut Ihandle) -> *mut c_char;

    pub fn IupSetAttributeHandle(ih: *mut Ihandle, name: *const c_char, ih_named: *mut Ihandle);
    pub fn IupGetAttributeHandle(ih: *mut Ihandle, name: *const c_char) -> *mut Ihandle;

    pub fn IupGetClassName(ih: *mut Ihandle) -> *mut c_char;
    pub fn IupGetClassType(ih: *mut Ihandle) -> *mut c_char;
    pub fn IupGetAllClasses(names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupGetClassAttributes(classname: *const c_char, names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupGetClassCallbacks(classname: *const c_char, names: *mut *mut c_char, n: c_int) -> c_int;
    pub fn IupSaveClassAttributes(ih: *mut Ihandle);
    pub fn IupCopyClassAttributes(src_ih: *mut Ihandle, dst_ih: *mut Ihandle);
    pub fn IupSetClassDefaultAttribute(classname: *const c_char, name: *const c_char, value: *const c_char);
    pub fn IupClassMatch(ih: *mut Ihandle, classname: *const c_char) -> c_int;

    pub fn IupCreate(classname: *const c_char) -> *mut Ihandle;
    pub fn IupCreatev(classname: *const c_char, params: *mut *mut c_void) -> *mut Ihandle;
    pub fn IupCreatep(classname: *const c_char, first: *mut c_void, ...) -> *mut Ihandle;

    /************************************************************************/
    /*                        Elements                                      */
    /************************************************************************/
    pub fn IupFill() -> *mut Ihandle;
    pub fn IupRadio(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupVbox(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupVboxv(children: *mut *mut Ihandle) -> *mut Ihandle;
    pub fn IupZbox(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupZboxv(children: *mut *mut Ihandle) -> *mut Ihandle;
    pub fn IupHbox(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupHboxv(children: *mut *mut Ihandle) -> *mut Ihandle;

    pub fn IupNormalizer(ih_first: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupNormalizerv(ih_list: *mut *mut Ihandle) -> *mut Ihandle;

    pub fn IupCbox(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupCboxv(children: *mut *mut Ihandle) -> *mut Ihandle;
    pub fn IupSbox(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupSplit(child1: *mut Ihandle, child2: *mut Ihandle) -> *mut Ihandle;
    pub fn IupScrollBox(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupGridBox(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupGridBoxv(children: *mut *mut Ihandle) -> *mut Ihandle;
    pub fn IupExpander(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupDetachBox(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupBackgroundBox(child: *mut Ihandle) -> *mut Ihandle;

    pub fn IupFrame(child: *mut Ihandle) -> *mut Ihandle;

    pub fn IupImage(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;
    pub fn IupImageRGB(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;
    pub fn IupImageRGBA(width: c_int, height: c_int, pixmap: *const c_uchar) -> *mut Ihandle;

    pub fn IupItem(title: *const c_char, action: *const c_char) -> *mut Ihandle;
    pub fn IupSubmenu(title: *const c_char, child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupSeparator() -> *mut Ihandle;
    pub fn IupMenu(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupMenuv(children: *mut *mut Ihandle) -> *mut Ihandle;

    pub fn IupButton(title: *const c_char, action: *const c_char) -> *mut Ihandle;
    pub fn IupCanvas(action: *const c_char) -> *mut Ihandle;
    pub fn IupDialog(child: *mut Ihandle) -> *mut Ihandle;
    pub fn IupUser() -> *mut Ihandle;
    pub fn IupLabel(title: *const c_char) -> *mut Ihandle;
    pub fn IupList(action: *const c_char) -> *mut Ihandle;
    pub fn IupText(action: *const c_char) -> *mut Ihandle;
    pub fn IupMultiLine(action: *const c_char) -> *mut Ihandle;
    pub fn IupToggle(title: *const c_char, action: *const c_char) -> *mut Ihandle;
    pub fn IupTimer() -> *mut Ihandle;
    pub fn IupClipboard() -> *mut Ihandle;
    pub fn IupProgressBar() -> *mut Ihandle;
    pub fn IupVal(_type: *const c_char) -> *mut Ihandle;
    pub fn IupTabs(child: *mut Ihandle, ...) -> *mut Ihandle;
    pub fn IupTabsv(children: *mut *mut Ihandle) -> *mut Ihandle;
    pub fn IupTree() -> *mut Ihandle;
    pub fn IupLink(url: *const c_char, title: *const c_char) -> *mut Ihandle;

    /************************************************************************/
    /*                      Utilities                                       */
    /************************************************************************/

    /* IupImage utility */
    pub fn IupSaveImageAsText(ih: *mut Ihandle, file_name: *const c_char, format: *const c_char, name: *const c_char) -> c_int;

    /* IupText and IupScintilla utilities */
    pub fn IupTextConvertLinColToPos(ih: *mut Ihandle, lin: c_int, col: c_int, pos: *mut c_int);
    pub fn IupTextConvertPosToLinCol(ih: *mut Ihandle, pos: c_int, lin: *mut c_int, col: *mut c_int);

    /* IupTree utilities */
    pub fn IupTreeSetUserId(ih: *mut Ihandle, id: c_int, userid: *mut c_void) -> c_int;
    pub fn IupTreeGetUserId(ih: *mut Ihandle, id: c_int) -> *mut c_void;
    pub fn IupTreeGetId(ih: *mut Ihandle, userid: *mut c_void) -> c_int;
    pub fn IupTreeSetAttributeHandle(ih: *mut Ihandle, name: *const c_char, id: c_int, ih_named: *mut Ihandle);

    /************************************************************************/
    /*                      Pre-definided dialogs                           */
    /************************************************************************/
    pub fn IupFileDlg() -> *mut Ihandle;
    pub fn IupMessageDlg() -> *mut Ihandle;
    pub fn IupColorDlg() -> *mut Ihandle;
    pub fn IupFontDlg() -> *mut Ihandle;
    pub fn IupProgressDlg() -> *mut Ihandle;

    pub fn IupGetFile(arq: *mut c_char) -> c_int;
    pub fn IupMessage(title: *const c_char, msg: *const c_char);
    pub fn IupMessagef(title: *const c_char, format: *const c_char, ...);
    pub fn IupAlarm(title: *const c_char, msg: *const c_char, b1: *const c_char, b2: *const c_char, b3: *const c_char) -> c_int;
    pub fn IupScanf(format: *const c_char, ...) -> c_int;
    pub fn IupListDialog(_type: c_int, title: *const c_char, size: c_int, list: *mut *const c_char, op: c_int, max_col: c_int, max_lin: c_int, marks: *mut c_int) -> c_int;
    pub fn IupGetText(title: *const c_char, text: *mut c_char) -> c_int;
    pub fn IupGetColor(x: c_int, y: c_int, r: *mut c_uchar, g: *mut c_uchar, b: *mut c_uchar) -> c_int;

    pub fn IupGetParam(title: *const c_char, action: Iparamcb, user_data: *mut c_void, format: *const c_char, ...) -> c_int;
    pub fn IupGetParamv(title: *const c_char, action: Iparamcb, user_data: *mut c_void, format: *const c_char, param_count: c_int, param_extra: c_int, param_data: *mut *mut c_void) -> c_int;

    pub fn IupLayoutDialog(dialog: *mut Ihandle) -> *mut Ihandle;
    pub fn IupElementPropertiesDialog(elem: *mut Ihandle) -> *mut Ihandle;
}

/************************************************************************/
/*                   Common Flags and Return Values                     */
/************************************************************************/
pub const IUP_ERROR: c_int      = 1;
pub const IUP_NOERROR: c_int    = 0;
pub const IUP_OPENED: c_int     = -1;
pub const IUP_INVALID: c_int    = -1;
pub const IUP_INVALID_ID: c_int = -10;

/************************************************************************/
/*                   Callback Return Values                             */
/************************************************************************/
pub const IUP_IGNORE: c_int   = -1;
pub const IUP_DEFAULT: c_int  = -2;
pub const IUP_CLOSE: c_int    = -3;
pub const IUP_CONTINUE: c_int = -4;

/************************************************************************/
/*           IupPopup and IupShowXY Parameter Values                    */
/************************************************************************/
pub const IUP_CENTER: c_int       = 0xFFFF;  /* 65535 */
pub const IUP_LEFT: c_int         = 0xFFFE;  /* 65534 */
pub const IUP_RIGHT: c_int        = 0xFFFD;  /* 65533 */
pub const IUP_MOUSEPOS: c_int     = 0xFFFC;  /* 65532 */
pub const IUP_CURRENT: c_int      = 0xFFFB;  /* 65531 */
pub const IUP_CENTERPARENT: c_int = 0xFFFA;  /* 65530 */
pub const IUP_TOP: c_int          = IUP_LEFT;
pub const IUP_BOTTOM: c_int       = IUP_RIGHT;

/************************************************************************/
/*               SHOW_CB Callback Values                                */
/************************************************************************/
pub const IUP_SHOW: c_int     = 0;
pub const IUP_RESTORE: c_int  = 1;
pub const IUP_MINIMIZE: c_int = 2;
pub const IUP_MAXIMIZE: c_int = 3;
pub const IUP_HIDE: c_int     = 4;

/************************************************************************/
/*               SCROLL_CB Callback Values                              */
/************************************************************************/
pub const IUP_SBUP: c_int      =  0;
pub const IUP_SBDN: c_int      =  1;
pub const IUP_SBPGUP: c_int    =  2;
pub const IUP_SBPGDN: c_int    =  3;
pub const IUP_SBPOSV: c_int    =  4;
pub const IUP_SBDRAGV: c_int   =  5;
pub const IUP_SBLEFT: c_int    =  6;
pub const IUP_SBRIGHT: c_int   =  7;
pub const IUP_SBPGLEFT: c_int  =  8;
pub const IUP_SBPGRIGHT: c_int =  9;
pub const IUP_SBPOSH: c_int    = 10;
pub const IUP_SBDRAGH: c_int   = 11;

/************************************************************************/
/*               Mouse Button Values and Functions                      */
/************************************************************************/
pub const IUP_BUTTON1: c_char = '1' as c_char;
pub const IUP_BUTTON2: c_char = '2' as c_char;
pub const IUP_BUTTON3: c_char = '3' as c_char;
pub const IUP_BUTTON4: c_char = '4' as c_char;
pub const IUP_BUTTON5: c_char = '5' as c_char;

pub fn iup_isshift(s: CString) -> bool   { s[0] == 'S' as c_char }
pub fn iup_iscontrol(s: CString) -> bool { s[1] == 'C' as c_char }
pub fn iup_isbutton1(s: CString) -> bool { s[2] == '1' as c_char }
pub fn iup_isbutton2(s: CString) -> bool { s[3] == '2' as c_char }
pub fn iup_isbutton3(s: CString) -> bool { s[4] == '3' as c_char }
pub fn iup_isdouble(s: CString) -> bool  { s[5] == 'D' as c_char }
pub fn iup_isalt(s: CString) -> bool     { s[6] == 'A' as c_char }
pub fn iup_issys(s: CString) -> bool     { s[7] == 'Y' as c_char }
pub fn iup_isbutton4(s: CString) -> bool { s[8] == '4' as c_char }
pub fn iup_isbutton5(s: CString) -> bool { s[9] == '5' as c_char }

/************************************************************************/
/*                      Pre-Defined Masks                               */
/************************************************************************/
pub const IUP_MASK_FLOAT: &'static str  = "[+/-]?(/d+/.?/d*|/./d+)";
pub const IUP_MASK_UFLOAT: &'static str = "(/d+/.?/d*|/./d+)";
pub const IUP_MASK_EFLOAT: &'static str = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?";
pub const IUP_MASK_INT: &'static str    = "[+/-]?/d+";
pub const IUP_MASK_UINT: &'static str   = "/d+";

/************************************************************************/
/*                   IupGetParam Callback situations                    */
/************************************************************************/
pub const IUP_GETPARAM_OK: c_int     = -1;
pub const IUP_GETPARAM_INIT: c_int   = -2;
pub const IUP_GETPARAM_CANCEL: c_int = -3;
pub const IUP_GETPARAM_HELP: c_int   = -4;

/************************************************************************/
/*                   Record Input Modes                                 */
/************************************************************************/
pub const IUP_RECBINARY: c_int = 0;
pub const IUP_RECTEXT: c_int = 1;
<|endoftext|>


<commit_before>use crate::util::lossy_channel::{lossy_channel, LossyReceiver, LossySender};
use crossbeam::channel::{unbounded, Receiver, Sender};
use std::collections::VecDeque;
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

pub fn fork<T: Write + Send + 'static>(queue_size: usize) -> (TargetList<T>, DataStream) {
    let (streams_sender, streams) = unbounded();
    let (data_sender, data) = lossy_channel(queue_size);
    let target_count = Arc::new(AtomicUsize::new(0));
    let target_count_thread = Arc::clone(&target_count);
    thread::spawn(move || fork_thread::<T>(&streams, &data, &target_count_thread));
    (
        TargetList(streams_sender),
        DataStream {
            sender: data_sender,
            target_count,
        },
    )
}

fn fill_with_queued<T>(data: &LossyReceiver<T>, queue: &mut VecDeque<T>) -> bool {
    if queue.is_empty() {
        match data.recv() {
            Err(_) | Ok(None) => return false,
            Ok(Some(value)) => queue.push_front(value),
        };
    }
    while let Ok(item) = data.try_recv() {
        match item {
            Some(value) => queue.push_front(value),
            None => return false,
        }
    }
    true
}

fn fork_thread<T: Write + Send + 'static>(
    streams: &Receiver<T>,
    data: &LossyReceiver<Arc<Vec<u8>>>,
    target_count: &AtomicUsize,
) {
    let mut targets = Vec::new();
    let mut datapoints = VecDeque::new();
    let mut sender_is_open = true;
    while sender_is_open {
        sender_is_open = fill_with_queued(data, &mut datapoints);

        let buffer = match datapoints.pop_back() {
            Some(v) => v,
            None => continue,
        };
        while let Ok(target) = streams.try_recv() {
            targets.push(target);
        }
        targets = targets
            .into_iter()
            .filter_map(|mut target| match target.write_all(&buffer) {
                Ok(()) => Some(target),
                Err(_) => None,
            })
            .collect();
        // It's not extremely important that the count is correct at every moment,
        // so the ordering is relaxed.
        // Getting this wrong for a very short amount of time should make no problems.
        target_count.store(targets.len(), Ordering::Relaxed);
    }
}

pub type ForkResult = Result<(), ()>;

pub struct TargetList<T: Write + Send + 'static>(Sender<T>);

impl<T: Write + Send + 'static> TargetList<T> {
    pub fn add(&self, stream: T) -> ForkResult {
        self.0.send(stream).or(Err(()))
    }
}

#[derive(Clone)]
pub struct DataStream {
    sender: LossySender<Arc<Vec<u8>>>,
    target_count: Arc<AtomicUsize>,
}

impl DataStream {
    pub fn send(&self, data: Arc<Vec<u8>>) -> ForkResult {
        self.sender.try_send(data).or(Err(()))
    }

    #[inline]
    pub fn get_target_count(&self) -> usize {
        self.target_count.load(Ordering::Relaxed)
    }

    #[inline]
    pub fn set_queue_size(&self, queue_size: usize) {
        self.sender.set_queue_size(queue_size);
    }

    #[inline]
    pub fn set_queue_size_max(&self, queue_size: usize) {
        self.sender.set_queue_size_max(queue_size);
    }
}
<commit_msg>Fix subscriber count tracking for publishers<commit_after>use crate::util::lossy_channel::{lossy_channel, LossyReceiver, LossySender};
use crossbeam::channel::{self, unbounded, Receiver, Sender};
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

pub fn fork<T: Write + Send + 'static>(queue_size: usize) -> (TargetList<T>, DataStream) {
    let (streams_sender, streams) = unbounded();
    let (data_sender, data) = lossy_channel(queue_size);

    let mut fork_thread = ForkThread::new();
    let target_count = fork_thread.clone_target_count();

    thread::spawn(move || fork_thread.run(&streams, &data));

    (
        TargetList(streams_sender),
        DataStream {
            sender: data_sender,
            target_count,
        },
    )
}

struct ForkThread<T: Write + Send + 'static> {
    targets: Vec<T>,
    target_count: Arc<AtomicUsize>,
}

impl<T: Write + Send + 'static> ForkThread<T> {
    pub fn new() -> Self {
        Self {
            targets: vec![],
            target_count: Arc::new(AtomicUsize::new(0)),
        }
    }

    pub fn clone_target_count(&self) -> Arc<AtomicUsize> {
        Arc::clone(&self.target_count)
    }

    fn publish_buffer_and_prune_targets(&mut self, buffer: &[u8]) {
        let mut dropped_targets = vec![];
        for (idx, target) in self.targets.iter_mut().enumerate() {
            if target.write_all(&buffer).is_err() {
                dropped_targets.push(idx);
            }
        }

        if !dropped_targets.is_empty() {
            // We reverse the order, to remove bigger indices first.
            for idx in dropped_targets.into_iter().rev() {
                self.targets.swap_remove(idx);
            }

            self.target_count
                .store(self.targets.len(), Ordering::SeqCst);
        }
    }

    fn add_target(&mut self, target: T) {
        self.targets.push(target);
        self.target_count
            .store(self.targets.len(), Ordering::SeqCst);
    }

    fn step(
        &mut self,
        streams: &Receiver<T>,
        data: &LossyReceiver<Arc<Vec<u8>>>,
    ) -> Result<(), channel::RecvError> {
        channel::select! {
            recv(data) -> msg => {
                let buffer = msg?.ok_or(channel::RecvError)?;
                self.publish_buffer_and_prune_targets(&buffer);
            }
            recv(streams) -> target => {
                self.add_target(target?);
            }
        }
        Ok(())
    }

    pub fn run(&mut self, streams: &Receiver<T>, data: &LossyReceiver<Arc<Vec<u8>>>) {
        while self.step(streams, data).is_ok() {}
    }
}

pub type ForkResult = Result<(), ()>;

pub struct TargetList<T: Write + Send + 'static>(Sender<T>);

impl<T: Write + Send + 'static> TargetList<T> {
    pub fn add(&self, stream: T) -> ForkResult {
        self.0.send(stream).or(Err(()))
    }
}

#[derive(Clone)]
pub struct DataStream {
    sender: LossySender<Arc<Vec<u8>>>,
    target_count: Arc<AtomicUsize>,
}

impl DataStream {
    pub fn send(&self, data: Arc<Vec<u8>>) -> ForkResult {
        self.sender.try_send(data).or(Err(()))
    }

    #[inline]
    pub fn get_target_count(&self) -> usize {
        self.target_count.load(Ordering::SeqCst)
    }

    #[inline]
    pub fn set_queue_size(&self, queue_size: usize) {
        self.sender.set_queue_size(queue_size);
    }

    #[inline]
    pub fn set_queue_size_max(&self, queue_size: usize) {
        self.sender.set_queue_size_max(queue_size);
    }
}
<|endoftext|>


<commit_before>//https://rust-lang.github.io/book/ch04-04-slices.html

fn first_word(s: &String) -> usize {

    // Since we need to go through the String element by element, and
    // check if a value is a space, we will convert our String to an
    // array of bytes, using the `.as_bytes()` method.
    let bytes = s.as_bytes();

    // We discussed using the iter() method with for in Chapter 3.7. Here,
    // we’re adding another method: enumerate(). While iter() returns each
    // element, enumerate() modifies the result of iter(), and returns a
    // tuple instead. The first element of the tuple is the index, and the
    // second element is a reference to the element itself. This is a bit
    // nicer than calculating the index ourselves.
    //
    // Since it’s a tuple, we can use patterns, just like elsewhere in Rust.
    // So we match against the tuple with i for the index, and &byte for
    // the byte itself.
    for (i, &byte) in bytes.iter().enumerate() {

        println!("Processing {} {}",i,byte);
        // 32 is the value of a space in UTF-8
        if byte == 0x20 {

            // We found a space! Return this position.
            return i;
        }
    }

    // If we got here, we didn’t find a space, so this whole thing must be a
    // word. So return the length.
    s.len()
}

fn main() {
    //ok, apparently 0x20 isn't part of any unicode char seen as utf-8 as far as i tested until
    //here(not all):
    //http://www.utf8-chartable.de/unicode-utf8-table.pl?start=121856&number=1024&utf8=0x
    //about to search here next(as soon as internet is back):
    //http://www.fileformat.info/search/search.htm?q=0x20
    //ok this explains it: http://www.joelonsoftware.com/articles/Unicode.html
    //since high bits are always at least 10, there won't be any 0x20 dangling around as part of
    //the utf8 represented unicode - except 0x20 itself :D
    let s=String::from("Ԡ123԰4Ġ");
    let word = first_word(&s);
    // word is now totally invalid! There’s no more word here.
    println!("{}",word);
}
<commit_msg>experimenting with chars<commit_after>//https://rust-lang.github.io/book/ch04-04-slices.html

fn first_word(s: &String) -> usize {

    // Since we need to go through the String element by element, and
    // check if a value is a space, we will convert our String to an
    // array of bytes, using the `.as_bytes()` method.
    let bytes = s.as_bytes();

    // We discussed using the iter() method with for in Chapter 3.7. Here,
    // we’re adding another method: enumerate(). While iter() returns each
    // element, enumerate() modifies the result of iter(), and returns a
    // tuple instead. The first element of the tuple is the index, and the
    // second element is a reference to the element itself. This is a bit
    // nicer than calculating the index ourselves.
    //
    // Since it’s a tuple, we can use patterns, just like elsewhere in Rust.
    // So we match against the tuple with i for the index, and &byte for
    // the byte itself.
    //for (i, &byte) in bytes.iter().enumerate() {
    for (i, chr) in s.chars().enumerate() {

        //println!("Processing {} {}",i,byte);
        println!("Processing {} {}",i,chr);
        // 32 is the value of a space in UTF-8
        //if chr == 0x20 {
        if chr == '\u{0020}' {

            // We found a space! Return this position.
            return i;
        }
    }

    // If we got here, we didn’t find a space, so this whole thing must be a
    // word. So return the length.
    s.len()
}

fn main() {
    //ok, apparently 0x20 isn't part of any unicode char seen as utf-8 as far as i tested until
    //here(not all):
    //http://www.utf8-chartable.de/unicode-utf8-table.pl?start=121856&number=1024&utf8=0x
    //about to search here next(as soon as internet is back):
    //http://www.fileformat.info/search/search.htm?q=0x20
    //ok this explains it: http://www.joelonsoftware.com/articles/Unicode.html
    //since high bits are always at least 10, there won't be any 0x20 dangling around as part of
    //the utf8 represented unicode - except 0x20 itself :D
    let s=String::from("Ԡ123԰4Ġ❤well");
    //❤ is two unicode code points which is why you'll see a blank after it!
    //src: https://doc.rust-lang.org/std/primitive.char.html
    let word = first_word(&s);
    // word is now totally invalid! There’s no more word here.
    println!("{}",word);
}
<|endoftext|>


<commit_before>use super::columndescription::ColumnDescription;

#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DataType {
    TBIT,
    TBYTE,
    TSBYTE,
    TLOGICAL,
    TSTRING,
    TUSHORT,
    TSHORT,
    TUINT,
    TINT,
    TULONG,
    TLONG,
    TLONGLONG,
    TFLOAT,
    TDOUBLE,
    TCOMPLEX,
    TDBLCOMPLEX,
}

macro_rules! datatype_into_impl {
    ($t: ty) => (
        impl From<DataType> for $t {
            fn from(original: DataType) -> $t {
                match original {
                    DataType::TBIT => 1,
                    DataType::TBYTE => 11,
                    DataType::TSBYTE => 12,
                    DataType::TLOGICAL => 14,
                    DataType::TSTRING => 16,
                    DataType::TUSHORT => 20,
                    DataType::TSHORT => 21,
                    DataType::TUINT => 30,
                    DataType::TINT => 31,
                    DataType::TULONG => 40,
                    DataType::TLONG => 41,
                    DataType::TLONGLONG => 81,
                    DataType::TFLOAT => 42,
                    DataType::TDOUBLE => 82,
                    DataType::TCOMPLEX => 83,
                    DataType::TDBLCOMPLEX => 163,
                }
            }
        }
    )
}

datatype_into_impl!(u8);
datatype_into_impl!(i32);
datatype_into_impl!(u32);
datatype_into_impl!(i64);
datatype_into_impl!(u64);

#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ImageType {
    BYTE_IMG,
    SHORT_IMG,
    LONG_IMG,
    LONGLONG_IMG,
    FLOAT_IMG,
    DOUBLE_IMG,
}

macro_rules! imagetype_into_impl {
    ($t: ty) => (
        impl From<ImageType> for $t {
            fn from(original: ImageType) -> $t {
                match original {
                    ImageType::BYTE_IMG => 8,
                    ImageType::SHORT_IMG => 16,
                    ImageType::LONG_IMG => 32,
                    ImageType::LONGLONG_IMG => 64,
                    ImageType::FLOAT_IMG => -32,
                    ImageType::DOUBLE_IMG => -64,
                }
            }
        }
        )
}

imagetype_into_impl!(i8);
imagetype_into_impl!(i32);
imagetype_into_impl!(i64);

/// Description of the current HDU
///
/// If the current HDU is an image, then
/// [`fetch_hdu_info`](struct.FitsFile.html#method.fetch_hdu_info) returns `HduInfo::ImageInfo`.
/// Otherwise the variant is `HduInfo::TableInfo`.
#[derive(Debug)]
pub enum HduInfo {
    ImageInfo { shape: Vec<usize> },
    TableInfo {
        column_descriptions: Vec<ColumnDescription>,
        num_rows: usize,
    },
    AnyInfo,
}

macro_rules! hduinfo_into_impl {
    ($t: ty) => (
        impl From<HduInfo> for $t {
            fn from(original: HduInfo) -> $t {
                match original {
                    HduInfo::ImageInfo { .. } => 0,
                    HduInfo::TableInfo { .. } => 2,
                    HduInfo::AnyInfo => -1,
                }
            }
        }
    )
}

hduinfo_into_impl!(i8);
hduinfo_into_impl!(i32);
hduinfo_into_impl!(i64);

#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub enum FileOpenMode {
    READONLY,
    READWRITE,
}

macro_rules! fileopenmode_into_impl {
    ($t: ty) => (
        impl From<FileOpenMode> for $t {
            fn from(original: FileOpenMode) -> $t {
                match original {
                    FileOpenMode::READONLY => 0,
                    FileOpenMode::READWRITE => 1,
                }
            }
        }
        )
}

fileopenmode_into_impl!(u8);
fileopenmode_into_impl!(u32);
fileopenmode_into_impl!(u64);
fileopenmode_into_impl!(i8);
fileopenmode_into_impl!(i32);
fileopenmode_into_impl!(i64);

#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub enum CaseSensitivity {
    CASEINSEN,
    CASESEN,
}

macro_rules! casesensitivity_into_impl {
    ($t: ty) => (
        impl From<CaseSensitivity> for $t {
            fn from(original: CaseSensitivity) -> $t {
                match original {
                    CaseSensitivity::CASEINSEN => 0,
                    CaseSensitivity::CASESEN => 1,
                }
            }
        }
        )
}

casesensitivity_into_impl!(u8);
casesensitivity_into_impl!(u32);
casesensitivity_into_impl!(u64);
casesensitivity_into_impl!(i8);
casesensitivity_into_impl!(i32);
casesensitivity_into_impl!(i64);

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

    #[test]
    fn image_types() {
        assert_eq!(i8::from(ImageType::BYTE_IMG), 8);
        assert_eq!(i8::from(ImageType::SHORT_IMG), 16);
        assert_eq!(i8::from(ImageType::LONG_IMG), 32);
        assert_eq!(i8::from(ImageType::LONGLONG_IMG), 64);
        assert_eq!(i8::from(ImageType::FLOAT_IMG), -32);
        assert_eq!(i8::from(ImageType::DOUBLE_IMG), -64);
    }

    #[test]
    fn file_open_modes() {
        assert_eq!(u8::from(FileOpenMode::READONLY), 0);
        assert_eq!(u8::from(FileOpenMode::READWRITE), 1);
    }

    #[test]
    fn case_sensitivity() {
        assert_eq!(u8::from(CaseSensitivity::CASESEN), 1);
        assert_eq!(u8::from(CaseSensitivity::CASEINSEN), 0);
    }

    #[test]
    fn converting_from_data_type() {
        assert_eq!(u8::from(DataType::TBIT), 1);
        assert_eq!(u8::from(DataType::TBYTE), 11);
        assert_eq!(u8::from(DataType::TLOGICAL), 14);
        assert_eq!(u8::from(DataType::TSTRING), 16);
        assert_eq!(u8::from(DataType::TSHORT), 21);
        assert_eq!(u8::from(DataType::TLONG), 41);
        assert_eq!(u8::from(DataType::TFLOAT), 42);
        assert_eq!(u8::from(DataType::TDOUBLE), 82);
    }

}
<commit_msg>Add test for HduInfo::From conversions<commit_after>use super::columndescription::ColumnDescription;

#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DataType {
    TBIT,
    TBYTE,
    TSBYTE,
    TLOGICAL,
    TSTRING,
    TUSHORT,
    TSHORT,
    TUINT,
    TINT,
    TULONG,
    TLONG,
    TLONGLONG,
    TFLOAT,
    TDOUBLE,
    TCOMPLEX,
    TDBLCOMPLEX,
}

macro_rules! datatype_into_impl {
    ($t: ty) => (
        impl From<DataType> for $t {
            fn from(original: DataType) -> $t {
                match original {
                    DataType::TBIT => 1,
                    DataType::TBYTE => 11,
                    DataType::TSBYTE => 12,
                    DataType::TLOGICAL => 14,
                    DataType::TSTRING => 16,
                    DataType::TUSHORT => 20,
                    DataType::TSHORT => 21,
                    DataType::TUINT => 30,
                    DataType::TINT => 31,
                    DataType::TULONG => 40,
                    DataType::TLONG => 41,
                    DataType::TLONGLONG => 81,
                    DataType::TFLOAT => 42,
                    DataType::TDOUBLE => 82,
                    DataType::TCOMPLEX => 83,
                    DataType::TDBLCOMPLEX => 163,
                }
            }
        }
    )
}

datatype_into_impl!(u8);
datatype_into_impl!(i32);
datatype_into_impl!(u32);
datatype_into_impl!(i64);
datatype_into_impl!(u64);

#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ImageType {
    BYTE_IMG,
    SHORT_IMG,
    LONG_IMG,
    LONGLONG_IMG,
    FLOAT_IMG,
    DOUBLE_IMG,
}

macro_rules! imagetype_into_impl {
    ($t: ty) => (
        impl From<ImageType> for $t {
            fn from(original: ImageType) -> $t {
                match original {
                    ImageType::BYTE_IMG => 8,
                    ImageType::SHORT_IMG => 16,
                    ImageType::LONG_IMG => 32,
                    ImageType::LONGLONG_IMG => 64,
                    ImageType::FLOAT_IMG => -32,
                    ImageType::DOUBLE_IMG => -64,
                }
            }
        }
        )
}

imagetype_into_impl!(i8);
imagetype_into_impl!(i32);
imagetype_into_impl!(i64);

/// Description of the current HDU
///
/// If the current HDU is an image, then
/// [`fetch_hdu_info`](struct.FitsFile.html#method.fetch_hdu_info) returns `HduInfo::ImageInfo`.
/// Otherwise the variant is `HduInfo::TableInfo`.
#[derive(Debug)]
pub enum HduInfo {
    ImageInfo { shape: Vec<usize> },
    TableInfo {
        column_descriptions: Vec<ColumnDescription>,
        num_rows: usize,
    },
    AnyInfo,
}

macro_rules! hduinfo_into_impl {
    ($t: ty) => (
        impl From<HduInfo> for $t {
            fn from(original: HduInfo) -> $t {
                match original {
                    HduInfo::ImageInfo { .. } => 0,
                    HduInfo::TableInfo { .. } => 2,
                    HduInfo::AnyInfo => -1,
                }
            }
        }
    )
}

hduinfo_into_impl!(i8);
hduinfo_into_impl!(i32);
hduinfo_into_impl!(i64);

#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub enum FileOpenMode {
    READONLY,
    READWRITE,
}

macro_rules! fileopenmode_into_impl {
    ($t: ty) => (
        impl From<FileOpenMode> for $t {
            fn from(original: FileOpenMode) -> $t {
                match original {
                    FileOpenMode::READONLY => 0,
                    FileOpenMode::READWRITE => 1,
                }
            }
        }
        )
}

fileopenmode_into_impl!(u8);
fileopenmode_into_impl!(u32);
fileopenmode_into_impl!(u64);
fileopenmode_into_impl!(i8);
fileopenmode_into_impl!(i32);
fileopenmode_into_impl!(i64);

#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub enum CaseSensitivity {
    CASEINSEN,
    CASESEN,
}

macro_rules! casesensitivity_into_impl {
    ($t: ty) => (
        impl From<CaseSensitivity> for $t {
            fn from(original: CaseSensitivity) -> $t {
                match original {
                    CaseSensitivity::CASEINSEN => 0,
                    CaseSensitivity::CASESEN => 1,
                }
            }
        }
        )
}

casesensitivity_into_impl!(u8);
casesensitivity_into_impl!(u32);
casesensitivity_into_impl!(u64);
casesensitivity_into_impl!(i8);
casesensitivity_into_impl!(i32);
casesensitivity_into_impl!(i64);

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

    #[test]
    fn image_types() {
        assert_eq!(i8::from(ImageType::BYTE_IMG), 8);
        assert_eq!(i8::from(ImageType::SHORT_IMG), 16);
        assert_eq!(i8::from(ImageType::LONG_IMG), 32);
        assert_eq!(i8::from(ImageType::LONGLONG_IMG), 64);
        assert_eq!(i8::from(ImageType::FLOAT_IMG), -32);
        assert_eq!(i8::from(ImageType::DOUBLE_IMG), -64);
    }

    #[test]
    fn hdu_types() {
        let image_info = HduInfo::ImageInfo { shape: Vec::new() };

        let table_info = HduInfo::TableInfo {
            column_descriptions: Vec::new(),
            num_rows: 0,
        };

        assert_eq!(i32::from(image_info), 0);
        assert_eq!(i32::from(table_info), 2);
        assert_eq!(i32::from(HduInfo::AnyInfo), -1);
    }

    #[test]
    fn file_open_modes() {
        assert_eq!(u8::from(FileOpenMode::READONLY), 0);
        assert_eq!(u8::from(FileOpenMode::READWRITE), 1);
    }

    #[test]
    fn case_sensitivity() {
        assert_eq!(u8::from(CaseSensitivity::CASESEN), 1);
        assert_eq!(u8::from(CaseSensitivity::CASEINSEN), 0);
    }

    #[test]
    fn converting_from_data_type() {
        assert_eq!(u8::from(DataType::TBIT), 1);
        assert_eq!(u8::from(DataType::TBYTE), 11);
        assert_eq!(u8::from(DataType::TLOGICAL), 14);
        assert_eq!(u8::from(DataType::TSTRING), 16);
        assert_eq!(u8::from(DataType::TSHORT), 21);
        assert_eq!(u8::from(DataType::TLONG), 41);
        assert_eq!(u8::from(DataType::TFLOAT), 42);
        assert_eq!(u8::from(DataType::TDOUBLE), 82);
    }

}
<|endoftext|>


<commit_before>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteSeek: Write + Seek {}

impl<T: Write + Seek> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<W: Write, WS: WriteSeek> {
    NonSeekable(W, u64),
    Seekable(WS),
}

impl<W: Write, WS: WriteSeek> Writer<W, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: W) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }
}

impl<W: Write, WS: WriteSeek> Write for Writer<W, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<W: Write, WS: WriteSeek> Seek for Writer<W, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<W: Write, WS: WriteSeek>(&mut self, out: &mut Writer<W, WS>) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<W: Write, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<W, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<W: Write, WS: WriteSeek>(&mut self, out: &mut Writer<W, WS>) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, W: Write, WS: WriteSeek> {
    muxer: M,
    writer: Writer<W, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, W: Write, WS: WriteSeek> Context<M, W, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<W, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<W, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}
<commit_msg>format: Add APIs to get the underlying buffer<commit_after>use crate::common::*;
use crate::data::packet::Packet;
use crate::data::value::*;
use std::any::Any;
use std::io::{ErrorKind, Seek, SeekFrom, Write};
use std::sync::Arc;

use crate::error::*;

pub trait WriteOwned: Write + ToOwned {}
pub trait WriteSeek: Write + Seek + ToOwned {}

impl<T: Write + ToOwned> WriteOwned for T {}
impl<T: Write + Seek + ToOwned> WriteSeek for T {}

/// Runtime wrapper around either a [`Write`] or a [`WriteSeek`] trait object which supports querying
/// for seek support.
pub enum Writer<WO: WriteOwned, WS: WriteSeek> {
    NonSeekable(WO, u64),
    Seekable(WS),
}

impl<WO: WriteOwned, WS: WriteSeek> Writer<WO, WS> {
    /// Creates a [`Writer`] from an object that implements both [`Write`] and [`Seek`] traits.
    pub fn from_seekable(inner: WS) -> Self {
        Self::Seekable(inner)
    }

    /// Creates a [`Writer`] from an object that implements the [`Write`] trait.
    pub fn from_nonseekable(inner: WO) -> Self {
        Self::NonSeekable(inner, 0)
    }

    /// Returns whether the [`Writer`] can seek within the source.
    pub fn can_seek(&self) -> bool {
        matches!(self, Self::Seekable(_))
    }

    /// Returns the non-seekable object whether is present.
    pub fn non_seekable_object(&self) -> Option<(<WO as ToOwned>::Owned, u64)> {
        if let Self::NonSeekable(inner, index) = self {
            Some((inner.to_owned(), *index))
        } else {
            None
        }
    }

    /// Returns the seekable object whether is present.
    pub fn seekable_object(&self) -> Option<<WS as ToOwned>::Owned> {
        if let Self::Seekable(inner) = self {
            Some(inner.to_owned())
        } else {
            None
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Write for Writer<WO, WS> {
    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
        match self {
            Self::NonSeekable(inner, ref mut index) => {
                let result = inner.write(bytes);

                if let Ok(written) = result {
                    *index += written as u64;
                }

                result
            }
            Self::Seekable(inner) => inner.write(bytes),
        }
    }

    fn flush(&mut self) -> std::io::Result<()> {
        match self {
            Self::NonSeekable(inner, ..) => inner.flush(),
            Self::Seekable(inner) => inner.flush(),
        }
    }
}

impl<WO: WriteOwned, WS: WriteSeek> Seek for Writer<WO, WS> {
    fn seek(&mut self, seek: SeekFrom) -> std::io::Result<u64> {
        match self {
            Self::NonSeekable(_, index) => {
                if let SeekFrom::Current(0) = seek {
                    Ok(*index)
                } else {
                    Err(std::io::Error::new(
                        ErrorKind::Other,
                        "Seeking not supported",
                    ))
                }
            }
            Self::Seekable(inner) => inner.seek(seek),
        }
    }
}

/// Used to implement muxing operations.
pub trait Muxer: Send {
    /// Configures a muxer.
    fn configure(&mut self) -> Result<()>;
    /// Writes a stream header into a data structure implementing
    /// the `Write` trait.
    fn write_header<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;
    /// Writes a stream packet into a data structure implementing
    /// the `Write` trait.
    fn write_packet<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
        pkt: Arc<Packet>,
    ) -> Result<()>;
    /// Writes a stream trailer into a data structure implementing
    /// the `Write` trait.
    fn write_trailer<WO: WriteOwned, WS: WriteSeek>(
        &mut self,
        out: &mut Writer<WO, WS>,
    ) -> Result<()>;

    /// Sets global media file information for a muxer.
    fn set_global_info(&mut self, info: GlobalInfo) -> Result<()>;
    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
}

/// Auxiliary structure to encapsulate a muxer object and
/// its additional data.
pub struct Context<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> {
    muxer: M,
    writer: Writer<WO, WS>,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Box<dyn Any + Send + Sync>>,
}

impl<M: Muxer + Send, WO: WriteOwned, WS: WriteSeek> Context<M, WO, WS> {
    /// Creates a new `Context` instance.
    pub fn new(muxer: M, writer: Writer<WO, WS>) -> Self {
        Context {
            muxer,
            writer,
            user_private: None,
        }
    }

    /// Configures a muxer.
    pub fn configure(&mut self) -> Result<()> {
        self.muxer.configure()
    }

    /// Writes a stream header to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_header(&mut self) -> Result<()> {
        self.muxer.write_header(&mut self.writer)
    }

    /// Writes a stream packet to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_packet(&mut self, pkt: Arc<Packet>) -> Result<()> {
        self.muxer.write_packet(&mut self.writer, pkt)
    }

    /// Writes a stream trailer to an internal buffer and returns how many
    /// bytes were written or an error.
    pub fn write_trailer(&mut self) -> Result<()> {
        self.muxer.write_trailer(&mut self.writer)?;
        self.writer.flush()?;

        Ok(())
    }

    /// Sets global media file information for a muxer.
    pub fn set_global_info(&mut self, info: GlobalInfo) -> Result<()> {
        self.muxer.set_global_info(info)
    }

    /// Sets a muxer option.
    ///
    /// This method should be called as many times as the number of options
    /// present in a muxer.
    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
    where
        V: Into<Value<'a>>,
    {
        self.muxer.set_option(key, val.into())
    }

    /// Returns the underlying writer.
    pub fn writer(&self) -> &Writer<WO, WS> {
        &self.writer
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own muxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Muxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new muxer.
pub trait Descriptor {
    type OutputMuxer: Muxer + Send;

    /// Creates a new muxer for the requested format.
    fn create(&self) -> Self::OutputMuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;
}

/// Used to look for a specific format.
pub trait Lookup<T: Descriptor + ?Sized> {
    /// Retrieves a specific format by name.
    fn by_name(&self, name: &str) -> Option<&'static T>;
}

impl<T: Descriptor + ?Sized> Lookup<T> for [&'static T] {
    fn by_name(&self, name: &str) -> Option<&'static T> {
        self.iter().find(|&&d| d.describe().name == name).copied()
    }
}
<|endoftext|>


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

//! This module crawls a `clean::Crate` and produces a summarization of the
//! stability levels within the crate. The summary contains the module
//! hierarchy, with item counts for every stability level per module. A parent
//! module's count includes its children's.

use std::ops::Add;
use std::num::Zero;

use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
use syntax::ast::Public;

use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum};
use clean::{ImplItem, Impl, Trait, TraitItem, TraitMethod, ProvidedMethod, RequiredMethod};
use clean::{TypeTraitItem, ViewItemItem, PrimitiveItem, Stability};

use html::render::cache_key;

#[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
/// The counts for each stability level.
pub struct Counts {
    pub deprecated: uint,
    pub experimental: uint,
    pub unstable: uint,
    pub stable: uint,
    pub frozen: uint,
    pub locked: uint,

    /// No stability level, inherited or otherwise.
    pub unmarked: uint,
}

impl Add<Counts, Counts> for Counts {
    fn add(&self, other: &Counts) -> Counts {
        Counts {
            deprecated:   self.deprecated   + other.deprecated,
            experimental: self.experimental + other.experimental,
            unstable:     self.unstable     + other.unstable,
            stable:       self.stable       + other.stable,
            frozen:       self.frozen       + other.frozen,
            locked:       self.locked       + other.locked,
            unmarked:     self.unmarked     + other.unmarked,
        }
    }
}

impl Counts {
    fn zero() -> Counts {
        Counts {
            deprecated:   0,
            experimental: 0,
            unstable:     0,
            stable:       0,
            frozen:       0,
            locked:       0,
            unmarked:     0,
        }
    }

    pub fn total(&self) -> uint {
        self.deprecated + self.experimental + self.unstable + self.stable +
            self.frozen + self.locked + self.unmarked
    }
}

#[deriving(Encodable, Decodable, PartialEq, Eq)]
/// A summarized module, which includes total counts and summarized children
/// modules.
pub struct ModuleSummary {
    pub name: String,
    pub counts: Counts,
    pub submodules: Vec<ModuleSummary>,
}

impl PartialOrd for ModuleSummary {
    fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> {
        self.name.partial_cmp(&other.name)
    }
}

impl Ord for ModuleSummary {
    fn cmp(&self, other: &ModuleSummary) -> Ordering {
        self.name.cmp(&other.name)
    }
}

// is the item considered publically visible?
fn visible(item: &Item) -> bool {
    match item.inner {
        ImplItem(_) => true,
        _ => item.visibility == Some(Public)
    }
}

fn count_stability(stab: Option<&Stability>) -> Counts {
    match stab {
        None             => Counts { unmarked: 1,     .. Counts::zero() },
        Some(ref stab) => match stab.level {
            Deprecated   => Counts { deprecated: 1,   .. Counts::zero() },
            Experimental => Counts { experimental: 1, .. Counts::zero() },
            Unstable     => Counts { unstable: 1,     .. Counts::zero() },
            Stable       => Counts { stable: 1,       .. Counts::zero() },
            Frozen       => Counts { frozen: 1,       .. Counts::zero() },
            Locked       => Counts { locked: 1,       .. Counts::zero() },
        }
    }
}

fn summarize_methods(item: &Item) -> Counts {
    match cache_key.get().unwrap().impls.get(&item.def_id) {
        Some(v) => {
            v.iter().map(|i| {
                let count = count_stability(i.stability.as_ref());
                if i.impl_.trait_.is_none() {
                    count + i.impl_.items.iter()
                        .map(|ti| summarize_item(ti).0)
                        .fold(Counts::zero(), |acc, c| acc + c)
                } else {
                    count
                }
            }).fold(Counts::zero(), |acc, c| acc + c)
        },
        None => {
            Counts::zero()
        },
    }
}

// Produce the summary for an arbitrary item. If the item is a module, include a
// module summary. The counts for items with nested items (e.g. modules, traits,
// impls) include all children counts.
fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
    let item_counts = count_stability(item.stability.as_ref()) + summarize_methods(item);

    // Count this item's children, if any. Note that a trait impl is
    // considered to have no children.
    match item.inner {
        // Require explicit `pub` to be visible
        StructItem(Struct { fields: ref subitems, .. }) |
        ImplItem(Impl { items: ref subitems, trait_: None, .. }) => {
            let subcounts = subitems.iter().filter(|i| visible(*i))
                                           .map(summarize_item)
                                           .map(|s| s.val0())
                                           .fold(Counts::zero(), |acc, x| acc + x);
            (item_counts + subcounts, None)
        }
        // `pub` automatically
        EnumItem(Enum { variants: ref subitems, .. }) => {
            let subcounts = subitems.iter().map(summarize_item)
                                           .map(|s| s.val0())
                                           .fold(Counts::zero(), |acc, x| acc + x);
            (item_counts + subcounts, None)
        }
        TraitItem(Trait {
            items: ref trait_items,
            ..
        }) => {
            fn extract_item<'a>(trait_item: &'a TraitMethod) -> &'a Item {
                match *trait_item {
                    ProvidedMethod(ref item) |
                    RequiredMethod(ref item) |
                    TypeTraitItem(ref item) => item
                }
            }
            let subcounts = trait_items.iter()
                                       .map(extract_item)
                                       .map(summarize_item)
                                       .map(|s| s.val0())
                                       .fold(Counts::zero(), |acc, x| acc + x);
            (item_counts + subcounts, None)
        }
        ModuleItem(Module { ref items, .. }) => {
            let mut counts = item_counts;
            let mut submodules = Vec::new();

            for (subcounts, submodule) in items.iter().filter(|i| visible(*i))
                                                      .map(summarize_item) {
                counts = counts + subcounts;
                submodule.map(|m| submodules.push(m));
            }
            submodules.sort();

            (counts, Some(ModuleSummary {
                name: item.name.as_ref().map_or("".to_string(), |n| n.clone()),
                counts: counts,
                submodules: submodules,
            }))
        }
        // no stability information for the following items:
        ViewItemItem(_) | PrimitiveItem(_) => (Counts::zero(), None),
        _ => (item_counts, None)
    }
}

/// Summarizes the stability levels in a crate.
pub fn build(krate: &Crate) -> ModuleSummary {
    match krate.module {
        None => ModuleSummary {
            name: krate.name.clone(),
            counts: Counts::zero(),
            submodules: Vec::new(),
        },
        Some(ref item) => ModuleSummary {
            name: krate.name.clone(), .. summarize_item(item).val1().unwrap()
        }
    }
}
<commit_msg>rustdoc: tweak stability summary counting<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module crawls a `clean::Crate` and produces a summarization of the
//! stability levels within the crate. The summary contains the module
//! hierarchy, with item counts for every stability level per module. A parent
//! module's count includes its children's.

use std::ops::Add;
use std::num::Zero;

use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
use syntax::ast::Public;

use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum};
use clean::{ImplItem, Impl, Trait, TraitItem, TraitMethod, ProvidedMethod, RequiredMethod};
use clean::{TypeTraitItem, ViewItemItem, PrimitiveItem, Stability};

use html::render::cache_key;

#[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
/// The counts for each stability level.
pub struct Counts {
    pub deprecated: uint,
    pub experimental: uint,
    pub unstable: uint,
    pub stable: uint,
    pub frozen: uint,
    pub locked: uint,

    /// No stability level, inherited or otherwise.
    pub unmarked: uint,
}

impl Add<Counts, Counts> for Counts {
    fn add(&self, other: &Counts) -> Counts {
        Counts {
            deprecated:   self.deprecated   + other.deprecated,
            experimental: self.experimental + other.experimental,
            unstable:     self.unstable     + other.unstable,
            stable:       self.stable       + other.stable,
            frozen:       self.frozen       + other.frozen,
            locked:       self.locked       + other.locked,
            unmarked:     self.unmarked     + other.unmarked,
        }
    }
}

impl Counts {
    fn zero() -> Counts {
        Counts {
            deprecated:   0,
            experimental: 0,
            unstable:     0,
            stable:       0,
            frozen:       0,
            locked:       0,
            unmarked:     0,
        }
    }

    pub fn total(&self) -> uint {
        self.deprecated + self.experimental + self.unstable + self.stable +
            self.frozen + self.locked + self.unmarked
    }
}

#[deriving(Encodable, Decodable, PartialEq, Eq)]
/// A summarized module, which includes total counts and summarized children
/// modules.
pub struct ModuleSummary {
    pub name: String,
    pub counts: Counts,
    pub submodules: Vec<ModuleSummary>,
}

impl PartialOrd for ModuleSummary {
    fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> {
        self.name.partial_cmp(&other.name)
    }
}

impl Ord for ModuleSummary {
    fn cmp(&self, other: &ModuleSummary) -> Ordering {
        self.name.cmp(&other.name)
    }
}

// is the item considered publically visible?
fn visible(item: &Item) -> bool {
    match item.inner {
        ImplItem(_) => true,
        _ => item.visibility == Some(Public)
    }
}

fn count_stability(stab: Option<&Stability>) -> Counts {
    match stab {
        None             => Counts { unmarked: 1,     .. Counts::zero() },
        Some(ref stab) => match stab.level {
            Deprecated   => Counts { deprecated: 1,   .. Counts::zero() },
            Experimental => Counts { experimental: 1, .. Counts::zero() },
            Unstable     => Counts { unstable: 1,     .. Counts::zero() },
            Stable       => Counts { stable: 1,       .. Counts::zero() },
            Frozen       => Counts { frozen: 1,       .. Counts::zero() },
            Locked       => Counts { locked: 1,       .. Counts::zero() },
        }
    }
}

fn summarize_methods(item: &Item) -> Counts {
    match cache_key.get().unwrap().impls.get(&item.def_id) {
        Some(v) => {
            v.iter().map(|i| {
                let count = count_stability(i.stability.as_ref());
                if i.impl_.trait_.is_none() {
                    count + i.impl_.items.iter()
                        .map(|ti| summarize_item(ti).0)
                        .fold(Counts::zero(), |acc, c| acc + c)
                } else {
                    count
                }
            }).fold(Counts::zero(), |acc, c| acc + c)
        },
        None => {
            Counts::zero()
        },
    }
}

// Produce the summary for an arbitrary item. If the item is a module, include a
// module summary. The counts for items with nested items (e.g. modules, traits,
// impls) include all children counts.
fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
    let item_counts = count_stability(item.stability.as_ref()) + summarize_methods(item);

    // Count this item's children, if any. Note that a trait impl is
    // considered to have no children.
    match item.inner {
        // Require explicit `pub` to be visible
        ImplItem(Impl { items: ref subitems, trait_: None, .. }) => {
            let subcounts = subitems.iter().filter(|i| visible(*i))
                                           .map(summarize_item)
                                           .map(|s| s.val0())
                                           .fold(Counts::zero(), |acc, x| acc + x);
            (subcounts, None)
        }
        // `pub` automatically
        EnumItem(Enum { variants: ref subitems, .. }) => {
            let subcounts = subitems.iter().map(summarize_item)
                                           .map(|s| s.val0())
                                           .fold(Counts::zero(), |acc, x| acc + x);
            (item_counts + subcounts, None)
        }
        TraitItem(Trait {
            items: ref trait_items,
            ..
        }) => {
            fn extract_item<'a>(trait_item: &'a TraitMethod) -> &'a Item {
                match *trait_item {
                    ProvidedMethod(ref item) |
                    RequiredMethod(ref item) |
                    TypeTraitItem(ref item) => item
                }
            }
            let subcounts = trait_items.iter()
                                       .map(extract_item)
                                       .map(summarize_item)
                                       .map(|s| s.val0())
                                       .fold(Counts::zero(), |acc, x| acc + x);
            (item_counts + subcounts, None)
        }
        ModuleItem(Module { ref items, .. }) => {
            let mut counts = item_counts;
            let mut submodules = Vec::new();

            for (subcounts, submodule) in items.iter().filter(|i| visible(*i))
                                                      .map(summarize_item) {
                counts = counts + subcounts;
                submodule.map(|m| submodules.push(m));
            }
            submodules.sort();

            (counts, Some(ModuleSummary {
                name: item.name.as_ref().map_or("".to_string(), |n| n.clone()),
                counts: counts,
                submodules: submodules,
            }))
        }
        // no stability information for the following items:
        ViewItemItem(_) | PrimitiveItem(_) => (Counts::zero(), None),
        _ => (item_counts, None)
    }
}

/// Summarizes the stability levels in a crate.
pub fn build(krate: &Crate) -> ModuleSummary {
    match krate.module {
        None => ModuleSummary {
            name: krate.name.clone(),
            counts: Counts::zero(),
            submodules: Vec::new(),
        },
        Some(ref item) => ModuleSummary {
            name: krate.name.clone(), .. summarize_item(item).val1().unwrap()
        }
    }
}
<|endoftext|>