<commit_before>export Image;

export load;
export load_from_memory;
export test_image_bin;

import stb_image = stb_image::image;

// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.

type Image = stb_image::image;

fn Image(width: uint, height: uint, depth: uint, +data: ~[u8]) -> Image {
    stb_image::image(width, height, depth, data)
}

const TEST_IMAGE: [u8 * 4962] = #include_bin("test.jpeg");

fn test_image_bin() -> ~[u8] {
    return vec::from_fn(4962, |i| TEST_IMAGE[i]);
}

fn load_from_memory(buffer: &[u8]) -> option<Image> {
    do stb_image::load_from_memory(buffer).map |image| {

        // Do color space conversion :(
        let data = do vec::from_fn(image.width * image.height * 4) |i| {
            let color = i % 4;
            let pixel = i / 4;
            match color {
              0 => image.data[pixel * 3 + 2],
              1 => image.data[pixel * 3 + 1],
              2 => image.data[pixel * 3 + 0],
              3 => 0xffu8,
              _ => fail
            }
        };

        stb_image::image(image.width, image.height, image.depth, data)
    }
}
<commit_msg>Fix colorspace correction<commit_after>export Image;

export load;
export load_from_memory;
export test_image_bin;

import stb_image = stb_image::image;

// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.

type Image = stb_image::image;

fn Image(width: uint, height: uint, depth: uint, +data: ~[u8]) -> Image {
    stb_image::image(width, height, depth, data)
}

const TEST_IMAGE: [u8 * 4962] = #include_bin("test.jpeg");

fn test_image_bin() -> ~[u8] {
    return vec::from_fn(4962, |i| TEST_IMAGE[i]);
}

fn load_from_memory(buffer: &[u8]) -> option<Image> {
    do stb_image::load_from_memory(buffer).map |image| {

        assert image.depth == 4;
        // Do color space conversion :(
        let data = do vec::from_fn(image.width * image.height * 4) |i| {
            let color = i % 4;
            let pixel = i / 4;
            match color {
              0 => image.data[pixel * 4 + 2],
              1 => image.data[pixel * 4 + 1],
              2 => image.data[pixel * 4 + 0],
              3 => 0xffu8,
              _ => fail
            }
        };

        assert image.data.len() == data.len();

        stb_image::image(image.width, image.height, image.depth, data)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::{RwLock, Mutex};

use fs2::FileExt;

use entry::Entry;
use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub type StoreId = PathBuf;

trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl<'a> IntoStoreId for &'a str {
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl<'a> IntoStoreId for &'a String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

impl<'a> IntoStoreId for &'a PathBuf {
    fn into_storeid(self) -> StoreId {
        self.clone()
    }
}

impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
    fn into_storeid(self) -> StoreId {
        let (first, second) = self;
        let mut res : StoreId = first.into_storeid();
        res.push(second.into_storeid());
        res
    }
}

pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, (File, Option<Entry>)>>>,
}

impl Store {
    fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    fn delete(&self, id: StoreId) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| (f.1).0.unlock());
    }

}

pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        let mut map = self.store.entries.write().unwrap();
        let (_, ref mut en) = *map.get_mut(&self.key).unwrap();
        *en = Some(self.entry.clone());
    }
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use store::{StoreId, IntoStoreId};

    #[test]
    fn into_storeid_trait() {
        let buf = PathBuf::from("abc/def");

        let test = ("abc", "def");
        assert_eq!(buf, test.into_storeid());

        let test = "abc/def";
        assert_eq!(buf, test.into_storeid());

        let test = String::from("abc/def");
        assert_eq!(buf, test.into_storeid());

        let test = PathBuf::from("abc/def");
        assert_eq!(buf, test.into_storeid());
    }
}

<commit_msg>Use StoreEntry instead of a tuple<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::{RwLock, Mutex};

use fs2::FileExt;

use entry::Entry;
use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub type StoreId = PathBuf;

trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl<'a> IntoStoreId for &'a str {
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl<'a> IntoStoreId for &'a String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

impl<'a> IntoStoreId for &'a PathBuf {
    fn into_storeid(self) -> StoreId {
        self.clone()
    }
}

impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
    fn into_storeid(self) -> StoreId {
        let (first, second) = self;
        let mut res : StoreId = first.into_storeid();
        res.push(second.into_storeid());
        res
    }
}

struct StoreEntry {
    file: File,
    entry: Option<Entry>,
}

impl StoreEntry {
    fn is_borrowed(&self) -> bool {
        self.entry.is_none()
    }

    fn set_entry(&mut self, entry: Entry) -> Result<()> {
        self.entry = Some(entry);
        unimplemented!()
    }

    fn get_entry(&mut self) -> Result<Entry> {
        unimplemented!()
    }
}

pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
}

impl Store {
    fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    fn delete(&self, id: StoreId) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| f.1.file.unlock());
    }

}

pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        let mut map = self.store.entries.write().unwrap();
        map.get_mut(&self.key).unwrap().set_entry(self.entry.clone());
    }
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use store::{StoreId, IntoStoreId};

    #[test]
    fn into_storeid_trait() {
        let buf = PathBuf::from("abc/def");

        let test = ("abc", "def");
        assert_eq!(buf, test.into_storeid());

        let test = "abc/def";
        assert_eq!(buf, test.into_storeid());

        let test = String::from("abc/def");
        assert_eq!(buf, test.into_storeid());

        let test = PathBuf::from("abc/def");
        assert_eq!(buf, test.into_storeid());
    }
}

<|endoftext|>


<commit_before>//! Standard library macros
//!
//! This module contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[doc(include = "../../core/src/macros/panic.md")]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(libstd_sys_internals)]
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "std_panic_macro")]
macro_rules! panic {
    () => ({ $crate::panic!("explicit panic") });
    ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
    ($fmt:expr, $($arg:tt)+) => ({
        $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))
    });
}

/// Prints to the standard output.
///
/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [flush]: crate::io::Write::flush
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// print!("this ");
/// print!("will ");
/// print!("be ");
/// print!("on ");
/// print!("the ");
/// print!("same ");
/// print!("line ");
///
/// io::stdout().flush().unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n");
///
/// io::stdout().flush().unwrap();
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
    ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
}

/// Prints to the standard output, with a newline.
///
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// [`std::fmt`]: crate::fmt
///
/// # Panics
///
/// Panics if writing to [`io::stdout`] fails.
///
/// [`io::stdout`]: crate::io::stdout
///
/// # Examples
///
/// ```
/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}

/// Prints to the standard error.
///
/// Equivalent to the [`print!`] macro, except that output goes to
/// [`io::stderr`] instead of [`io::stdout`]. See [`print!`] for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprint!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
    ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
}

/// Prints to the standard error, with a newline.
///
/// Equivalent to the [`println!`] macro, except that output goes to
/// [`io::stderr`] instead of [`io::stdout`]. See [`println!`] for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprintln!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
    () => ($crate::eprint!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_eprint($crate::format_args_nl!($($arg)*));
    })
}

