<commit_before>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
// which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
        unsafe {
            let size = layout.size();
            if size == 0 {
                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
            } else {
                let raw_ptr = match init {
                    AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
                    AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
                };
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(MemoryBlock { ptr, size })
            }
        }
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        let size = layout.size();
        debug_assert!(
            new_size >= size,
            "`new_size` must be greater than or equal to `memory.size()`"
        );

        if size == new_size {
            return Ok(MemoryBlock { ptr, size });
        }

        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove if layout.size() == 0 => {
                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                self.alloc(new_layout, init)
            }
            ReallocPlacement::MayMove => {
                // `realloc` probably checks for `new_size > size` or something similar.
                intrinsics::assume(new_size > size);
                let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                let memory =
                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
                init.init_offset(memory, size);
                Ok(memory)
            }
        }
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        let size = layout.size();
        debug_assert!(
            new_size <= size,
            "`new_size` must be smaller than or equal to `memory.size()`"
        );

        if size == new_size {
            return Ok(MemoryBlock { ptr, size });
        }

        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove if new_size == 0 => {
                self.dealloc(ptr, layout);
                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
            }
            ReallocPlacement::MayMove => {
                // `realloc` probably checks for `new_size < size` or something similar.
                intrinsics::assume(new_size < size);
                let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
            }
        }
    }
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc(layout)
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        let old_layout = Layout::from_size_align_unchecked(old_size, align);
        System.realloc(ptr, old_layout, new_size)
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc_zeroed(layout)
    }
}
<commit_msg>Rollup merge of #74333 - poliorcetics:std-alloc-unsafe-op-in-unsafe-fn, r=LukasKalbertodt<commit_after>//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified. Libraries, however,
//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by
//! default.
//!
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![deny(unsafe_op_in_unsafe_fn)]
#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};

use crate::sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
///     let a = Box::new(4); // Allocates from the system allocator.
///     println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
///
/// unsafe impl GlobalAlloc for Counter {
///     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
///         let ret = System.alloc(layout);
///         if !ret.is_null() {
///             ALLOCATED.fetch_add(layout.size(), SeqCst);
///         }
///         return ret
///     }
///
///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
///         System.dealloc(ptr, layout);
///         ALLOCATED.fetch_sub(layout.size(), SeqCst);
///     }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
///     println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[derive(Debug, Default, Copy, Clone)]
pub struct System;

// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
// which is in `std::sys::*::alloc`.
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl AllocRef for System {
    #[inline]
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
        unsafe {
            let size = layout.size();
            if size == 0 {
                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
            } else {
                let raw_ptr = match init {
                    AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
                    AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
                };
                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
                Ok(MemoryBlock { ptr, size })
            }
        }
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        if layout.size() != 0 {
            // SAFETY: The safety guarantees are explained in the documentation
            // for the `GlobalAlloc` trait and its `dealloc` method.
            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
        }
    }

    #[inline]
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        let size = layout.size();
        debug_assert!(
            new_size >= size,
            "`new_size` must be greater than or equal to `memory.size()`"
        );

        if size == new_size {
            return Ok(MemoryBlock { ptr, size });
        }

        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove if layout.size() == 0 => {
                let new_layout =
                    // SAFETY: The new size and layout alignement guarantees
                    // are transfered to the caller (they come from parameters).
                    //
                    // See the preconditions for `Layout::from_size_align` to
                    // see what must be checked.
                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
                self.alloc(new_layout, init)
            }
            ReallocPlacement::MayMove => {
                // SAFETY:
                //
                // The safety guarantees are explained in the documentation
                // for the `GlobalAlloc` trait and its `dealloc` method.
                //
                // `realloc` probably checks for `new_size > size` or something
                // similar.
                //
                // For the guarantees about `init_offset`, see its documentation:
                // `ptr` is assumed valid (and checked for non-NUL) and
                // `memory.size` is set to `new_size` so the offset being `size`
                // is valid.
                let memory = unsafe {
                    intrinsics::assume(new_size > size);
                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                    let memory =
                        MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
                    init.init_offset(memory, size);
                    memory
                };
                Ok(memory)
            }
        }
    }

    #[inline]
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        let size = layout.size();
        debug_assert!(
            new_size <= size,
            "`new_size` must be smaller than or equal to `memory.size()`"
        );

        if size == new_size {
            return Ok(MemoryBlock { ptr, size });
        }

        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove if new_size == 0 => {
                // SAFETY: see `GlobalAlloc::dealloc` for the guarantees that
                // must be respected. `ptr` and `layout` are parameters and so
                // those guarantees must be checked by the caller.
                unsafe { self.dealloc(ptr, layout) };
                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
            }
            ReallocPlacement::MayMove => {
                // SAFETY:
                //
                // See `GlobalAlloc::realloc` for more informations about the
                // guarantees expected by this method. `ptr`, `layout` and
                // `new_size` are parameters and the responsability for their
                // correctness is left to the caller.
                //
                // `realloc` probably checks for `new_size < size` or something
                // similar.
                let memory = unsafe {
                    intrinsics::assume(new_size < size);
                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }
                };
                Ok(memory)
            }
        }
    }
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
///
/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) =
        if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
    hook(layout);
    crate::process::abort()
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __default_lib_allocator {
    use super::{GlobalAlloc, Layout, System};
    // These magic symbol names are used as a fallback for implementing the
    // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
    // no `#[global_allocator]` attribute.

    // for symbol names src/librustc_ast/expand/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc(layout)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::dealloc`.
        unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_realloc(
        ptr: *mut u8,
        old_size: usize,
        align: usize,
        new_size: usize,
    ) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::realloc`.
        unsafe {
            let old_layout = Layout::from_size_align_unchecked(old_size, align);
            System.realloc(ptr, old_layout, new_size)
        }
    }

    #[rustc_std_internal_symbol]
    pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        // SAFETY: see the guarantees expected by `Layout::from_size_align` and
        // `GlobalAlloc::alloc_zeroed`.
        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);
            System.alloc_zeroed(layout)
        }
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use retain_mut::RetainMut;
use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf};

#[cfg(unix)]
use uucore::libc;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";

mod options {
    pub const APPEND: &str = "append";
    pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
    pub const FILE: &str = "file";
}

#[allow(dead_code)]
struct Options {
    append: bool,
    ignore_interrupts: bool,
    files: Vec<String>,
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help("If a FILE is -, it refers to a file named - .")
        .arg(
            Arg::with_name(options::APPEND)
                .long(options::APPEND)
                .short("a")
                .help("append to the given FILEs, do not overwrite"),
        )
        .arg(
            Arg::with_name(options::IGNORE_INTERRUPTS)
                .long(options::IGNORE_INTERRUPTS)
                .short("i")
                .help("ignore interrupt signals (ignored on non-Unix platforms)"),
        )
        .arg(Arg::with_name(options::FILE).multiple(true))
        .get_matches_from(args);

    let options = Options {
        append: matches.is_present(options::APPEND),
        ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
        files: matches
            .values_of(options::FILE)
            .map(|v| v.map(ToString::to_string).collect())
            .unwrap_or_default(),
    };

    match tee(options) {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

#[cfg(unix)]
fn ignore_interrupts() -> Result<()> {
    let ret = unsafe { libc::signal(libc::SIGINT, libc::SIG_IGN) };
    if ret == libc::SIG_ERR {
        return Err(Error::new(ErrorKind::Other, ""));
    }
    Ok(())
}

#[cfg(not(unix))]
fn ignore_interrupts() -> Result<()> {
    // Do nothing.
    Ok(())
}

fn tee(options: Options) -> Result<()> {
    if options.ignore_interrupts {
        ignore_interrupts()?
    }
    let mut writers: Vec<NamedWriter> = options
        .files
        .clone()
        .into_iter()
        .map(|file| NamedWriter {
            name: file.clone(),
            inner: open(file, options.append),
        })
        .collect();

    writers.insert(
        0,
        NamedWriter {
            name: "'standard output'".to_owned(),
            inner: Box::new(stdout()),
        },
    );

    let mut output = MultiWriter::new(writers);
    let input = &mut NamedReader {
        inner: Box::new(stdin()) as Box<dyn Read>,
    };

    // TODO: replaced generic 'copy' call to be able to stop copying
    // if all outputs are closed (due to errors)
    if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occured() {
        Err(Error::new(ErrorKind::Other, ""))
    } else {
        Ok(())
    }
}

fn open(name: String, append: bool) -> Box<dyn Write> {
    let path = PathBuf::from(name.clone());
    let inner: Box<dyn Write> = {
        let mut options = OpenOptions::new();
        let mode = if append {
            options.append(true)
        } else {
            options.truncate(true)
        };
        match mode.write(true).create(true).open(path.as_path()) {
            Ok(file) => Box::new(file),
            Err(_) => Box::new(sink()),
        }
    };
    Box::new(NamedWriter { inner, name }) as Box<dyn Write>
}

struct MultiWriter {
    writers: Vec<NamedWriter>,
    initial_len: usize,
}

impl MultiWriter {
    fn new(writers: Vec<NamedWriter>) -> Self {
        Self {
            initial_len: writers.len(),
            writers,
        }
    }
    fn error_occured(&self) -> bool {
        self.writers.len() != self.initial_len
    }
}

impl Write for MultiWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.writers.retain_mut(|writer| {
            let result = writer.write_all(buf);
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name, f.to_string());
                    false
                }
                _ => true,
            }
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<()> {
        self.writers.retain_mut(|writer| {
            let result = writer.flush();
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name, f.to_string());
                    false
                }
                _ => true,
            }
        });
        Ok(())
    }
}

struct NamedWriter {
    inner: Box<dyn Write>,
    pub name: String,
}

impl Write for NamedWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.inner.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

struct NamedReader {
    inner: Box<dyn Read>,
}

impl Read for NamedReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.read(buf) {
            Err(f) => {
                show_error!("{}: {}", Path::new("stdin").display(), f.to_string());
                Err(f)
            }
            okay => okay,
        }
    }
}
<commit_msg>refactor/tee ~ polish spelling (comments, names, and exceptions)<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use retain_mut::RetainMut;
use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf};

#[cfg(unix)]
use uucore::libc;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";

mod options {
    pub const APPEND: &str = "append";
    pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
    pub const FILE: &str = "file";
}

#[allow(dead_code)]
struct Options {
    append: bool,
    ignore_interrupts: bool,
    files: Vec<String>,
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [FILE]...", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help("If a FILE is -, it refers to a file named - .")
        .arg(
            Arg::with_name(options::APPEND)
                .long(options::APPEND)
                .short("a")
                .help("append to the given FILEs, do not overwrite"),
        )
        .arg(
            Arg::with_name(options::IGNORE_INTERRUPTS)
                .long(options::IGNORE_INTERRUPTS)
                .short("i")
                .help("ignore interrupt signals (ignored on non-Unix platforms)"),
        )
        .arg(Arg::with_name(options::FILE).multiple(true))
        .get_matches_from(args);

    let options = Options {
        append: matches.is_present(options::APPEND),
        ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
        files: matches
            .values_of(options::FILE)
            .map(|v| v.map(ToString::to_string).collect())
            .unwrap_or_default(),
    };

    match tee(options) {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

#[cfg(unix)]
fn ignore_interrupts() -> Result<()> {
    let ret = unsafe { libc::signal(libc::SIGINT, libc::SIG_IGN) };
    if ret == libc::SIG_ERR {
        return Err(Error::new(ErrorKind::Other, ""));
    }
    Ok(())
}

#[cfg(not(unix))]
fn ignore_interrupts() -> Result<()> {
    // Do nothing.
    Ok(())
}

fn tee(options: Options) -> Result<()> {
    if options.ignore_interrupts {
        ignore_interrupts()?
    }
    let mut writers: Vec<NamedWriter> = options
        .files
        .clone()
        .into_iter()
        .map(|file| NamedWriter {
            name: file.clone(),
            inner: open(file, options.append),
        })
        .collect();

    writers.insert(
        0,
        NamedWriter {
            name: "'standard output'".to_owned(),
            inner: Box::new(stdout()),
        },
    );

    let mut output = MultiWriter::new(writers);
    let input = &mut NamedReader {
        inner: Box::new(stdin()) as Box<dyn Read>,
    };

    // TODO: replaced generic 'copy' call to be able to stop copying
    // if all outputs are closed (due to errors)
    if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occurred() {
        Err(Error::new(ErrorKind::Other, ""))
    } else {
        Ok(())
    }
}

fn open(name: String, append: bool) -> Box<dyn Write> {
    let path = PathBuf::from(name.clone());
    let inner: Box<dyn Write> = {
        let mut options = OpenOptions::new();
        let mode = if append {
            options.append(true)
        } else {
            options.truncate(true)
        };
        match mode.write(true).create(true).open(path.as_path()) {
            Ok(file) => Box::new(file),
            Err(_) => Box::new(sink()),
        }
    };
    Box::new(NamedWriter { inner, name }) as Box<dyn Write>
}

struct MultiWriter {
    writers: Vec<NamedWriter>,
    initial_len: usize,
}

impl MultiWriter {
    fn new(writers: Vec<NamedWriter>) -> Self {
        Self {
            initial_len: writers.len(),
            writers,
        }
    }
    fn error_occurred(&self) -> bool {
        self.writers.len() != self.initial_len
    }
}

impl Write for MultiWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.writers.retain_mut(|writer| {
            let result = writer.write_all(buf);
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name, f.to_string());
                    false
                }
                _ => true,
            }
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<()> {
        self.writers.retain_mut(|writer| {
            let result = writer.flush();
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name, f.to_string());
                    false
                }
                _ => true,
            }
        });
        Ok(())
    }
}

struct NamedWriter {
    inner: Box<dyn Write>,
    pub name: String,
}

impl Write for NamedWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.inner.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

struct NamedReader {
    inner: Box<dyn Read>,
}

impl Read for NamedReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.read(buf) {
            Err(f) => {
                show_error!("{}: {}", Path::new("stdin").display(), f.to_string());
                Err(f)
            }
            okay => okay,
        }
    }
}
<|endoftext|>


<commit_before>static CONST1: i32 = 20091;
static CONST2: i32 = 35468;

pub fn idct4x4(block: &mut [i32]) {
    for i in 0usize..4 {
        let a1 = block[i] + block[8 + i];
        let b1 = block[i] - block[8 + i];

        let t1 = (block[4 + i] * CONST2) >> 16;
        let t2 = block[12 + i] + ((block[12 + i] * CONST1) >> 16);
        let c1 = t1 - t2;

        let t1 = block[4 + i] + ((block[4 + i] * CONST1) >> 16);
        let t2 = (block[12 + i] * CONST2) >> 16;
        let d1 = t1 + t2;

        block[i] = a1 + d1;
        block[4 + i] = b1 + c1;
        block[4 * 3 + i] = a1 - d1;
        block[4 * 2 + i] = b1 - c1;
    }

    for i in 0usize..4 {
        let a1 = block[4 * i] + block[4 * i + 2];
        let b1 = block[4 * i] - block[4 * i + 2];

        let t1 = (block[4 * i + 1] * CONST2) >> 16;
        let t2 = block[4 * i + 3] + ((block[4 * i + 3] * CONST1) >> 16);
        let c1 = t1 - t2;

        let t1 = block[4 * i + 1] + ((block[4 * i + 1] * CONST1) >> 16);
        let t2 = (block[4 * i + 3] * CONST2) >> 16;
        let d1 = t1 + t2;

        block[4 * i] = (a1 + d1 + 4) >> 3;
        block[4 * i + 3] = (a1 - d1 + 4) >> 3;
        block[4 * i + 1] = (b1 + c1 + 4) >> 3;
        block[4 * i + 2] = (b1 - c1 + 4) >> 3;
    }
}

// 14.3
pub fn iwht4x4(block: &mut [i32]) {
    for i in 0usize..4 {
        let a1 = block[i] + block[12 + i];
        let b1 = block[4 + i] + block[8 + i];
        let c1 = block[4 + i] - block[8 + i];
        let d1 = block[i] - block[12 + i];

        block[i] = a1 + b1;
        block[4 + i] = c1 + d1;
        block[8 + i] = a1 - b1;
        block[12 + i] = d1 - c1;
    }

    for i in 0usize..4 {
        let a1 = block[4 * i] + block[4 * i + 3];
        let b1 = block[4 * i + 1] + block[4 * i + 2];
        let c1 = block[4 * i + 1] - block[4 * i + 2];
        let d1 = block[4 * i] - block[4 * i + 3];

        let a2 = a1 + b1;
        let b2 = c1 + d1;
        let c2 = a1 - b1;
        let d2 = d1 - c1;

        block[4 * i] = (a2 + 3) >> 3;
        block[4 * i + 1] = (b2 + 3) >> 3;
        block[4 * i + 2] = (c2 + 3) >> 3;
        block[4 * i + 3] = (d2 + 3) >> 3;
    }
}
<commit_msg>Fix intermediate transformation math types<commit_after>static CONST1: i64 = 20091;
static CONST2: i64 = 35468;

pub fn idct4x4(block: &mut [i32]) {
    // The intermediate results may overflow the types, so we stretch the type.
    fn fetch(block: &mut [i32], idx: usize) -> i64 {
        i64::from(block[idx])
    }

    for i in 0usize..4 {
        let a1 = fetch(block, i) + fetch(block, 8 + i);
        let b1 = fetch(block, i) - fetch(block, 8 + i);

        let t1 = (fetch(block, 4 + i) * CONST2) >> 16;
        let t2 = fetch(block, 12 + i) + ((fetch(block, 12 + i) * CONST1) >> 16);
        let c1 = t1 - t2;

        let t1 = fetch(block, 4 + i) + ((fetch(block, 4 + i) * CONST1) >> 16);
        let t2 = (fetch(block, 12 + i) * CONST2) >> 16;
        let d1 = t1 + t2;

        block[i] = (a1 + d1) as i32;
        block[4 + i] = (b1 + c1) as i32;
        block[4 * 3 + i] = (a1 - d1) as i32;
        block[4 * 2 + i] = (b1 - c1) as i32;
    }

    for i in 0usize..4 {
        let a1 = fetch(block, 4 * i) + fetch(block, 4 * i + 2);
        let b1 = fetch(block, 4 * i) - fetch(block, 4 * i + 2);

        let t1 = (fetch(block, 4 * i + 1) * CONST2) >> 16;
        let t2 = fetch(block, 4 * i + 3) + ((fetch(block, 4 * i + 3) * CONST1) >> 16);
        let c1 = t1 - t2;

        let t1 = fetch(block, 4 * i + 1) + ((fetch(block, 4 * i + 1) * CONST1) >> 16);
        let t2 = (fetch(block, 4 * i + 3) * CONST2) >> 16;
        let d1 = t1 + t2;

        block[4 * i] = ((a1 + d1 + 4) >> 3) as i32;
        block[4 * i + 3] = ((a1 - d1 + 4) >> 3) as i32;
        block[4 * i + 1] = ((b1 + c1 + 4) >> 3) as i32;
        block[4 * i + 2] = ((b1 - c1 + 4) >> 3) as i32;
    }
}

// 14.3
pub fn iwht4x4(block: &mut [i32]) {
    for i in 0usize..4 {
        let a1 = block[i] + block[12 + i];
        let b1 = block[4 + i] + block[8 + i];
        let c1 = block[4 + i] - block[8 + i];
        let d1 = block[i] - block[12 + i];

        block[i] = a1 + b1;
        block[4 + i] = c1 + d1;
        block[8 + i] = a1 - b1;
        block[12 + i] = d1 - c1;
    }

    for i in 0usize..4 {
        let a1 = block[4 * i] + block[4 * i + 3];
        let b1 = block[4 * i + 1] + block[4 * i + 2];
        let c1 = block[4 * i + 1] - block[4 * i + 2];
        let d1 = block[4 * i] - block[4 * i + 3];

        let a2 = a1 + b1;
        let b2 = c1 + d1;
        let c2 = a1 - b1;
        let d2 = d1 - c1;

        block[4 * i] = (a2 + 3) >> 3;
        block[4 * i + 1] = (b2 + 3) >> 3;
        block[4 * i + 2] = (c2 + 3) >> 3;
        block[4 * i + 3] = (d2 + 3) >> 3;
    }
}
<|endoftext|>


<commit_before>use async_trait::async_trait;
use chrono::{DateTime, NaiveDateTime, Utc};
use events::{subscribe, Subscriber};
use eyre::{bail, Result};
use node_address::Address;
use node_pointer::{walk, Visitor};
use once_cell::sync::Lazy;
use regex::{Captures, Regex};
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::str::FromStr;
use stencila_schema::{InlineContent, Node};
use tokio::{
    sync::mpsc,
    time::{timeout, Duration},
};

// Export and re-export for the convenience of crates that implement a provider
pub use ::async_trait;
pub use ::codecs;
pub use ::eyre;
pub use ::http_utils;
pub use ::once_cell;
pub use ::regex;
pub use ::stencila_schema;
pub use ::tokio;
pub use ::tracing;

pub const IMPORT: &str = "import";
pub const EXPORT: &str = "export";
pub const IMPORT_EXPORT: &str = "import/export";
pub const ACTIONS: &[&str] = &[IMPORT, EXPORT, IMPORT_EXPORT];

/// A specification for providers
///
/// All providers, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Provider` instance from the
/// `spec` function of `ProviderTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Provider {
    /// The name of the provider
    pub name: String,
}