/// Prints and returns the value of a given expression for quick and dirty
/// debugging.
///
/// An example:
///
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
/// The macro works by using the `Debug` implementation of the type of
/// the given expression to print the value to [stderr] along with the
/// source location of the macro invocation as well as the source code
/// of the expression.
///
/// Invoking the macro on an expression moves and takes ownership of it
/// before returning the evaluated expression unchanged. If the type
/// of the expression does not implement `Copy` and you don't want
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
/// for some expression `expr`.
///
/// The `dbg!` macro works exactly the same in release builds.
/// This is useful when debugging issues that only occur in release
/// builds or when debugging in release mode is significantly faster.
///
/// Note that the macro is intended as a debugging tool and therefore you
/// should avoid having uses of it in version control for long periods.
/// Use cases involving debug output that should be added to version control
/// are better served by macros such as [`debug!`] from the [`log`] crate.
///
/// # Stability
///
/// The exact output printed by this macro should not be relied upon
/// and is subject to future changes.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Further examples
///
/// With a method call:
///
/// ```rust
/// fn foo(n: usize) {
///     if let Some(_) = dbg!(n.checked_sub(4)) {
///         // ...
///     }
/// }
///
/// foo(3)
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// ```
///
/// Naive factorial implementation:
///
/// ```rust
/// fn factorial(n: u32) -> u32 {
///     if dbg!(n <= 1) {
///         dbg!(1)
///     } else {
///         dbg!(n * factorial(n - 1))
///     }
/// }
///
/// dbg!(factorial(4));
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// ```
///
/// The `dbg!(..)` macro moves the input:
///
/// ```compile_fail
/// /// A wrapper around `usize` which importantly is not Copyable.
/// #[derive(Debug)]
/// struct NoCopy(usize);
///
/// let a = NoCopy(42);
/// let _ = dbg!(a); // <-- `a` is moved here.
/// let _ = dbg!(a); // <-- `a` is moved again; error!
/// ```
///
/// You can also use `dbg!()` without a value to just print the
/// file and line whenever it's reached.
///
/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
/// a tuple (and return it, too):
///
/// ```
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
/// ```
///
/// However, a single argument with a trailing comma will still not be treated
/// as a tuple, following the convention of ignoring trailing commas in macro
/// invocations. You can use a 1-tuple directly if you need one:
///
/// ```
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
/// ```
///
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
#[macro_export]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
    () => {
        $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
    };
    ($val:expr $(,)?) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::eprintln!("[{}:{}] {} = {:#?}",
                    $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}

#[cfg(test)]
macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
    }};
}
<commit_msg>Add cfg(not(test)) to std_panic_macro rustc_diagnostic_item.<commit_after>//! Standard library macros
//!
//! This module contains a set of macros which are exported from the standard
//! library. Each macro is available for use when linking against the standard
//! library.

#[doc(include = "../../core/src/macros/panic.md")]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(libstd_sys_internals)]
#[cfg_attr(not(any(bootstrap, test)), rustc_diagnostic_item = "std_panic_macro")]
macro_rules! panic {
    () => ({ $crate::panic!("explicit panic") });
    ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) });
    ($fmt:expr, $($arg:tt)+) => ({
        $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))
    });
}

/// Prints to the standard output.
///
/// Equivalent to the [`println!`] macro except that a newline is not printed at
/// the end of the message.
///
/// Note that stdout is frequently line-buffered by default so it may be
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [flush]: crate::io::Write::flush
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// print!("this ");
/// print!("will ");
/// print!("be ");
/// print!("on ");
/// print!("the ");
/// print!("same ");
/// print!("line ");
///
/// io::stdout().flush().unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n");
///
/// io::stdout().flush().unwrap();
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
    ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
}

/// Prints to the standard output, with a newline.
///
/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)).
///
/// Use the [`format!`] syntax to write data to the standard output.
/// See [`std::fmt`] for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// [`std::fmt`]: crate::fmt
///
/// # Panics
///
/// Panics if writing to [`io::stdout`] fails.
///
/// [`io::stdout`]: crate::io::stdout
///
/// # Examples
///
/// ```
/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}

/// Prints to the standard error.
///
/// Equivalent to the [`print!`] macro, except that output goes to
/// [`io::stderr`] instead of [`io::stdout`]. See [`print!`] for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprint!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
    ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
}

/// Prints to the standard error, with a newline.
///
/// Equivalent to the [`println!`] macro, except that output goes to
/// [`io::stderr`] instead of [`io::stdout`]. See [`println!`] for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Examples
///
/// ```
/// eprintln!("Error: Could not complete task");
/// ```
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
    () => ($crate::eprint!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_eprint($crate::format_args_nl!($($arg)*));
    })
}

/// Prints and returns the value of a given expression for quick and dirty
/// debugging.
///
/// An example:
///
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
/// The macro works by using the `Debug` implementation of the type of
/// the given expression to print the value to [stderr] along with the
/// source location of the macro invocation as well as the source code
/// of the expression.
///
/// Invoking the macro on an expression moves and takes ownership of it
/// before returning the evaluated expression unchanged. If the type
/// of the expression does not implement `Copy` and you don't want
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
/// for some expression `expr`.
///
/// The `dbg!` macro works exactly the same in release builds.
/// This is useful when debugging issues that only occur in release
/// builds or when debugging in release mode is significantly faster.
///
/// Note that the macro is intended as a debugging tool and therefore you
/// should avoid having uses of it in version control for long periods.
/// Use cases involving debug output that should be added to version control
/// are better served by macros such as [`debug!`] from the [`log`] crate.
///
/// # Stability
///
/// The exact output printed by this macro should not be relied upon
/// and is subject to future changes.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
///
/// # Further examples
///
/// With a method call:
///
/// ```rust
/// fn foo(n: usize) {
///     if let Some(_) = dbg!(n.checked_sub(4)) {
///         // ...
///     }
/// }
///
/// foo(3)
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// ```
///
/// Naive factorial implementation:
///
/// ```rust
/// fn factorial(n: u32) -> u32 {
///     if dbg!(n <= 1) {
///         dbg!(1)
///     } else {
///         dbg!(n * factorial(n - 1))
///     }
/// }
///
/// dbg!(factorial(4));
/// ```
///
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// ```
///
/// The `dbg!(..)` macro moves the input:
///
/// ```compile_fail
/// /// A wrapper around `usize` which importantly is not Copyable.
/// #[derive(Debug)]
/// struct NoCopy(usize);
///
/// let a = NoCopy(42);
/// let _ = dbg!(a); // <-- `a` is moved here.
/// let _ = dbg!(a); // <-- `a` is moved again; error!
/// ```
///
/// You can also use `dbg!()` without a value to just print the
/// file and line whenever it's reached.
///
/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
/// a tuple (and return it, too):
///
/// ```
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
/// ```
///
/// However, a single argument with a trailing comma will still not be treated
/// as a tuple, following the convention of ignoring trailing commas in macro
/// invocations. You can use a 1-tuple directly if you need one:
///
/// ```
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
/// ```
///
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
#[macro_export]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
    () => {
        $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
    };
    ($val:expr $(,)?) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::eprintln!("[{}:{}] {} = {:#?}",
                    $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}

#[cfg(test)]
macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => {{
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
    }};
}
<|endoftext|>


<commit_before>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

use std::ptr;

// Restore the original signal from a fixed linear prediction.
//
// Signal restoration is accomplished by summing up the residual and the
// predictor. With the linear prediction being "fixed", the polynomials will
// remain the same depending on the order value. And the max order is
// `MAX_FIXED_ORDER`, which is 4.
//
// This function also assumes that `output` already has the warm up values
// from the `Fixed` subframe in it.
pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

/// Decodes the current subframe.
///
/// * `Constant` - fills the length of `output` with the constant value
///   within the subframe.
/// * `Verbatim` - copies the data within the verbatim subframe over to
///   `output`.
/// * `Fixed` - restore the signal of the fixed linear prediction and put
///   the result into `output`.
/// * `LPC` - restore the signal of the finite impulse response linear
///   prediction and put the result into `output`.
pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(constant)     => {
      for i in 0..output.len() {
        output[i] = constant
      }
    }
    subframe::Data::Verbatim(ref verbatim) => {
      let length = verbatim.len();

      unsafe {
        ptr::copy(verbatim.as_ptr(), output.as_mut_ptr(), length)
      }
    }
    subframe::Data::Fixed(ref fixed)       => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(ref lpc)           => {
      let order        = lpc.order as usize;
      let coefficients = &lpc.qlp_coefficients[0..order];

      for i in 0..order {
        output[i] = lpc.warmup[i];
      }

      lpc_restore_signal(lpc.quantization_level, coefficients, &lpc.residual,
                         output);
    }
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}

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

  use subframe;
  use subframe::{
    Subframe, Fixed, LPC,
    EntropyCodingMethod, CodingMethod, PartitionedRice,
    PartitionedRiceContents,
  };

  #[test]
  fn test_fixed_restore_signal() {
    let residuals   = [ &[-19, -16, 17, -23, -7, 16, -16, -5, 3
                         , -8, -13, -15, -1][..]
                      , &[-6513][..]
                      ];
    let mut outputs = [ &mut [-729, -722, -667, 0, 0, 0, 0, 0, 0
                             , 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [21877, 27482, 0][..]
                      ];

    fixed_restore_signal(3, &residuals[0], &mut outputs[0]);
    fixed_restore_signal(2, &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-729, -722, -667, -583, -486, -359, -225, -91
                             , 59, 209, 354, 497, 630, 740, 812, 845]);
    assert_eq!(&outputs[1], &[21877, 27482, 26574]);
  }

  #[test]
  fn test_lpc_restore_signal() {
    let residuals    = [ &[-2, -23, 14, 6, 3, -4, 12, -2, 10][..]
                       , &[3157][..]
                       ];
    let coefficients = [ &[1042, -399, -75, -269, 121, 166, -75][..]
                       , &[1757, -1199, 879, -836, 555, -255, 119][..]
                       ];
    let mut outputs = [ &mut [-796, -547, -285, -32, 199, 443, 670
                             , 0, 0, 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [-21363, -21951, -22649, -24364, -27297, -26870
                             ,-30017, 0][..]
                      ];

    lpc_restore_signal(9, &coefficients[0], &residuals[0], &mut outputs[0]);
    lpc_restore_signal(10, &coefficients[1], &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-796, -547, -285, -32, 199, 443, 670, 875
                             , 1046, 1208, 1343, 1454, 1541, 1616, 1663
                             , 1701]);
    assert_eq!(&outputs[1], &[-21363, -21951, -22649, -24364, -27297, -26870
                             , -30017, -29718]);
  }

  #[test]
  fn test_decode() {
    let mut output = [0; 16];

    let constant = Subframe {
      data: subframe::Data::Constant(4),
      wasted_bits: 0,
    };

    let verbatim = Subframe {
      data: subframe::Data::Verbatim(vec![16, -3, 55, 49, -32, 6, 40, -90, 1
                                         ,0, 77, -12, 84, 10, -112, 136]),
      wasted_bits: 0,
    };

    let fixed = Subframe {
      data: subframe::Data::Fixed(Fixed {
        entropy_coding_method: EntropyCodingMethod {
          method_type: CodingMethod::PartitionedRice,
          data: PartitionedRice {
            order: 0,
            contents: PartitionedRiceContents {
              parameters: vec![],
              raw_bits: vec![],
            },
          },
        },
        order: 3,
        warmup: [-729, -722, -667, 0],
        residual: vec![-19, -16, 17, -23, -7, 16, -16, -5, 3 , -8, -13, -15
                      ,-1],
      }),
      wasted_bits: 0,
    };

    let lpc = Subframe {
      data: subframe::Data::LPC(LPC {
        entropy_coding_method: EntropyCodingMethod {
          method_type: CodingMethod::PartitionedRice,
          data: PartitionedRice {
            order: 0,
            contents: PartitionedRiceContents {
              parameters: vec![],
              raw_bits: vec![],
            },
          },
        },
        order: 7,
        qlp_coeff_precision: 0,
        quantization_level: 9,
        qlp_coefficients: [1042, -399, -75, -269, 121, 166, -75, 0, 0, 0, 0
                          ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                          ,0, 0, 0, 0],
        warmup: [-796, -547, -285, -32, 199, 443, 670, 0, 0, 0, 0, 0, 0, 0, 0
                ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        residual: vec![-2, -23, 14, 6, 3, -4, 12, -2, 10],
      }),
      wasted_bits: 0,
    };

    decode(&constant, &mut output);
    assert_eq!(&output, &[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]);

    decode(&verbatim, &mut output);
    assert_eq!(&output, &[16, -3, 55, 49, -32, 6, 40 , -90, 1, 0, 77, -12, 84
                         ,10 , -112, 136]);

    decode(&fixed, &mut output);
    assert_eq!(&output, &[-729, -722, -667, -583, -486, -359, -225, -91, 59
                         ,209, 354, 497, 630, 740, 812, 845]);

    decode(&lpc, &mut output);
    assert_eq!(&output, &[-796, -547, -285, -32, 199, 443, 670, 875, 1046
                         ,1208, 1343, 1454, 1541, 1616, 1663, 1701]);
  }

  #[test]
  fn test_wasted_bit_decode() {
    let mut output = [0; 4];

    let constant = Subframe {
      data: subframe::Data::Constant(1),
      wasted_bits: 10,
    };

    decode(&constant, &mut output);
    assert_eq!(&output, &[1024, 1024, 1024, 1024]);
  }
}
<commit_msg>Add explanation for `lpc_restore_signal`<commit_after>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

use std::ptr;

// Restore the original signal from a fixed linear prediction.
//
// Signal restoration is accomplished by summing up the residual and the
// predictor. With the linear prediction being "fixed", the polynomials will
// remain the same depending on the order value. And the max order is
// `MAX_FIXED_ORDER`, which is 4.
//
// This function also assumes that `output` already has the warm up values
// from the `Fixed` subframe in it.
pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

// Restore the original signal from a FIR linear prediction.
//
// Signal restoration is accomplished by summing up the residual and the
// predictor. Figuring out the linear prediction for finite impulse response
// is a bit more involved because you have more to deal with, but the
// concept is very similar to the fixed version. Coefficients are passed in
// and reversed within function and the result of these reverse order
// coefficients and warm up values are summed and the quantization level
// will determine how much the bits gets shifted in order to figure the
// current predictor for it's corresponding residual value.
//
// The order doesn't get passed in explicitly because the coefficients
// length is assumed to be the value of order. And the max order is
// `MAX_LPC_ORDER`, which is 32. This function also assumes that `output`
// already has the warm up values from the `LPC` subframe in it.
pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