impl Provider {
    pub fn new(name: impl AsRef<str>) -> Self {
        Self {
            name: name.as_ref().to_string(),
        }
    }
}

/// A trait for providers
///
/// This trait can be used by Rust implementations of providers, allowing them to
/// be compiled into the Stencila binaries.
#[async_trait]
pub trait ProviderTrait {
    /// Get the [`Provider`] specification
    fn spec() -> Provider;

    /// Parse a string into a node
    fn parse(_string: &str) -> Vec<ParseItem> {
        Vec::new()
    }

    /// Detect nodes within a root node that the provider may be able to identify and enrich.
    ///
    /// Returns a vector of [`Detection`].
    async fn detect(root: &Node) -> Result<Vec<DetectItem>> {
        let name = Self::spec().name;
        let parse = Box::new(|string: &str| Self::parse(string));

        let mut detector = Detector::new(name, parse);
        walk(root, &mut detector);
        Ok(detector.detections)
    }

    /// Identify a node
    ///
    /// The node is supplied to the provider, with one or more properties populated.
    /// The provider then attempts to identify the node based on those properties,
    /// and if it was able to do so, returns a copy of the node with one or more identifying
    /// properties populated (e.g. the `GithubProvider` might populate the `codeRepository` property
    /// of a `SofwareSourceCode` node).
    async fn identify(node: Node) -> Result<Node> {
        Ok(node)
    }

    /// Enrich a node
    ///
    /// If the provider had previously identified the node, then the relevant identifiers
    /// will be used to fetch enrichment data, otherwise `identify` will be called.
    /// Then, the provider will return a opy of the node with properties that are missing.
    async fn enrich(node: Node, _options: Option<EnrichOptions>) -> Result<Node> {
        Ok(node)
    }

    /// Import content from a remote [`Node`] (e.g. an `Article` or `SoftwareSourceCode` repository) to a local path
    async fn import(_node: &Node, _path: &Path, _options: Option<ImportOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Export content from a local path to a remote [`Node`] (e.g. an `Article` or `SoftwareSourceCode` repository)
    async fn export(_node: &Node, _path: &Path, _options: Option<ExportOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Synchronize changes between a remote [`Node`] (e.g. a `SoftwareSourceCode` repository) and a local path (a file or directory)
    async fn sync(_node: &Node, _path: &Path, _options: Option<SyncOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Schedule import and/or export to/from a remove [`Node`] and a local path
    async fn schedule(_action: &str, _schedule: &str, _node: &Node, _path: &Path) -> Result<bool> {
        Ok(false)
    }
}

#[derive(Debug, Default, Clone)]
pub struct EnrichOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct ImportOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct ExportOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct SyncOptions {
    pub token: Option<String>,

    /// The URL to listen on
    pub url: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct ParseItem {
    /// The start position in the string that the node was parsed from
    pub begin: usize,

    /// The end position in the string that the node was parsed from
    pub end: usize,

    /// The parsed [`Node`] usually with some properties populated
    pub node: Node,
}

#[derive(Debug, Serialize)]
pub struct DetectItem {
    /// The name of the provider that detected the node
    pub provider: String,

    /// The percent confidence in the detection (0-100)
    pub confidence: u32,

    /// The [`Address`], within the node tree, that the node detected node begins
    pub begin: Address,

    /// The [`Address`], within the node tree, that the node detected node ends
    pub end: Address,

    /// The detected [`Node`] usually with some properties populated (i.e. those
    /// properties that were used to detect it)
    pub node: Node,
}

pub struct Detector {
    /// The name of the provider that this detector is for
    provider: String,

    /// The function used to attempt to parse a string into a node
    parse: Box<dyn Fn(&str) -> Vec<ParseItem>>,

    /// The list of detected nodes and their location
    detections: Vec<DetectItem>,
}

impl Detector {
    fn new(provider: String, parse: Box<dyn Fn(&str) -> Vec<ParseItem>>) -> Self {
        Self {
            provider,
            parse,
            detections: Vec::new(),
        }
    }

    fn visit_string(&mut self, address: &Address, string: &str) {
        let nodes = (self.parse)(string);
        let mut detections = nodes
            .into_iter()
            .map(|ParseItem { begin, end, node }| DetectItem {
                provider: self.provider.clone(),
                confidence: 100,
                begin: address.add_index(begin),
                end: address.add_index(end),
                node,
            })
            .collect();
        self.detections.append(&mut detections);
    }
}

impl Visitor for Detector {
    fn visit_node(&mut self, address: &Address, node: &Node) -> bool {
        if let Node::String(string) = node {
            self.visit_string(address, string);
            false
        } else {
            true
        }
    }

    fn visit_inline(&mut self, address: &Address, node: &InlineContent) -> bool {
        if let InlineContent::String(string) = node {
            self.visit_string(address, string);
            false
        } else {
            true
        }
    }
}

/// Schedule import and/or export to/from a remove [`Node`] and a local path
pub async fn run_schedule(schedule: &str, sender: mpsc::Sender<()>) -> Result<()> {
    let (schedules, timezone) = cron_utils::parse(schedule)?;

    let (interrupt_sender, mut interrupt_receiver) = mpsc::unbounded_channel();
    subscribe("interrupt", Subscriber::Sender(interrupt_sender))?;

    tokio::spawn(async move {
        let interval = Duration::from_secs(1);
        let mut next = cron_utils::next(&schedules, &timezone);
        if let Some(time) = next {
            tracing::debug!("First action scheduled for {}", time);
        }
        loop {
            if let Err(..) = timeout(interval, interrupt_receiver.recv()).await {
                match next {
                    Some(time) => {
                        if Utc::now() >= time {
                            if let Err(error) = sender.send(()).await {
                                tracing::error!("When sending schedule message: {}", error);
                            }
                            next = cron_utils::next(&schedules, &timezone);
                            if let Some(time) = next {
                                tracing::debug!("Next action scheduled for {}", time);
                            }
                        }
                    }
                    None => {
                        tracing::info!("No more scheduled actions");
                        break;
                    }
                }
            } else {
                tracing::info!("Schedule was cancelled");
                break;
            }
        }
    })
    .await?;

    Ok(())
}
<commit_msg>chore(Provider): Linting<commit_after>use async_trait::async_trait;
use chrono::Utc;
use events::{subscribe, Subscriber};
use eyre::Result;
use node_address::Address;
use node_pointer::{walk, Visitor};

use serde::{Deserialize, Serialize};
use std::path::Path;

use stencila_schema::{InlineContent, Node};
use tokio::{
    sync::mpsc,
    time::{timeout, Duration},
};

// Export and re-export for the convenience of crates that implement a provider
pub use ::async_trait;
pub use ::codecs;
pub use ::eyre;
pub use ::http_utils;
pub use ::once_cell;
pub use ::regex;
pub use ::stencila_schema;
pub use ::tokio;
pub use ::tracing;

pub const IMPORT: &str = "import";
pub const EXPORT: &str = "export";
pub const IMPORT_EXPORT: &str = "import/export";
pub const ACTIONS: &[&str] = &[IMPORT, EXPORT, IMPORT_EXPORT];

/// A specification for providers
///
/// All providers, including those implemented in plugins, should provide this
/// specification. Rust implementations return a `Provider` instance from the
/// `spec` function of `ProviderTrait`. Plugins provide a JSON or YAML serialization
/// as part of their manifest.
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Provider {
    /// The name of the provider
    pub name: String,
}

impl Provider {
    pub fn new(name: impl AsRef<str>) -> Self {
        Self {
            name: name.as_ref().to_string(),
        }
    }
}

/// A trait for providers
///
/// This trait can be used by Rust implementations of providers, allowing them to
/// be compiled into the Stencila binaries.
#[async_trait]
pub trait ProviderTrait {
    /// Get the [`Provider`] specification
    fn spec() -> Provider;

    /// Parse a string into a node
    fn parse(_string: &str) -> Vec<ParseItem> {
        Vec::new()
    }

    /// Detect nodes within a root node that the provider may be able to identify and enrich.
    ///
    /// Returns a vector of [`Detection`].
    async fn detect(root: &Node) -> Result<Vec<DetectItem>> {
        let name = Self::spec().name;
        let parse = Box::new(|string: &str| Self::parse(string));

        let mut detector = Detector::new(name, parse);
        walk(root, &mut detector);
        Ok(detector.detections)
    }

    /// Identify a node
    ///
    /// The node is supplied to the provider, with one or more properties populated.
    /// The provider then attempts to identify the node based on those properties,
    /// and if it was able to do so, returns a copy of the node with one or more identifying
    /// properties populated (e.g. the `GithubProvider` might populate the `codeRepository` property
    /// of a `SofwareSourceCode` node).
    async fn identify(node: Node) -> Result<Node> {
        Ok(node)
    }

    /// Enrich a node
    ///
    /// If the provider had previously identified the node, then the relevant identifiers
    /// will be used to fetch enrichment data, otherwise `identify` will be called.
    /// Then, the provider will return a opy of the node with properties that are missing.
    async fn enrich(node: Node, _options: Option<EnrichOptions>) -> Result<Node> {
        Ok(node)
    }

    /// Import content from a remote [`Node`] (e.g. an `Article` or `SoftwareSourceCode` repository) to a local path
    async fn import(_node: &Node, _path: &Path, _options: Option<ImportOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Export content from a local path to a remote [`Node`] (e.g. an `Article` or `SoftwareSourceCode` repository)
    async fn export(_node: &Node, _path: &Path, _options: Option<ExportOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Synchronize changes between a remote [`Node`] (e.g. a `SoftwareSourceCode` repository) and a local path (a file or directory)
    async fn sync(_node: &Node, _path: &Path, _options: Option<SyncOptions>) -> Result<bool> {
        Ok(false)
    }

    /// Schedule import and/or export to/from a remove [`Node`] and a local path
    async fn schedule(_action: &str, _schedule: &str, _node: &Node, _path: &Path) -> Result<bool> {
        Ok(false)
    }
}

#[derive(Debug, Default, Clone)]
pub struct EnrichOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct ImportOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct ExportOptions {
    pub token: Option<String>,
}

#[derive(Debug, Default, Clone)]
pub struct SyncOptions {
    pub token: Option<String>,

    /// The URL to listen on
    pub url: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct ParseItem {
    /// The start position in the string that the node was parsed from
    pub begin: usize,

    /// The end position in the string that the node was parsed from
    pub end: usize,

    /// The parsed [`Node`] usually with some properties populated
    pub node: Node,
}

#[derive(Debug, Serialize)]
pub struct DetectItem {
    /// The name of the provider that detected the node
    pub provider: String,

    /// The percent confidence in the detection (0-100)
    pub confidence: u32,

    /// The [`Address`], within the node tree, that the node detected node begins
    pub begin: Address,

    /// The [`Address`], within the node tree, that the node detected node ends
    pub end: Address,

    /// The detected [`Node`] usually with some properties populated (i.e. those
    /// properties that were used to detect it)
    pub node: Node,
}

pub struct Detector {
    /// The name of the provider that this detector is for
    provider: String,

    /// The function used to attempt to parse a string into a node
    parse: Box<dyn Fn(&str) -> Vec<ParseItem>>,

    /// The list of detected nodes and their location
    detections: Vec<DetectItem>,
}

impl Detector {
    fn new(provider: String, parse: Box<dyn Fn(&str) -> Vec<ParseItem>>) -> Self {
        Self {
            provider,
            parse,
            detections: Vec::new(),
        }
    }

    fn visit_string(&mut self, address: &Address, string: &str) {
        let nodes = (self.parse)(string);
        let mut detections = nodes
            .into_iter()
            .map(|ParseItem { begin, end, node }| DetectItem {
                provider: self.provider.clone(),
                confidence: 100,
                begin: address.add_index(begin),
                end: address.add_index(end),
                node,
            })
            .collect();
        self.detections.append(&mut detections);
    }
}

impl Visitor for Detector {
    fn visit_node(&mut self, address: &Address, node: &Node) -> bool {
        if let Node::String(string) = node {
            self.visit_string(address, string);
            false
        } else {
            true
        }
    }

    fn visit_inline(&mut self, address: &Address, node: &InlineContent) -> bool {
        if let InlineContent::String(string) = node {
            self.visit_string(address, string);
            false
        } else {
            true
        }
    }
}

/// Schedule import and/or export to/from a remove [`Node`] and a local path
pub async fn run_schedule(schedule: &str, sender: mpsc::Sender<()>) -> Result<()> {
    let (schedules, timezone) = cron_utils::parse(schedule)?;

    let (interrupt_sender, mut interrupt_receiver) = mpsc::unbounded_channel();
    subscribe("interrupt", Subscriber::Sender(interrupt_sender))?;

    tokio::spawn(async move {
        let interval = Duration::from_secs(1);
        let mut next = cron_utils::next(&schedules, &timezone);
        if let Some(time) = next {
            tracing::debug!("First action scheduled for {}", time);
        }
        loop {
            if let Err(..) = timeout(interval, interrupt_receiver.recv()).await {
                match next {
                    Some(time) => {
                        if Utc::now() >= time {
                            if let Err(error) = sender.send(()).await {
                                tracing::error!("When sending schedule message: {}", error);
                            }
                            next = cron_utils::next(&schedules, &timezone);
                            if let Some(time) = next {
                                tracing::debug!("Next action scheduled for {}", time);
                            }
                        }
                    }
                    None => {
                        tracing::info!("No more scheduled actions");
                        break;
                    }
                }
            } else {
                tracing::info!("Schedule was cancelled");
                break;
            }
        }
    })
    .await?;

    Ok(())
}
<|endoftext|>


<commit_before>use cairo;
use cssparser;
use glib_sys;
use glib::translate::*;
use libc;

use std::rc::Rc;
use std::ptr;

use bbox::RsvgBbox;
use color::Color;
use drawing_ctx;
use error::*;
use gradient;
use node::NodeType;
use parsers::{Parse, ParseError};
use pattern;
use util::utf8_cstr;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PaintServerSpread (pub cairo::enums::Extend);

impl Parse for PaintServerSpread {
    type Data = ();
    type Err = AttributeError;

    fn parse (s: &str, _: ()) -> Result <PaintServerSpread, AttributeError> {
        match s {
            "pad"     => Ok (PaintServerSpread (cairo::enums::Extend::Pad)),
            "reflect" => Ok (PaintServerSpread (cairo::enums::Extend::Reflect)),
            "repeat"  => Ok (PaintServerSpread (cairo::enums::Extend::Repeat)),
            _         => Err (AttributeError::Parse (ParseError::new ("expected 'pad' | 'reflect' | 'repeat'")))
        }
    }
}

impl Default for PaintServerSpread {
    fn default () -> PaintServerSpread {
        PaintServerSpread (cairo::enums::Extend::Pad)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    Iri {
        iri: String,
        alternate: Option<Color>,
    },
    SolidColor(Color),
}

impl PaintServer {
    pub fn parse_input<'i, 't>(
        input: &mut cssparser::Parser<'i, 't>,
    ) -> Result<Self, AttributeError> {
        if let Ok(url) = input.try(|i| i.expect_url()) {
            Ok(PaintServer::Iri {
                iri: String::from(url.as_ref()),
                alternate: PaintServer::parse_fallback(input),
            })
        } else {
            PaintServer::parse_color(input).map(|color| PaintServer::SolidColor(color))
        }
    }

    fn parse_color<'i, 't>(input: &mut cssparser::Parser<'i, 't>) -> Result<Color, AttributeError> {
        if input.try(|i| i.expect_ident_matching("inherit")).is_ok() {
            Ok(Color::Inherit)
        } else if input.try(|i| i.expect_ident_matching("currentColor")).is_ok() {
            Ok(Color::CurrentColor)
        } else {
            input
                .try(|i| cssparser::Color::parse(i))
                .map(|c| Color::from(c))
                .map_err(|e| AttributeError::from(e))
        }
    }

    fn parse_fallback<'i, 't>(input: &mut cssparser::Parser<'i, 't>) -> Option<Color> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            None
        } else if input.try(|i| i.expect_ident_matching("currentColor")).is_ok() {
            Some(Color::CurrentColor)
        } else {
            input.try(|i| cssparser::Color::parse(i)).ok().map(|i| {
                Color::from(i)
            })
        }
    }
}

impl Parse for PaintServer {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<PaintServer, AttributeError> {
        let mut input = cssparser::ParserInput::new(s);
        PaintServer::parse_input(&mut cssparser::Parser::new(&mut input))
    }
}

fn _set_source_rsvg_solid_color(
    ctx: *mut drawing_ctx::RsvgDrawingCtx,
    color: &Color,
    opacity: u8,
    current_color: u32,
) {
    let rgba_color = match *color {
        Color::RGBA(rgba)   => Some(rgba),
        Color::CurrentColor => {
            if let Color::RGBA(rgba) = Color::from(current_color) {
                Some(rgba)
            } else {
                None
            }
        },

        _  => None
    };

    if let Some(rgba) = rgba_color {
        drawing_ctx::get_cairo_context(ctx).set_source_rgba(
            f64::from(rgba.red_f32()),
            f64::from(rgba.green_f32()),
            f64::from(rgba.blue_f32()),
            f64::from(rgba.alpha_f32()) * (f64::from(opacity) / 255.0)
        );
    }
}

/// Parses the paint specification, creating a new paint server object.
/// Return value: (nullable): The newly created paint server, or NULL on error.
///
/// # Arguments
///
/// * `str` - The SVG paint specification string to parse.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_parse(
    inherit: *mut glib_sys::gboolean,
    str: *const libc::c_char,
) -> *const PaintServer {

    if !inherit.is_null() {
        unsafe {
            *inherit = true.to_glib();
        }
    }

    let mut paint_server = PaintServer::parse(unsafe { utf8_cstr(str) }, ());

    if let Ok(PaintServer::SolidColor(ref mut color)) = paint_server {
        if *color == Color::Inherit {
            // FIXME: this is incorrect; we should inherit the paint server
            if !inherit.is_null() {
                unsafe {
                    *inherit = false.to_glib();
                }
            }

            *color = Color::RGBA(
                cssparser::RGBA{red: 0, green: 0, blue: 0, alpha: 255}
            );
        }
    }

    match paint_server {
        Ok(m)  => Rc::into_raw(Rc::new(m)),
        Err(_) => ptr::null_mut(),
    }
}

/// Increase references counter of `PaintServer`.
///
/// # Arguments
///
/// * `paint_server` - must be constructed with `rsvg_paint_server_parse`.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_ref(paint_server: *const PaintServer) {
    if paint_server.is_null() {
        return;
    }

    let server: Rc<PaintServer> = unsafe { Rc::from_raw(paint_server) };

    // forget about references
    Rc::into_raw(server.clone());
    Rc::into_raw(server);
}

/// Decrease references counter of `PaintServer`.
///
/// # Arguments
///
/// * `paint_server` - must be constructed with `rsvg_paint_server_parse`.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_unref(paint_server: *const PaintServer) {
    if paint_server.is_null() {
        return;
    }

    // drop reference
    unsafe { Rc::from_raw(paint_server) };
}

#[no_mangle]
pub extern "C" fn _set_source_rsvg_paint_server(
    c_ctx: *mut drawing_ctx::RsvgDrawingCtx,
    c_ps: *const PaintServer,
    opacity: u8,
    c_bbox: RsvgBbox,
    current_color: u32,
) -> glib_sys::gboolean {
    assert!(!c_ctx.is_null());
    assert!(!c_ps.is_null());

    let ps = unsafe { &*c_ps };
    let mut had_paint_server = false;

    match *ps {
        PaintServer::Iri {
            ref iri,
            ref alternate,
        } => {
            let node_ptr = drawing_ctx::acquire_node(c_ctx, iri.as_str());

            if !node_ptr.is_null() {
                let node = unsafe { &*node_ptr };

                if node.get_type() == NodeType::LinearGradient ||
                    node.get_type() == NodeType::RadialGradient
                {
                    had_paint_server = gradient::gradient_resolve_fallbacks_and_set_pattern(
                        node,
                        c_ctx,
                        opacity,
                        &c_bbox,
                    );
                } else if node.get_type() == NodeType::Pattern {
                    had_paint_server = pattern::pattern_resolve_fallbacks_and_set_pattern(node, c_ctx, &c_bbox);
                }
            }

            if !had_paint_server && alternate.is_some() {
                _set_source_rsvg_solid_color(
                    c_ctx,
                    alternate.as_ref().unwrap(),
                    opacity,
                    current_color,
                    );
                had_paint_server = true;
            }

            drawing_ctx::release_node(c_ctx, node_ptr);
        },

        PaintServer::SolidColor(color) => {
            _set_source_rsvg_solid_color(c_ctx, &color, opacity, current_color);
            had_paint_server = true;
        }
    };

    had_paint_server.to_glib()
}

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

    #[test]
    fn parses_spread_method () {
        assert_eq! (PaintServerSpread::parse ("pad", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Pad)));

        assert_eq! (PaintServerSpread::parse ("reflect", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Reflect)));

        assert_eq! (PaintServerSpread::parse ("repeat", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Repeat)));