/// Decodes the current subframe.
///
/// * `Constant` - fills the length of `output` with the constant value
///   within the subframe.
/// * `Verbatim` - copies the data within the verbatim subframe over to
///   `output`.
/// * `Fixed` - restore the signal of the fixed linear prediction and put
///   the result into `output`.
/// * `LPC` - restore the signal of the finite impulse response linear
///   prediction and put the result into `output`.
pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(constant)     => {
      for i in 0..output.len() {
        output[i] = constant
      }
    }
    subframe::Data::Verbatim(ref verbatim) => {
      let length = verbatim.len();

      unsafe {
        ptr::copy(verbatim.as_ptr(), output.as_mut_ptr(), length)
      }
    }
    subframe::Data::Fixed(ref fixed)       => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(ref lpc)           => {
      let order        = lpc.order as usize;
      let coefficients = &lpc.qlp_coefficients[0..order];

      for i in 0..order {
        output[i] = lpc.warmup[i];
      }

      lpc_restore_signal(lpc.quantization_level, coefficients, &lpc.residual,
                         output);
    }
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}

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

  use subframe;
  use subframe::{
    Subframe, Fixed, LPC,
    EntropyCodingMethod, CodingMethod, PartitionedRice,
    PartitionedRiceContents,
  };

  #[test]
  fn test_fixed_restore_signal() {
    let residuals   = [ &[-19, -16, 17, -23, -7, 16, -16, -5, 3
                         , -8, -13, -15, -1][..]
                      , &[-6513][..]
                      ];
    let mut outputs = [ &mut [-729, -722, -667, 0, 0, 0, 0, 0, 0
                             , 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [21877, 27482, 0][..]
                      ];

    fixed_restore_signal(3, &residuals[0], &mut outputs[0]);
    fixed_restore_signal(2, &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-729, -722, -667, -583, -486, -359, -225, -91
                             , 59, 209, 354, 497, 630, 740, 812, 845]);
    assert_eq!(&outputs[1], &[21877, 27482, 26574]);
  }

  #[test]
  fn test_lpc_restore_signal() {
    let residuals    = [ &[-2, -23, 14, 6, 3, -4, 12, -2, 10][..]
                       , &[3157][..]
                       ];
    let coefficients = [ &[1042, -399, -75, -269, 121, 166, -75][..]
                       , &[1757, -1199, 879, -836, 555, -255, 119][..]
                       ];
    let mut outputs = [ &mut [-796, -547, -285, -32, 199, 443, 670
                             , 0, 0, 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [-21363, -21951, -22649, -24364, -27297, -26870
                             ,-30017, 0][..]
                      ];

    lpc_restore_signal(9, &coefficients[0], &residuals[0], &mut outputs[0]);
    lpc_restore_signal(10, &coefficients[1], &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-796, -547, -285, -32, 199, 443, 670, 875
                             , 1046, 1208, 1343, 1454, 1541, 1616, 1663
                             , 1701]);
    assert_eq!(&outputs[1], &[-21363, -21951, -22649, -24364, -27297, -26870
                             , -30017, -29718]);
  }

  #[test]
  fn test_decode() {
    let mut output = [0; 16];

    let constant = Subframe {
      data: subframe::Data::Constant(4),
      wasted_bits: 0,
    };

    let verbatim = Subframe {
      data: subframe::Data::Verbatim(vec![16, -3, 55, 49, -32, 6, 40, -90, 1
                                         ,0, 77, -12, 84, 10, -112, 136]),
      wasted_bits: 0,
    };

    let fixed = Subframe {
      data: subframe::Data::Fixed(Fixed {
        entropy_coding_method: EntropyCodingMethod {
          method_type: CodingMethod::PartitionedRice,
          data: PartitionedRice {
            order: 0,
            contents: PartitionedRiceContents {
              parameters: vec![],
              raw_bits: vec![],
            },
          },
        },
        order: 3,
        warmup: [-729, -722, -667, 0],
        residual: vec![-19, -16, 17, -23, -7, 16, -16, -5, 3 , -8, -13, -15
                      ,-1],
      }),
      wasted_bits: 0,
    };

    let lpc = Subframe {
      data: subframe::Data::LPC(LPC {
        entropy_coding_method: EntropyCodingMethod {
          method_type: CodingMethod::PartitionedRice,
          data: PartitionedRice {
            order: 0,
            contents: PartitionedRiceContents {
              parameters: vec![],
              raw_bits: vec![],
            },
          },
        },
        order: 7,
        qlp_coeff_precision: 0,
        quantization_level: 9,
        qlp_coefficients: [1042, -399, -75, -269, 121, 166, -75, 0, 0, 0, 0
                          ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                          ,0, 0, 0, 0],
        warmup: [-796, -547, -285, -32, 199, 443, 670, 0, 0, 0, 0, 0, 0, 0, 0
                ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        residual: vec![-2, -23, 14, 6, 3, -4, 12, -2, 10],
      }),
      wasted_bits: 0,
    };

    decode(&constant, &mut output);
    assert_eq!(&output, &[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]);

    decode(&verbatim, &mut output);
    assert_eq!(&output, &[16, -3, 55, 49, -32, 6, 40 , -90, 1, 0, 77, -12, 84
                         ,10 , -112, 136]);

    decode(&fixed, &mut output);
    assert_eq!(&output, &[-729, -722, -667, -583, -486, -359, -225, -91, 59
                         ,209, 354, 497, 630, 740, 812, 845]);

    decode(&lpc, &mut output);
    assert_eq!(&output, &[-796, -547, -285, -32, 199, 443, 670, 875, 1046
                         ,1208, 1343, 1454, 1541, 1616, 1663, 1701]);
  }

  #[test]
  fn test_wasted_bit_decode() {
    let mut output = [0; 4];

    let constant = Subframe {
      data: subframe::Data::Constant(1),
      wasted_bits: 10,
    };

    decode(&constant, &mut output);
    assert_eq!(&output, &[1024, 1024, 1024, 1024]);
  }
}
<|endoftext|>


<commit_before>use std::io::Write;

use crate::error;
use itertools::Itertools;
use lazy_static::lazy_static;
use liquid_core::error::ResultLiquidReplaceExt;
use liquid_core::parser::TryMatchToken;
use liquid_core::Language;
use liquid_core::TagBlock;
use liquid_core::TagTokenIter;
use liquid_core::ValueView;
use liquid_core::{Renderable, Runtime};
use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, End, Html, Start, Text};

#[cfg(not(feature = "syntax-highlight"))]
use engarde::Raw as Highlight;
#[cfg(feature = "syntax-highlight")]
use engarde::Syntax as Highlight;

lazy_static! {
    static ref HIGHLIGHT: Highlight = Highlight::new();
}

#[cfg(feature = "syntax-highlight")]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    Ok(HIGHLIGHT.has_theme(name))
}

#[cfg(not(feature = "syntax-highlight"))]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    failure::bail!("Themes are unsupported in this build.");
}

pub fn list_syntax_themes() -> Vec<String> {
    HIGHLIGHT.themes().collect()
}

pub fn list_syntaxes() -> Vec<String> {
    HIGHLIGHT.syntaxes().collect()
}

#[derive(Clone, Debug)]
struct CodeBlock {
    lang: Option<liquid::model::KString>,
    code: String,
    theme: liquid::model::KString,
}

impl Renderable for CodeBlock {
    fn render_to(
        &self,
        writer: &mut dyn Write,
        _context: &dyn Runtime,
    ) -> Result<(), liquid_core::Error> {
        write!(
            writer,
            "{}",
            HIGHLIGHT.format(&self.code, self.lang.as_deref(), Some(self.theme.as_str()))
        )
        .replace("Failed to render")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct CodeBlockParser {
    syntax_theme: liquid::model::KString,
}

impl CodeBlockParser {
    pub fn new(theme: Option<liquid::model::KString>) -> error::Result<Self> {
        let theme = if let Some(theme) = theme {
            let result: error::Result<()> = match has_syntax_theme(&theme) {
                Ok(true) => Ok(()),
                Ok(false) => Err(failure::format_err!(
                    "Syntax theme '{}' is unsupported",
                    theme
                )),
                Err(err) => {
                    log::warn!("Syntax theme named '{}' ignored. Reason: {}", theme, err);
                    Ok(())
                }
            };
            result?;
            theme
        } else {
            "".into()
        };

        Ok(Self {
            syntax_theme: theme,
        })
    }
}

impl liquid_core::BlockReflection for CodeBlockParser {
    fn start_tag(&self) -> &'static str {
        "highlight"
    }

    fn end_tag(&self) -> &'static str {
        "endhighlight"
    }

    fn description(&self) -> &'static str {
        "Syntax highlight code using HTML"
    }
}

impl liquid_core::ParseBlock for CodeBlockParser {
    fn reflection(&self) -> &dyn liquid_core::BlockReflection {
        self
    }

    fn parse(
        &self,
        mut arguments: TagTokenIter<'_>,
        mut tokens: TagBlock<'_, '_>,
        _options: &Language,
    ) -> Result<Box<dyn Renderable>, liquid_core::Error> {
        let lang = arguments
            .expect_next("Identifier or literal expected.")
            .ok()
            .map(|lang| {
                // This may accept strange inputs such as `{% include 0 %}` or `{% include filterchain | filter:0 %}`.
                // Those inputs would fail anyway by there being not a path with those langs so they are not a big concern.
                match lang.expect_literal() {
                    // Using `to_str()` on literals ensures `Strings` will have their quotes trimmed.
                    TryMatchToken::Matches(lang) => lang.to_kstr().into_owned(),
                    TryMatchToken::Fails(lang) => liquid::model::KString::from_ref(lang.as_str()),
                }
            });
        // no more arguments should be supplied, trying to supply them is an error
        arguments.expect_nothing()?;

        let mut content = String::new();
        while let Some(element) = tokens.next()? {
            content.push_str(element.as_str());
        }
        tokens.assert_empty();

        Ok(Box::new(CodeBlock {
            code: content,
            lang,
            theme: self.syntax_theme.clone(),
        }))
    }
}