        assert! (PaintServerSpread::parse ("foobar", ()).is_err ());
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse("rgb(255, 128, 64, 0.5)", ()),
            Ok(PaintServer::SolidColor(Color::from(0x80ff8040)))
        );

        assert_eq!(
            PaintServer::parse("inherit", ()),
            Ok(PaintServer::SolidColor(Color::Inherit))
        );

        assert_eq!(
            PaintServer::parse("currentColor", ()),
            Ok(PaintServer::SolidColor(Color::CurrentColor))
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse("url(#link)", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) none", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) #ff8040", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::from(0xffff8040)),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) rgb(255, 128, 64, 0.5)", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::from(0x80ff8040)),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) currentColor", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::CurrentColor),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) inherit", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );
    }

    #[test]
    fn paint_server_refs_and_unrefs() {
        let rc = Rc::new(PaintServer::parse("#ffffff", ()).unwrap());
        let weak = Rc::downgrade(&rc);
        let ps = Rc::into_raw(rc);

        rsvg_paint_server_ref(ps);
        assert!(weak.upgrade().is_some());

        rsvg_paint_server_unref(ps);
        assert!(weak.upgrade().is_some());

        rsvg_paint_server_unref(ps);
        assert!(weak.upgrade().is_none());
    }
}
<commit_msg>cargo-clippy: Remove redundant closures<commit_after>use cairo;
use cssparser;
use glib_sys;
use glib::translate::*;
use libc;

use std::rc::Rc;
use std::ptr;

use bbox::RsvgBbox;
use color::Color;
use drawing_ctx;
use error::*;
use gradient;
use node::NodeType;
use parsers::{Parse, ParseError};
use pattern;
use util::utf8_cstr;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PaintServerSpread (pub cairo::enums::Extend);

impl Parse for PaintServerSpread {
    type Data = ();
    type Err = AttributeError;

    fn parse (s: &str, _: ()) -> Result <PaintServerSpread, AttributeError> {
        match s {
            "pad"     => Ok (PaintServerSpread (cairo::enums::Extend::Pad)),
            "reflect" => Ok (PaintServerSpread (cairo::enums::Extend::Reflect)),
            "repeat"  => Ok (PaintServerSpread (cairo::enums::Extend::Repeat)),
            _         => Err (AttributeError::Parse (ParseError::new ("expected 'pad' | 'reflect' | 'repeat'")))
        }
    }
}

impl Default for PaintServerSpread {
    fn default () -> PaintServerSpread {
        PaintServerSpread (cairo::enums::Extend::Pad)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    Iri {
        iri: String,
        alternate: Option<Color>,
    },
    SolidColor(Color),
}

impl PaintServer {
    pub fn parse_input<'i, 't>(
        input: &mut cssparser::Parser<'i, 't>,
    ) -> Result<Self, AttributeError> {
        if let Ok(url) = input.try(|i| i.expect_url()) {
            Ok(PaintServer::Iri {
                iri: String::from(url.as_ref()),
                alternate: PaintServer::parse_fallback(input),
            })
        } else {
            PaintServer::parse_color(input).map(PaintServer::SolidColor)
        }
    }