pub struct DecoratedParser<'a> {
    parser: cmark::Parser<'a, 'a>,
    theme: Option<&'a str>,
    lang: Option<String>,
    code: Option<Vec<pulldown_cmark::CowStr<'a>>>,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a, 'a>, theme: Option<&'a str>) -> Self {
        DecoratedParser {
            parser,
            theme,
            lang: None,
            code: None,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(Text(text)) => {
                if let Some(ref mut code) = self.code {
                    code.push(text);
                    Some(Text(pulldown_cmark::CowStr::Borrowed("")))
                } else {
                    Some(Text(text))
                }
            }
            Some(Start(cmark::Tag::CodeBlock(info))) => {
                let tag = match info {
                    pulldown_cmark::CodeBlockKind::Indented => "",
                    pulldown_cmark::CodeBlockKind::Fenced(ref tag) => tag.as_ref(),
                };
                self.lang = tag.split(' ').map(|s| s.to_owned()).next();
                self.code = Some(vec![]);
                Some(Text(pulldown_cmark::CowStr::Borrowed("")))
            }
            Some(End(cmark::Tag::CodeBlock(_))) => {
                let html = if let Some(code) = self.code.as_deref() {
                    let code = code.iter().join("\n");
                    HIGHLIGHT.format(&code, self.lang.as_deref(), self.theme)
                } else {
                    HIGHLIGHT.format("", self.lang.as_deref(), self.theme)
                };
                // reset highlighter
                self.lang = None;
                self.code = None;
                // close the code block
                Some(Html(pulldown_cmark::CowStr::Boxed(html.into_boxed_str())))
            }
            item => item,
        }
    }
}

pub fn decorate_markdown<'a>(
    parser: cmark::Parser<'a, 'a>,
    theme_name: Option<&'a str>,
) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, theme_name)
}

#[cfg(test)]
#[cfg(feature = "syntax-highlight")]
mod test_syntsx {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new(Some("base16-ocean.dark".into())).unwrap());
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        snapbox::assert_eq(CODEBLOCK_RENDERED, &output.unwrap());
    }

    const MARKDOWN_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\
             \n\

\n";

    #[test]
    fn markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        snapbox::assert_eq(MARKDOWN_RENDERED, &buf);
    }
}

#[cfg(test)]
#[cfg(not(feature = "syntax-highlight"))]
mod test_raw {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new("base16-ocean.dark".into()));
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        assert_eq!(output.unwrap(), CODEBLOCK_RENDERED.to_string());
    }

    const MARKDOWN_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<commit_msg>fix: Make liquid/md code formatting consistent<commit_after>use std::io::Write;

use crate::error;
use itertools::Itertools;
use lazy_static::lazy_static;
use liquid_core::error::ResultLiquidReplaceExt;
use liquid_core::parser::TryMatchToken;
use liquid_core::Language;
use liquid_core::TagBlock;
use liquid_core::TagTokenIter;
use liquid_core::ValueView;
use liquid_core::{Renderable, Runtime};
use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, End, Html, Start, Text};

#[cfg(not(feature = "syntax-highlight"))]
use engarde::Raw as Highlight;
#[cfg(feature = "syntax-highlight")]
use engarde::Syntax as Highlight;

lazy_static! {
    static ref HIGHLIGHT: Highlight = Highlight::new();
}

#[cfg(feature = "syntax-highlight")]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    Ok(HIGHLIGHT.has_theme(name))
}

#[cfg(not(feature = "syntax-highlight"))]
pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    failure::bail!("Themes are unsupported in this build.");
}

pub fn list_syntax_themes() -> Vec<String> {
    HIGHLIGHT.themes().collect()
}

pub fn list_syntaxes() -> Vec<String> {
    HIGHLIGHT.syntaxes().collect()
}

#[derive(Clone, Debug)]
struct CodeBlock {
    lang: Option<liquid::model::KString>,
    code: String,
    theme: Option<liquid::model::KString>,
}

impl Renderable for CodeBlock {
    fn render_to(
        &self,
        writer: &mut dyn Write,
        _context: &dyn Runtime,
    ) -> Result<(), liquid_core::Error> {
        write!(
            writer,
            "{}",
            HIGHLIGHT.format(&self.code, self.lang.as_deref(), self.theme.as_deref())
        )
        .replace("Failed to render")?;

        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct CodeBlockParser {
    syntax_theme: Option<liquid::model::KString>,
}

impl CodeBlockParser {
    pub fn new(theme: Option<liquid::model::KString>) -> error::Result<Self> {
        if let Some(theme) = &theme {
            match has_syntax_theme(theme) {
                Ok(true) => {}
                Ok(false) => failure::bail!("Syntax theme '{}' is unsupported", theme),
                Err(err) => {
                    log::warn!("Syntax theme named '{}' ignored. Reason: {}", theme, err);
                }
            };
        }

        Ok(Self {
            syntax_theme: theme,
        })
    }
}

impl liquid_core::BlockReflection for CodeBlockParser {
    fn start_tag(&self) -> &'static str {
        "highlight"
    }

    fn end_tag(&self) -> &'static str {
        "endhighlight"
    }

    fn description(&self) -> &'static str {
        "Syntax highlight code using HTML"
    }
}

impl liquid_core::ParseBlock for CodeBlockParser {
    fn reflection(&self) -> &dyn liquid_core::BlockReflection {
        self
    }

    fn parse(
        &self,
        mut arguments: TagTokenIter<'_>,
        mut tokens: TagBlock<'_, '_>,
        _options: &Language,
    ) -> Result<Box<dyn Renderable>, liquid_core::Error> {
        let lang = arguments
            .expect_next("Identifier or literal expected.")
            .ok()
            .map(|lang| {
                // This may accept strange inputs such as `{% include 0 %}` or `{% include filterchain | filter:0 %}`.
                // Those inputs would fail anyway by there being not a path with those langs so they are not a big concern.
                match lang.expect_literal() {
                    // Using `to_str()` on literals ensures `Strings` will have their quotes trimmed.
                    TryMatchToken::Matches(lang) => lang.to_kstr().into_owned(),
                    TryMatchToken::Fails(lang) => liquid::model::KString::from_ref(lang.as_str()),
                }
            });
        // no more arguments should be supplied, trying to supply them is an error
        arguments.expect_nothing()?;

        let mut content = String::new();
        while let Some(element) = tokens.next()? {
            content.push_str(element.as_str());
        }
        tokens.assert_empty();

        Ok(Box::new(CodeBlock {
            code: content,
            lang,
            theme: self.syntax_theme.clone(),
        }))
    }
}

pub struct DecoratedParser<'a> {
    parser: cmark::Parser<'a, 'a>,
    theme: Option<&'a str>,
    lang: Option<String>,
    code: Option<Vec<pulldown_cmark::CowStr<'a>>>,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a, 'a>, theme: Option<&'a str>) -> Self {
        DecoratedParser {
            parser,
            theme,
            lang: None,
            code: None,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(Text(text)) => {
                if let Some(ref mut code) = self.code {
                    code.push(text);
                    Some(Text(pulldown_cmark::CowStr::Borrowed("")))
                } else {
                    Some(Text(text))
                }
            }
            Some(Start(cmark::Tag::CodeBlock(info))) => {
                let tag = match info {
                    pulldown_cmark::CodeBlockKind::Indented => "",
                    pulldown_cmark::CodeBlockKind::Fenced(ref tag) => tag.as_ref(),
                };
                self.lang = tag.split(' ').map(|s| s.to_owned()).next();
                self.code = Some(vec![]);
                Some(Text(pulldown_cmark::CowStr::Borrowed("")))
            }
            Some(End(cmark::Tag::CodeBlock(_))) => {
                let html = if let Some(code) = self.code.as_deref() {
                    let code = code.iter().join("\n");
                    HIGHLIGHT.format(&code, self.lang.as_deref(), self.theme)
                } else {
                    HIGHLIGHT.format("", self.lang.as_deref(), self.theme)
                };
                // reset highlighter
                self.lang = None;
                self.code = None;
                // close the code block
                Some(Html(pulldown_cmark::CowStr::Boxed(html.into_boxed_str())))
            }
            item => item,
        }
    }
}