    fn parse_color<'i, 't>(input: &mut cssparser::Parser<'i, 't>) -> Result<Color, AttributeError> {
        if input.try(|i| i.expect_ident_matching("inherit")).is_ok() {
            Ok(Color::Inherit)
        } else if input.try(|i| i.expect_ident_matching("currentColor")).is_ok() {
            Ok(Color::CurrentColor)
        } else {
            input
                .try(|i| cssparser::Color::parse(i))
                .map(Color::from)
                .map_err(AttributeError::from)
        }
    }

    fn parse_fallback<'i, 't>(input: &mut cssparser::Parser<'i, 't>) -> Option<Color> {
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            None
        } else if input.try(|i| i.expect_ident_matching("currentColor")).is_ok() {
            Some(Color::CurrentColor)
        } else {
            input.try(|i| cssparser::Color::parse(i)).ok().map(|i| {
                Color::from(i)
            })
        }
    }
}

impl Parse for PaintServer {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _: ()) -> Result<PaintServer, AttributeError> {
        let mut input = cssparser::ParserInput::new(s);
        PaintServer::parse_input(&mut cssparser::Parser::new(&mut input))
    }
}

fn _set_source_rsvg_solid_color(
    ctx: *mut drawing_ctx::RsvgDrawingCtx,
    color: &Color,
    opacity: u8,
    current_color: u32,
) {
    let rgba_color = match *color {
        Color::RGBA(rgba)   => Some(rgba),
        Color::CurrentColor => {
            if let Color::RGBA(rgba) = Color::from(current_color) {
                Some(rgba)
            } else {
                None
            }
        },

        _  => None
    };

    if let Some(rgba) = rgba_color {
        drawing_ctx::get_cairo_context(ctx).set_source_rgba(
            f64::from(rgba.red_f32()),
            f64::from(rgba.green_f32()),
            f64::from(rgba.blue_f32()),
            f64::from(rgba.alpha_f32()) * (f64::from(opacity) / 255.0)
        );
    }
}

/// Parses the paint specification, creating a new paint server object.
/// Return value: (nullable): The newly created paint server, or NULL on error.
///
/// # Arguments
///
/// * `str` - The SVG paint specification string to parse.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_parse(
    inherit: *mut glib_sys::gboolean,
    str: *const libc::c_char,
) -> *const PaintServer {

    if !inherit.is_null() {
        unsafe {
            *inherit = true.to_glib();
        }
    }

    let mut paint_server = PaintServer::parse(unsafe { utf8_cstr(str) }, ());

    if let Ok(PaintServer::SolidColor(ref mut color)) = paint_server {
        if *color == Color::Inherit {
            // FIXME: this is incorrect; we should inherit the paint server
            if !inherit.is_null() {
                unsafe {
                    *inherit = false.to_glib();
                }
            }

            *color = Color::RGBA(
                cssparser::RGBA{red: 0, green: 0, blue: 0, alpha: 255}
            );
        }
    }

    match paint_server {
        Ok(m)  => Rc::into_raw(Rc::new(m)),
        Err(_) => ptr::null_mut(),
    }
}

/// Increase references counter of `PaintServer`.
///
/// # Arguments
///
/// * `paint_server` - must be constructed with `rsvg_paint_server_parse`.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_ref(paint_server: *const PaintServer) {
    if paint_server.is_null() {
        return;
    }

    let server: Rc<PaintServer> = unsafe { Rc::from_raw(paint_server) };

    // forget about references
    Rc::into_raw(server.clone());
    Rc::into_raw(server);
}

/// Decrease references counter of `PaintServer`.
///
/// # Arguments
///
/// * `paint_server` - must be constructed with `rsvg_paint_server_parse`.
#[no_mangle]
pub extern "C" fn rsvg_paint_server_unref(paint_server: *const PaintServer) {
    if paint_server.is_null() {
        return;
    }

    // drop reference
    unsafe { Rc::from_raw(paint_server) };
}