pub fn decorate_markdown<'a>(
    parser: cmark::Parser<'a, 'a>,
    theme_name: Option<&'a str>,
) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, theme_name)
}

#[cfg(test)]
#[cfg(feature = "syntax-highlight")]
mod test_syntsx {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const CODEBLOCK_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\

\n";

    #[test]
    fn highlight_block_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new(Some("base16-ocean.dark".into())).unwrap());
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        snapbox::assert_eq(CODEBLOCK_RENDERED, &output.unwrap());
    }

    const MARKDOWN_RENDERED: &str =
        "
\n\
         mod \
         test {\n\
                 \
         fn \
         hello(\
         arg: int) -> \
         bool {\n\
                     \
         true\n\
                 }\n\
             }\n\
             \n\

\n";

    #[test]
    fn markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        snapbox::assert_eq(MARKDOWN_RENDERED, &buf);
    }
}

#[cfg(test)]
#[cfg(not(feature = "syntax-highlight"))]
mod test_raw {
    use super::*;

    const CODE_BLOCK: &str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
";

    const CODEBLOCK_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn codeblock_renders_rust() {
        let highlight: Box<dyn liquid_core::ParseBlock> =
            Box::new(CodeBlockParser::new("base16-ocean.dark".into()));
        let parser = liquid::ParserBuilder::new()
            .block(highlight)
            .build()
            .unwrap();
        let template = parser
            .parse(&format!(
                "{{% highlight rust %}}{}{{% endhighlight %}}",
                CODE_BLOCK
            ))
            .unwrap();
        let output = template.render(&liquid::Object::new());
        assert_eq!(output.unwrap(), CODEBLOCK_RENDERED.to_string());
    }

    const MARKDOWN_RENDERED: &str = r#"
mod test {
        fn hello(arg: int) -> bool {
            true
        }
    }

"#;

    #[test]
    fn decorate_markdown_renders_rust() {
        let html = format!(
            "```rust
{}
```",
            CODE_BLOCK
        );

        let mut buf = String::new();
        let parser = cmark::Parser::new(&html);
        cmark::html::push_html(
            &mut buf,
            decorate_markdown(parser, Some("base16-ocean.dark")),
        );
        assert_eq!(buf, MARKDOWN_RENDERED);
    }
}
<|endoftext|>


<commit_before>use serde::{Deserialize, Deserializer};
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::marker::PhantomData;
use std::str::FromStr;

pub struct NumberVisitor<T> {
    marker: PhantomData<T>,
}

impl<'de, T> serde::de::Visitor<'de> for NumberVisitor<T>
where
    T: TryFrom<u64> + TryFrom<i64> + FromStr,
    <T as TryFrom<u64>>::Error: Display,
    <T as TryFrom<i64>>::Error: Display,
    <T as FromStr>::Err: Display,
{
    type Value = T;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("an integer or string")
    }

    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        T::try_from(v).map_err(serde::de::Error::custom)
    }

    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        T::try_from(v).map_err(serde::de::Error::custom)
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        v.parse().map_err(serde::de::Error::custom)
    }
}

fn deserialize_integer_or_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: TryFrom<u64> + TryFrom<i64> + FromStr,
    <T as TryFrom<u64>>::Error: Display,
    <T as TryFrom<i64>>::Error: Display,
    <T as FromStr>::Err: Display,
{
    deserializer.deserialize_any(NumberVisitor {
        marker: PhantomData,
    })
}

#[derive(Deserialize, Debug)]
pub struct Struct {
    #[serde(deserialize_with = "deserialize_integer_or_string")]
    pub i: i64,
}

#[test]
fn test() {
    let j = r#" {"i":100} "#;
    println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());

    let j = r#" {"i":"100"} "#;
    println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());
}
<commit_msg>Ignore trait_duplication_in_bounds clippy false positives<commit_after>#![allow(clippy::trait_duplication_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/8757

use serde::{Deserialize, Deserializer};
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::marker::PhantomData;
use std::str::FromStr;

pub struct NumberVisitor<T> {
    marker: PhantomData<T>,
}

impl<'de, T> serde::de::Visitor<'de> for NumberVisitor<T>
where
    T: TryFrom<u64> + TryFrom<i64> + FromStr,
    <T as TryFrom<u64>>::Error: Display,
    <T as TryFrom<i64>>::Error: Display,
    <T as FromStr>::Err: Display,
{
    type Value = T;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("an integer or string")
    }

    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        T::try_from(v).map_err(serde::de::Error::custom)
    }

    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        T::try_from(v).map_err(serde::de::Error::custom)
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        v.parse().map_err(serde::de::Error::custom)
    }
}

fn deserialize_integer_or_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: TryFrom<u64> + TryFrom<i64> + FromStr,
    <T as TryFrom<u64>>::Error: Display,
    <T as TryFrom<i64>>::Error: Display,
    <T as FromStr>::Err: Display,
{
    deserializer.deserialize_any(NumberVisitor {
        marker: PhantomData,
    })
}

#[derive(Deserialize, Debug)]
pub struct Struct {
    #[serde(deserialize_with = "deserialize_integer_or_string")]
    pub i: i64,
}

#[test]
fn test() {
    let j = r#" {"i":100} "#;
    println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());

    let j = r#" {"i":"100"} "#;
    println!("{:?}", serde_json::from_str::<Struct>(j).unwrap());
}
<|endoftext|>


<commit_before>//! Unix-specific extensions to general I/O primitives.
//!
//! Just like raw pointers, raw file descriptors point to resources with
//! dynamic lifetimes, and they can dangle if they outlive their resources
//! or be forged if they're created from invalid values.
//!
//! This module provides three types for representing file descriptors,
//! with different ownership properties: raw, borrowed, and owned, which are
//! analogous to types used for representing pointers:
//!
//! | Type               | Analogous to |
//! | ------------------ | ------------ |
//! | [`RawFd`]          | `*const _`   |
//! | [`BorrowedFd<'a>`] | `&'a _`      |
//! | [`OwnedFd`]        | `Box<_>`     |
//!
//! Like raw pointers, `RawFd` values are primitive values. And in new code,
//! they should be considered unsafe to do I/O on (analogous to dereferencing
//! them). Rust did not always provide this guidance, so existing code in the
//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Libraries are
//! encouraged to migrate, either by adding `unsafe` to APIs that dereference
//! `RawFd` values, or by using to `BorrowedFd` or `OwnedFd` instead.
//!
//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
//! that they don't outlive the resource they point to. These are safe to
//! use. `BorrowedFd` values may be used in APIs which provide safe access to
//! any system call except for:
//!  - `close`, because that would end the dynamic lifetime of the resource
//!    without ending the lifetime of the file descriptor.
//!  - `dup2`/`dup3`, in the second argument, because this argument is
//!    closed and replaced with a new resource, which may break the assumptions
//!    other code using that file descriptor.
//! This list doesn't include `mmap`, since `mmap` does do a proper borrow of
//! its file descriptor argument. That said, `mmap` is unsafe for other
//! reasons: it operates on raw pointers, and it has undefined behavior if the
//! underlying storage is mutated. Mutations may come from other processes, or
//! from the same process if the API provides `BorrowedFd` access, since as
//! mentioned earlier, `BorrowedFd` values may be used in APIs which provide
//! safe access to any system call. Consequently, code using `mmap` and
//! presenting a safe API must take full responsibility for ensuring that safe
//! Rust code cannot evoke undefined behavior through it.
//!
//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
//! and free (close) it when they are dropped.
//!
//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd

#![stable(feature = "rust1", since = "1.0.0")]

mod fd;
mod raw;

#[unstable(feature = "io_safety", issue = "87074")]
pub use fd::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;
<commit_msg>Be more precise about `mmap` and undefined behavior.<commit_after>//! Unix-specific extensions to general I/O primitives.
//!
//! Just like raw pointers, raw file descriptors point to resources with
//! dynamic lifetimes, and they can dangle if they outlive their resources
//! or be forged if they're created from invalid values.
//!
//! This module provides three types for representing file descriptors,
//! with different ownership properties: raw, borrowed, and owned, which are
//! analogous to types used for representing pointers:
//!
//! | Type               | Analogous to |
//! | ------------------ | ------------ |
//! | [`RawFd`]          | `*const _`   |
//! | [`BorrowedFd<'a>`] | `&'a _`      |
//! | [`OwnedFd`]        | `Box<_>`     |
//!
//! Like raw pointers, `RawFd` values are primitive values. And in new code,
//! they should be considered unsafe to do I/O on (analogous to dereferencing
//! them). Rust did not always provide this guidance, so existing code in the
//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Libraries are
//! encouraged to migrate, either by adding `unsafe` to APIs that dereference
//! `RawFd` values, or by using to `BorrowedFd` or `OwnedFd` instead.
//!
//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
//! that they don't outlive the resource they point to. These are safe to
//! use. `BorrowedFd` values may be used in APIs which provide safe access to
//! any system call except for:
//!  - `close`, because that would end the dynamic lifetime of the resource
//!    without ending the lifetime of the file descriptor.
//!  - `dup2`/`dup3`, in the second argument, because this argument is
//!    closed and replaced with a new resource, which may break the assumptions
//!    other code using that file descriptor.
//! This list doesn't include `mmap`, since `mmap` does do a proper borrow of
//! its file descriptor argument. That said, `mmap` is unsafe for other
//! reasons: it operates on raw pointers, and it can have undefined behavior if
//! the underlying storage is mutated. Mutations may come from other processes,
//! or from the same process if the API provides `BorrowedFd` access, since as
//! mentioned earlier, `BorrowedFd` values may be used in APIs which provide
//! safe access to any system call. Consequently, code using `mmap` and
//! presenting a safe API must take full responsibility for ensuring that safe
//! Rust code cannot evoke undefined behavior through it.
//!
//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
//! and free (close) it when they are dropped.
//!
//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd

#![stable(feature = "rust1", since = "1.0.0")]

mod fd;
mod raw;

#[unstable(feature = "io_safety", issue = "87074")]
pub use fd::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;
<|endoftext|>


<commit_before>import std::time;

enum IP {
    IPv4(u8,u8,u8,u8),
    IPv6(u16,u16,u16,u16,u16,u16,u16),
}

enum PgData {
    // +------------------------------------------------------------------------+
    // |          Name          |     Aliases      |        Description         |
    // |------------------------+------------------+----------------------------|
    // | bigint                 | int8             | signed eight-byte integer  |
    BigInt(i8),

    // |------------------------+------------------+----------------------------|
    // | bigserial              | serial8          | autoincrementing           |
    // |                        |                  | eight-byte integer         |
    BigSerial(i8),

    // |------------------------+------------------+----------------------------|
    // | bit [ (n) ]            |                  | fixed-length bit string    |
    Bit([bool]),

    // |------------------------+------------------+----------------------------|
    // | bit varying [ (n) ]    | varbit           | variable-length bit string |
    VarBit([bool]),

    // |------------------------+------------------+----------------------------|
    // | boolean                | bool             | logical Boolean            |
    // |                        |                  | (true/false)               |
    Bool(bool),

    // |------------------------+------------------+----------------------------|
    // | box                    |                  | rectangular box on a plane |
    //Box(f64, f64),

    // |------------------------+------------------+----------------------------|
    // | bytea                  |                  | binary data ("byte array") |
    ByteA([u8]),

    // |------------------------+------------------+----------------------------|
    // | character varying [    | varchar [ (n) ]  | variable-length character  |
    // | (n) ]                  |                  | string                     |
    VarChar(int, str),

    // |------------------------+------------------+----------------------------|
    // | character [ (n) ]      | char [ (n) ]     | fixed-length character     |
    // |                        |                  | string                     |
    Char(str),

    // |------------------------+------------------+----------------------------|
    // | cidr                   |                  | IPv4 or IPv6 network       |
    // |                        |                  | address                    |
    Cidr(IP),

    // |------------------------+------------------+----------------------------|
    // | circle                 |                  | circle on a plane          |
    // |------------------------+------------------+----------------------------|
    // | date                   |                  | calendar date (year,       |
    // |                        |                  | month, day)                |
    Date(u8,u8,u8),

    // |------------------------+------------------+----------------------------|
    // |                        |                  | double precision           |
    // | double precision       | float8           | floating-point number (8   |
    // |                        |                  | bytes)                     |
    Double(f64),

    // |------------------------+------------------+----------------------------|
    // | inet                   |                  | IPv4 or IPv6 host address  |
    Inet(IP),

    // |------------------------+------------------+----------------------------|
    // | integer                | int, int4        | signed four-byte integer   |
    Int4(i32),

    // |------------------------+------------------+----------------------------|
    // | interval [ fields ] [  |                  | time span                  |
    // | (p) ]                  |                  |                            |

    // |------------------------+------------------+----------------------------|
    // | line                   |                  | infinite line on a plane   |
    // |------------------------+------------------+----------------------------|
    // | lseg                   |                  | line segment on a plane    |
    // |------------------------+------------------+----------------------------|
    // | macaddr                |                  | MAC (Media Access Control) |
    // |                        |                  | address                    |
    MacAddr(u8,u8,u8,u8,u8,u8),

    // |------------------------+------------------+----------------------------|
    // | money                  |                  | currency amount            |
    // |------------------------+------------------+----------------------------|
    // | numeric [ (p, s) ]     | decimal [ (p, s) | exact numeric of           |
    // |                        | ]                | selectable precision       |
    // |------------------------+------------------+----------------------------|
    // | path                   |                  | geometric path on a plane  |
    // |------------------------+------------------+----------------------------|
    // | point                  |                  | geometric point on a plane |
    // |------------------------+------------------+----------------------------|
    // | polygon                |                  | closed geometric path on a |
    // |                        |                  | plane                      |
    // |------------------------+------------------+----------------------------|
    // |                        |                  | single precision           |
    // | real                   | float4           | floating-point number (4   |
    // |                        |                  | bytes)                     |
    Real(f32),

    // |------------------------+------------------+----------------------------|
    // | smallint               | int2             | signed two-byte integer    |
    SmallInt(i16),

    // |------------------------+------------------+----------------------------|
    // | serial                 | serial4          | autoincrementing four-byte |
    // |                        |                  | integer                    |
    Serial(i32),

    // |------------------------+------------------+----------------------------|
    // | text                   |                  | variable-length character  |
    // |                        |                  | string                     |
    Text(str),

    // |------------------------+------------------+----------------------------|
    // | time [ (p) ] [ without |                  | time of day (no time zone) |
    // | time zone ]            |                  |                            |
    Time(time::tm),

    // |------------------------+------------------+----------------------------|
    // | time [ (p) ] with time | timetz           | time of day, including     |
    // | zone                   |                  | time zone                  |
    TimeTz(time::tm),

    // |------------------------+------------------+----------------------------|
    // | timestamp [ (p) ] [    |                  | date and time (no time     |
    // | without time zone ]    |                  | zone)                      |
    // |------------------------+------------------+----------------------------|
    // | timestamp [ (p) ] with | timestamptz      | date and time, including   |
    // | time zone              |                  | time zone                  |
    // |------------------------+------------------+----------------------------|
    // | tsquery                |                  | text search query          |
    // |------------------------+------------------+----------------------------|
    // | tsvector               |                  | text search document       |
    // |------------------------+------------------+----------------------------|
    // | txid_snapshot          |                  | user-level transaction ID  |
    // |                        |                  | snapshot                   |
    // |------------------------+------------------+----------------------------|
    // | uuid                   |                  | universally unique         |
    // |                        |                  | identifier                 |
    Uuid([u8]),
    // |------------------------+------------------+----------------------------|
    // | xml                    |                  | XML data                   |

    Xml([u8]),
    // +------------------------------------------------------------------------+
}

iface Show {
    fn show() -> str;
}

impl of Show for PgData {
    fn show() -> str {
        alt self {
          BigInt(n) {"Asdf"}
          VarChar(n, s) {#fmt("'%s'", s)}
          Int4(n) {#fmt("%d", n as int)}
          _ { "asdf"}
        }
    }
}

          // BigSerial(n),
          // Bit(bs),
          // VarBit(bs),
          // Bool(b),
          // ByteA([u8]),
          // VarChar(int, str),
          // Char(str),
          // Cidr(IP),
          // Date(u8,u8,u8),
          // Double(f64),
          // Inet(IP),
          // Int4(i32),
          // MacAddr(u8,u8,u8,u8,u8,u8),
          // Real(f32),
          // SmallInt(i16),
          // Serial(i32),
          // Text(str),
          // Uuid(str),
          // Xml([u8]),
<commit_msg>fixed some naming confusion in glue<commit_after>import std::time;

enum IP {
    IPv4(u8,u8,u8,u8),
    IPv6(u16,u16,u16,u16,u16,u16,u16),
}

enum PgData {
    // +------------------------------------------------------------------------+
    // |          Name          |     Aliases      |        Description         |
    // |------------------------+------------------+----------------------------|
    // | bigint                 | int8             | signed eight-byte integer  |
    BigInt(i64),

    // |------------------------+------------------+----------------------------|
    // | bigserial              | serial8          | autoincrementing           |
    // |                        |                  | eight-byte integer         |
    BigSerial(i64),

    // |------------------------+------------------+----------------------------|
    // | bit [ (n) ]            |                  | fixed-length bit string    |
    Bit([bool]),

    // |------------------------+------------------+----------------------------|
    // | bit varying [ (n) ]    | varbit           | variable-length bit string |
    VarBit([bool]),

    // |------------------------+------------------+----------------------------|
    // | boolean                | bool             | logical Boolean            |
    // |                        |                  | (true/false)               |
    Bool(bool),

    // |------------------------+------------------+----------------------------|
    // | box                    |                  | rectangular box on a plane |
    //Box(f64, f64),

    // |------------------------+------------------+----------------------------|
    // | bytea                  |                  | binary data ("byte array") |
    ByteA([u8]),

    // |------------------------+------------------+----------------------------|
    // | character varying [    | varchar [ (n) ]  | variable-length character  |
    // | (n) ]                  |                  | string                     |
    VarChar(int, str),

    // |------------------------+------------------+----------------------------|
    // | character [ (n) ]      | char [ (n) ]     | fixed-length character     |
    // |                        |                  | string                     |
    Char(str),

    // |------------------------+------------------+----------------------------|
    // | cidr                   |                  | IPv4 or IPv6 network       |
    // |                        |                  | address                    |
    Cidr(IP),

    // |------------------------+------------------+----------------------------|
    // | circle                 |                  | circle on a plane          |
    // |------------------------+------------------+----------------------------|
    // | date                   |                  | calendar date (year,       |
    // |                        |                  | month, day)                |
    Date(u8,u8,u8),

    // |------------------------+------------------+----------------------------|
    // |                        |                  | double precision           |
    // | double precision       | float8           | floating-point number (8   |
    // |                        |                  | bytes)                     |
    Float64(f64),

    // |------------------------+------------------+----------------------------|
    // | inet                   |                  | IPv4 or IPv6 host address  |
    Inet(IP),

    // |------------------------+------------------+----------------------------|
    // | integer                | int, int4        | signed four-byte integer   |
    Int32(i32), // change from int4 to int32 because of brain violence.

    // |------------------------+------------------+----------------------------|
    // | interval [ fields ] [  |                  | time span                  |
    // | (p) ]                  |                  |                            |

    // |------------------------+------------------+----------------------------|
    // | line                   |                  | infinite line on a plane   |
    // |------------------------+------------------+----------------------------|
    // | lseg                   |                  | line segment on a plane    |
    // |------------------------+------------------+----------------------------|
    // | macaddr                |                  | MAC (Media Access Control) |
    // |                        |                  | address                    |
    MacAddr(u8,u8,u8,u8,u8,u8),

    // |------------------------+------------------+----------------------------|
    // | money                  |                  | currency amount            |
    // |------------------------+------------------+----------------------------|
    // | numeric [ (p, s) ]     | decimal [ (p, s) | exact numeric of           |
    // |                        | ]                | selectable precision       |
    // |------------------------+------------------+----------------------------|
    // | path                   |                  | geometric path on a plane  |
    // |------------------------+------------------+----------------------------|
    // | point                  |                  | geometric point on a plane |
    // |------------------------+------------------+----------------------------|
    // | polygon                |                  | closed geometric path on a |
    // |                        |                  | plane                      |
    // |------------------------+------------------+----------------------------|
    // |                        |                  | single precision           |
    // | real                   | float4           | floating-point number (4   |
    // |                        |                  | bytes)                     |
    Float32(f32),

    // |------------------------+------------------+----------------------------|
    // | smallint               | int2             | signed two-byte integer    |
    Int16(i16),

    // |------------------------+------------------+----------------------------|
    // | serial                 | serial4          | autoincrementing four-byte |
    // |                        |                  | integer                    |
    Serial(i32),

    // |------------------------+------------------+----------------------------|
    // | text                   |                  | variable-length character  |
    // |                        |                  | string                     |
    Text(str),

    // |------------------------+------------------+----------------------------|
    // | time [ (p) ] [ without |                  | time of day (no time zone) |
    // | time zone ]            |                  |                            |
    Time(time::tm),

    // |------------------------+------------------+----------------------------|
    // | time [ (p) ] with time | timetz           | time of day, including     |
    // | zone                   |                  | time zone                  |
    TimeTz(time::tm),

    // |------------------------+------------------+----------------------------|
    // | timestamp [ (p) ] [    |                  | date and time (no time     |
    // | without time zone ]    |                  | zone)                      |
    // |------------------------+------------------+----------------------------|
    // | timestamp [ (p) ] with | timestamptz      | date and time, including   |
    // | time zone              |                  | time zone                  |
    // |------------------------+------------------+----------------------------|
    // | tsquery                |                  | text search query          |
    // |------------------------+------------------+----------------------------|
    // | tsvector               |                  | text search document       |
    // |------------------------+------------------+----------------------------|
    // | txid_snapshot          |                  | user-level transaction ID  |
    // |                        |                  | snapshot                   |
    // |------------------------+------------------+----------------------------|
    // | uuid                   |                  | universally unique         |
    // |                        |                  | identifier                 |
    Uuid([u8]),
    // |------------------------+------------------+----------------------------|
    // | xml                    |                  | XML data                   |

    Xml([u8]),
    // +------------------------------------------------------------------------+
}

iface Show {
    fn show() -> str;
}

impl of Show for PgData {
    fn show() -> str {
        alt self {
          BigInt(n) {"Asdf"}
          VarChar(n, s) {#fmt("'%s'", s)}
          Int4(n) {#fmt("%d", n as int)}
          _ { "asdf"}
        }
    }
}

          // BigSerial(n),
          // Bit(bs),
          // VarBit(bs),
          // Bool(b),
          // ByteA([u8]),
          // VarChar(int, str),
          // Char(str),
          // Cidr(IP),
          // Date(u8,u8,u8),
          // Double(f64),
          // Inet(IP),
          // Int4(i32),
          // MacAddr(u8,u8,u8,u8,u8,u8),
          // Real(f32),
          // SmallInt(i16),
          // Serial(i32),
          // Text(str),
          // Uuid(str),
          // Xml([u8]),
<|endoftext|>