#[no_mangle]
pub extern "C" fn _set_source_rsvg_paint_server(
    c_ctx: *mut drawing_ctx::RsvgDrawingCtx,
    c_ps: *const PaintServer,
    opacity: u8,
    c_bbox: RsvgBbox,
    current_color: u32,
) -> glib_sys::gboolean {
    assert!(!c_ctx.is_null());
    assert!(!c_ps.is_null());

    let ps = unsafe { &*c_ps };
    let mut had_paint_server = false;

    match *ps {
        PaintServer::Iri {
            ref iri,
            ref alternate,
        } => {
            let node_ptr = drawing_ctx::acquire_node(c_ctx, iri.as_str());

            if !node_ptr.is_null() {
                let node = unsafe { &*node_ptr };

                if node.get_type() == NodeType::LinearGradient ||
                    node.get_type() == NodeType::RadialGradient
                {
                    had_paint_server = gradient::gradient_resolve_fallbacks_and_set_pattern(
                        node,
                        c_ctx,
                        opacity,
                        &c_bbox,
                    );
                } else if node.get_type() == NodeType::Pattern {
                    had_paint_server = pattern::pattern_resolve_fallbacks_and_set_pattern(node, c_ctx, &c_bbox);
                }
            }

            if !had_paint_server && alternate.is_some() {
                _set_source_rsvg_solid_color(
                    c_ctx,
                    alternate.as_ref().unwrap(),
                    opacity,
                    current_color,
                    );
                had_paint_server = true;
            }

            drawing_ctx::release_node(c_ctx, node_ptr);
        },

        PaintServer::SolidColor(color) => {
            _set_source_rsvg_solid_color(c_ctx, &color, opacity, current_color);
            had_paint_server = true;
        }
    };

    had_paint_server.to_glib()
}

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

    #[test]
    fn parses_spread_method () {
        assert_eq! (PaintServerSpread::parse ("pad", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Pad)));

        assert_eq! (PaintServerSpread::parse ("reflect", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Reflect)));

        assert_eq! (PaintServerSpread::parse ("repeat", ()),
                    Ok (PaintServerSpread (cairo::enums::Extend::Repeat)));

        assert! (PaintServerSpread::parse ("foobar", ()).is_err ());
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse("rgb(255, 128, 64, 0.5)", ()),
            Ok(PaintServer::SolidColor(Color::from(0x80ff8040)))
        );

        assert_eq!(
            PaintServer::parse("inherit", ()),
            Ok(PaintServer::SolidColor(Color::Inherit))
        );

        assert_eq!(
            PaintServer::parse("currentColor", ()),
            Ok(PaintServer::SolidColor(Color::CurrentColor))
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse("url(#link)", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) none", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) #ff8040", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::from(0xffff8040)),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) rgb(255, 128, 64, 0.5)", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::from(0x80ff8040)),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) currentColor", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: Some(Color::CurrentColor),
            })
        );

        assert_eq!(
            PaintServer::parse("url(#link) inherit", ()),
            Ok(PaintServer::Iri {
                iri: "#link".to_string(),
                alternate: None,
            })
        );
    }

    #[test]
    fn paint_server_refs_and_unrefs() {
        let rc = Rc::new(PaintServer::parse("#ffffff", ()).unwrap());
        let weak = Rc::downgrade(&rc);
        let ps = Rc::into_raw(rc);

        rsvg_paint_server_ref(ps);
        assert!(weak.upgrade().is_some());

        rsvg_paint_server_unref(ps);
        assert!(weak.upgrade().is_some());

        rsvg_paint_server_unref(ps);
        assert!(weak.upgrade().is_none());
    }
}
<|endoftext|>


<commit_before>extern crate time;

use std::io::net::udp::UdpSocket;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

#[allow(dead_code,non_camel_case_types)]
enum UtpPacketType {
    ST_DATA  = 0,
    ST_FIN   = 1,
    ST_STATE = 2,
    ST_RESET = 3,
    ST_SYN   = 4,
}

#[allow(dead_code)]
struct UtpPacketHeader {
    type_ver: u8, // type: u4, ver: u4
    extension: u8,
    connection_id: u16,
    timestamp_microseconds: u32,
    timestamp_difference_microseconds: u32,
    wnd_size: u32,
    seq_nr: u16,
    ack_nr: u16,
}

impl UtpPacketHeader {
    fn bytes(&self) -> &[u8] {
        unsafe {
            let buf: &[u8, ..20] = std::mem::transmute(self);
            return buf.as_slice();
        }
    }

    fn len(&self) -> uint {
        let header_size = 20;
        return header_size;
    }
}

#[allow(dead_code)]
struct UtpPacket {
    header: UtpPacketHeader,
    payload: Vec<u8>,
}

impl UtpPacket {
    /// Constructs a new, empty UtpPacket.
    fn new() -> UtpPacket {
        UtpPacket {
            header: UtpPacketHeader {
                type_ver: ST_DATA as u8 << 4 | 1,
                extension: 0,
                connection_id: 0,
                timestamp_microseconds: 0,
                timestamp_difference_microseconds: 0,
                wnd_size: 0,
                seq_nr: 0,
                ack_nr: 0,
            },
            payload: Vec::new(),
        }
    }

    fn bytes(&self) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::with_capacity(self.len());
        buf.push_all(self.header.bytes());
        buf.push_all(self.payload.as_slice());
        return buf;
    }

    fn len(&self) -> uint {
        self.header.len() + self.payload.len()
    }
}

struct UtpSocket {
    skt: UdpSocket,
    seq_nr: u16,
}

impl UtpSocket {
    fn bind(addr: SocketAddr) -> std::io::IoResult<UtpSocket> {
        let skt = UdpSocket::bind(addr);
        match skt {
            Ok(x)  => Ok(UtpSocket { skt: x, seq_nr: 1 }),
            Err(e) => Err(e)
        }
    }

    fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> std::io::IoResult<()> {
        let mut packet = UtpPacket::new();
        packet.payload = Vec::from_slice(buf);
        // Those should be hidden inside an abstraction
        packet.header.seq_nr = std::mem::to_be16(self.seq_nr);
        packet.header.connection_id = std::mem::to_be16(std::rand::random());
        let t = time::get_time();
        packet.header.timestamp_microseconds = std::mem::to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

        // Send packet
        let r = self.skt.sendto(packet.bytes().as_slice(), dst);

        self.seq_nr += 1;
        r
    }

    fn recvfrom(&mut self, buf: &mut[u8]) -> std::io::IoResult<(uint,SocketAddr)> {
        self.skt.recvfrom(buf)
    }
}

fn main() {
    let mut buf = [0, ..512];
    let mut sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 }).unwrap();

    match sock.recvfrom(buf) {
        Ok((_, src)) => {
            let payload = String::from_str("Hello\n").into_bytes();

            // Send uTP packet
            let _ = sock.sendto(payload.as_slice(), src);
        }
        Err(_) => {}
    }
    drop(sock);
}
<commit_msg>Move Utp stuff into a module.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            let header_size = 20;
            return header_size;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        skt: UdpSocket,
        seq_nr: u16,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { skt: x, seq_nr: 1 }),
                Err(e) => Err(e)
            }
        }

        pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            // Those should be hidden inside an abstraction
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let r = self.skt.sendto(packet.bytes().as_slice(), dst);

            self.seq_nr += 1;
            r
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.skt.recvfrom(buf)
        }
    }
}

fn main() {
    let mut buf = [0, ..512];
    let mut sock = libtorresmo::UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 }).unwrap();

    match sock.recvfrom(buf) {
        Ok((_, src)) => {
            let payload = String::from_str("Hello\n").into_bytes();

            // Send uTP packet
            let _ = sock.sendto(payload.as_slice(), src);
        }
        Err(_) => {}
    }
    drop(sock);
}
<|endoftext|>