<commit_before>#[cfg(any(target_os = "linux", target_os = "android"))]
mod eventfd {
    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::mem;
    use std::os::unix::io::FromRawFd;

    use crate::sys::Selector;
    use crate::{Interests, Token};

    /// Waker backed by `eventfd`.
    ///
    /// `eventfd` is effectively an 64 bit counter. All writes must be of 8
    /// bytes (64 bits) and are converted (native endian) into an 64 bit
    /// unsigned integer and added to the count. Reads must also be 8 bytes and
    /// reset the count to 0, returning the count.
    #[derive(Debug)]
    pub struct Waker {
        fd: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let fd = syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK))?;

            selector.register(fd, token, Interests::READABLE)?;
            Ok(Waker {
                fd: unsafe { File::from_raw_fd(fd) },
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            let buf: [u8; 8] = unsafe { mem::transmute(1u64) };
            match (&self.fd).write(&buf) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // Writing only blocks if the counter is going to overflow.
                    // So we'll reset the counter to 0 and wake it again.
                    self.reset()?;
                    self.wake()
                }
                Err(err) => Err(err),
            }
        }

        /// Reset the eventfd object, only need to call this if `wake` fails.
        fn reset(&self) -> io::Result<()> {
            let mut buf: [u8; 8] = [0; 8];
            match (&self.fd).read(&mut buf) {
                Ok(_) => Ok(()),
                // If the `Waker` hasn't been awoken yet this will return a
                // `WouldBlock` error which we can safely ignore.
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
                Err(err) => Err(err),
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::eventfd::Waker;

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
mod kqueue {
    use std::io;

    use crate::sys::Selector;
    use crate::Token;

    /// Waker backed by kqueue user space notifications (`EVFILT_USER`).
    ///
    /// The implementation is fairly simple, first the kqueue must be setup to
    /// receive waker events this done by calling `Selector.setup_waker`. Next
    /// we need access to kqueue, thus we need to duplicate the file descriptor.
    /// Now waking is as simple as adding an event to the kqueue.
    #[derive(Debug)]
    pub struct Waker {
        selector: Selector,
        token: Token,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            selector.try_clone_waker().and_then(|selector| {
                selector
                    .setup_waker(token)
                    .map(|()| Waker { selector, token })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            self.selector.wake(self.token)
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
pub use self::kqueue::Waker;

#[cfg(any(
    target_os = "bitrig",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod pipe {
    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    use crate::sys::unix::Selector;
    use crate::{Interests, Token};

    /// Waker backed by a unix pipe.
    ///
    /// Waker controls both the sending and receiving ends and empties the pipe
    /// if writing to it (waking) fails.
    #[derive(Debug)]
    pub struct Waker {
        sender: File,
        receiver: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let mut fds = [-1; 2];
            syscall!(pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC))?;
            selector.register(fds[0], token, Interests::READABLE)?;

            Ok(Waker {
                sender: unsafe { File::from_raw_fd(fds[1]) },
                receiver: unsafe { File::from_raw_fd(fds[0]) },
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            match (&self.sender).write(&[1]) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // The reading end is full so we'll empty the buffer and try
                    // again.
                    self.empty();
                    self.wake()
                }
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(),
                Err(err) => Err(err),
            }
        }

        /// Empty the pipe's buffer, only need to call this if `wake` fails.
        /// This ignores any errors.
        fn empty(&self) {
            let mut buf = [0; 4096];
            loop {
                match (&self.receiver).read(&mut buf) {
                    Ok(n) if n > 0 => continue,
                    _ => return,
                }
            }
        }
    }
}

#[cfg(any(
    target_os = "bitrig",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use self::pipe::Waker;
<commit_msg>Replace unsafe transmute with to_ne_bytes in Waker<commit_after>#[cfg(any(target_os = "linux", target_os = "android"))]
mod eventfd {
    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::mem;
    use std::os::unix::io::FromRawFd;

    use crate::sys::Selector;
    use crate::{Interests, Token};

    /// Waker backed by `eventfd`.
    ///
    /// `eventfd` is effectively an 64 bit counter. All writes must be of 8
    /// bytes (64 bits) and are converted (native endian) into an 64 bit
    /// unsigned integer and added to the count. Reads must also be 8 bytes and
    /// reset the count to 0, returning the count.
    #[derive(Debug)]
    pub struct Waker {
        fd: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let fd = syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK))?;

            selector.register(fd, token, Interests::READABLE)?;
            Ok(Waker {
                fd: unsafe { File::from_raw_fd(fd) },
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            let buf: [u8; 8] = 1u64.to_ne_bytes();
            match (&self.fd).write(&buf) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // Writing only blocks if the counter is going to overflow.
                    // So we'll reset the counter to 0 and wake it again.
                    self.reset()?;
                    self.wake()
                }
                Err(err) => Err(err),
            }
        }

        /// Reset the eventfd object, only need to call this if `wake` fails.
        fn reset(&self) -> io::Result<()> {
            let mut buf: [u8; 8] = 0u64.to_ne_bytes();
            match (&self.fd).read(&mut buf) {
                Ok(_) => Ok(()),
                // If the `Waker` hasn't been awoken yet this will return a
                // `WouldBlock` error which we can safely ignore.
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
                Err(err) => Err(err),
            }
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::eventfd::Waker;

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
mod kqueue {
    use std::io;

    use crate::sys::Selector;
    use crate::Token;

    /// Waker backed by kqueue user space notifications (`EVFILT_USER`).
    ///
    /// The implementation is fairly simple, first the kqueue must be setup to
    /// receive waker events this done by calling `Selector.setup_waker`. Next
    /// we need access to kqueue, thus we need to duplicate the file descriptor.
    /// Now waking is as simple as adding an event to the kqueue.
    #[derive(Debug)]
    pub struct Waker {
        selector: Selector,
        token: Token,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            selector.try_clone_waker().and_then(|selector| {
                selector
                    .setup_waker(token)
                    .map(|()| Waker { selector, token })
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            self.selector.wake(self.token)
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))]
pub use self::kqueue::Waker;

#[cfg(any(
    target_os = "bitrig",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod pipe {
    use std::fs::File;
    use std::io::{self, Read, Write};
    use std::os::unix::io::FromRawFd;

    use crate::sys::unix::Selector;
    use crate::{Interests, Token};

    /// Waker backed by a unix pipe.
    ///
    /// Waker controls both the sending and receiving ends and empties the pipe
    /// if writing to it (waking) fails.
    #[derive(Debug)]
    pub struct Waker {
        sender: File,
        receiver: File,
    }

    impl Waker {
        pub fn new(selector: &Selector, token: Token) -> io::Result<Waker> {
            let mut fds = [-1; 2];
            syscall!(pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC))?;
            selector.register(fds[0], token, Interests::READABLE)?;

            Ok(Waker {
                sender: unsafe { File::from_raw_fd(fds[1]) },
                receiver: unsafe { File::from_raw_fd(fds[0]) },
            })
        }

        pub fn wake(&self) -> io::Result<()> {
            match (&self.sender).write(&[1]) {
                Ok(_) => Ok(()),
                Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                    // The reading end is full so we'll empty the buffer and try
                    // again.
                    self.empty();
                    self.wake()
                }
                Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(),
                Err(err) => Err(err),
            }
        }

        /// Empty the pipe's buffer, only need to call this if `wake` fails.
        /// This ignores any errors.
        fn empty(&self) {
            let mut buf = [0; 4096];
            loop {
                match (&self.receiver).read(&mut buf) {
                    Ok(n) if n > 0 => continue,
                    _ => return,
                }
            }
        }
    }
}

#[cfg(any(
    target_os = "bitrig",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use self::pipe::Waker;
<|endoftext|>


<commit_before>use termcolor::{Color, ColorSpec};

use crate::diagnostic::{LabelStyle, Severity};

/// Configures how a diagnostic is rendered.
#[derive(Clone, Debug)]
pub struct Config {
    /// The display style to use when rendering diagnostics.
    /// Defaults to: [`DisplayStyle::Rich`].
    ///
    /// [`DisplayStyle::Rich`]: DisplayStyle::Rich
    pub display_style: DisplayStyle,
    /// Column width of tabs.
    /// Defaults to: `4`.
    pub tab_width: usize,
    /// Styles to use when rendering the diagnostic.
    pub styles: Styles,
    /// Characters to use when rendering the diagnostic.
    pub chars: Chars,
    /// The minimum number of lines to be shown after the line on which a multiline [`Label`] begins.
    ///
    /// Defaults to: `3`.
    pub start_context_lines: usize,
    /// The minimum number of lines to be shown before the line on which a multiline [`Label`] ends.
    ///
    /// Defaults to: `1`.
    pub end_context_lines: usize,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            display_style: DisplayStyle::Rich,
            tab_width: 4,
            styles: Styles::default(),
            chars: Chars::default(),
            start_context_lines: 3,
            end_context_lines: 1,
        }
    }
}

/// The display style to use when rendering diagnostics.
#[derive(Clone, Debug)]
pub enum DisplayStyle {
    /// Output a richly formatted diagnostic, with source code previews.
    ///
    /// ```text
    /// error[E0001]: unexpected type in `+` application
    ///   ┌─ test:2:9
    ///   │
    /// 2 │ (+ test "")
    ///   │         ^^ expected `Int` but found `String`
    ///   │
    ///   = expected type `Int`
    ///        found type `String`
    ///
    /// error[E0002]: Bad config found
    ///
    /// ```
    Rich,
    /// Output a condensed diagnostic, with a line number, severity, message and notes (if any).
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// = expected type `Int`
    ///      found type `String`
    ///
    /// error[E0002]: Bad config found
    /// ```
    Medium,
    /// Output a short diagnostic, with a line number, severity, and message.
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// error[E0002]: Bad config found
    /// ```
    Short,
}

/// Styles to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Styles {
    /// The style to use when rendering bug headers.
    /// Defaults to `fg:red bold intense`.
    pub header_bug: ColorSpec,
    /// The style to use when rendering error headers.
    /// Defaults to `fg:red bold intense`.
    pub header_error: ColorSpec,
    /// The style to use when rendering warning headers.
    /// Defaults to `fg:yellow bold intense`.
    pub header_warning: ColorSpec,
    /// The style to use when rendering note headers.
    /// Defaults to `fg:green bold intense`.
    pub header_note: ColorSpec,
    /// The style to use when rendering help headers.
    /// Defaults to `fg:cyan bold intense`.
    pub header_help: ColorSpec,
    /// The style to use when the main diagnostic message.
    /// Defaults to `bold intense`.
    pub header_message: ColorSpec,

    /// The style to use when rendering bug labels.
    /// Defaults to `fg:red`.
    pub primary_label_bug: ColorSpec,
    /// The style to use when rendering error labels.
    /// Defaults to `fg:red`.
    pub primary_label_error: ColorSpec,
    /// The style to use when rendering warning labels.
    /// Defaults to `fg:yellow`.
    pub primary_label_warning: ColorSpec,
    /// The style to use when rendering note labels.
    /// Defaults to `fg:green`.
    pub primary_label_note: ColorSpec,
    /// The style to use when rendering help labels.
    /// Defaults to `fg:cyan`.
    pub primary_label_help: ColorSpec,
    /// The style to use when rendering secondary labels.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub secondary_label: ColorSpec,

    /// The style to use when rendering the line numbers.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub line_number: ColorSpec,
    /// The style to use when rendering the source code borders.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub source_border: ColorSpec,
    /// The style to use when rendering the note bullets.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub note_bullet: ColorSpec,
}

impl Styles {
    /// The style used to mark a header at a given severity.
    pub fn header(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.header_bug,
            Severity::Error => &self.header_error,
            Severity::Warning => &self.header_warning,
            Severity::Note => &self.header_note,
            Severity::Help => &self.header_help,
        }
    }

    /// The style used to mark a primary or secondary label at a given severity.
    pub fn label(&self, severity: Severity, label_style: LabelStyle) -> &ColorSpec {
        match (label_style, severity) {
            (LabelStyle::Primary, Severity::Bug) => &self.primary_label_bug,
            (LabelStyle::Primary, Severity::Error) => &self.primary_label_error,
            (LabelStyle::Primary, Severity::Warning) => &self.primary_label_warning,
            (LabelStyle::Primary, Severity::Note) => &self.primary_label_note,
            (LabelStyle::Primary, Severity::Help) => &self.primary_label_help,
            (LabelStyle::Secondary, _) => &self.secondary_label,
        }
    }

    #[doc(hidden)]
    pub fn with_blue(blue: Color) -> Styles {
        let header = ColorSpec::new().set_bold(true).set_intense(true).clone();

        Styles {
            header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
            header_error: header.clone().set_fg(Some(Color::Red)).clone(),
            header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
            header_note: header.clone().set_fg(Some(Color::Green)).clone(),
            header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
            header_message: header,

            primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(),
            primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(),
            primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
            secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(),

            line_number: ColorSpec::new().set_fg(Some(blue)).clone(),
            source_border: ColorSpec::new().set_fg(Some(blue)).clone(),
            note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(),
        }
    }
}

impl Default for Styles {
    fn default() -> Styles {
        // Blue is really difficult to see on the standard windows command line
        #[cfg(windows)]
        const BLUE: Color = Color::Cyan;
        #[cfg(not(windows))]
        const BLUE: Color = Color::Blue;

        Self::with_blue(BLUE)
    }
}

/// Characters to use when rendering the diagnostic.
///
/// By using the feature `ascii-only` you can switch the defaults to an
/// ASCII-only format suitable for rendering on terminals that do not support
/// box drawing characters.
#[derive(Clone, Debug)]
pub struct Chars {
    /// The characters to use for the top-left border of the snippet.
    /// Defaults to: `"┌─"` or `"-->"` with `ascii-only` feature.
    pub snippet_start: String,
    /// The character to use for the left border of the source.
    /// Defaults to: `'│'` or `'|'` with `ascii-only` feature.
    pub source_border_left: char,
    /// The character to use for the left border break of the source.
    /// Defaults to: `'·'` or `'.'` with `ascii-only` feature.
    pub source_border_left_break: char,

    /// The character to use for the note bullet.
    /// Defaults to: `'='`.
    pub note_bullet: char,

    /// The character to use for marking a single-line primary label.
    /// Defaults to: `'^'`.
    pub single_primary_caret: char,
    /// The character to use for marking a single-line secondary label.
    /// Defaults to: `'-'`.
    pub single_secondary_caret: char,

    /// The character to use for marking the start of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multi_primary_caret_start: char,
    /// The character to use for marking the end of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multi_primary_caret_end: char,
    /// The character to use for marking the start of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multi_secondary_caret_start: char,
    /// The character to use for marking the end of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multi_secondary_caret_end: char,
    /// The character to use for the top-left corner of a multi-line label.
    /// Defaults to: `'╭'` or `'/'` with `ascii-only` feature.
    pub multi_top_left: char,
    /// The character to use for the top of a multi-line label.
    /// Defaults to: `'─'` or `'-'` with `ascii-only` feature.
    pub multi_top: char,
    /// The character to use for the bottom-left corner of a multi-line label.
    /// Defaults to: `'╰'` or `'\\'` with `ascii-only` feature.
    pub multi_bottom_left: char,
    /// The character to use when marking the bottom of a multi-line label.
    /// Defaults to: `'─'` or `'-'` with `ascii-only` feature.
    pub multi_bottom: char,
    /// The character to use for the left of a multi-line label.
    /// Defaults to: `'│'` or `'|'` with `ascii-only` feature.
    pub multi_left: char,

    /// The character to use for the left of a pointer underneath a caret.
    /// Defaults to: `'│'` or `'|'` with `ascii-only` feature.
    pub pointer_left: char,
}

impl Default for Chars {
    fn default() -> Chars {
        Chars::box_drawing()
    }
}

impl Chars {
    /// A character set that uses Unicode box drawing characters.
    pub fn box_drawing() -> Chars {
        Chars {
            snippet_start: "┌─".into(),
            source_border_left: '│',
            source_border_left_break: '·',

            note_bullet: '=',

            single_primary_caret: '^',
            single_secondary_caret: '-',

            multi_primary_caret_start: '^',
            multi_primary_caret_end: '^',
            multi_secondary_caret_start: '\'',
            multi_secondary_caret_end: '\'',
            multi_top_left: '╭',
            multi_top: '─',
            multi_bottom_left: '╰',
            multi_bottom: '─',
            multi_left: '│',

            pointer_left: '│',
        }
    }

    /// A character set that only uses ASCII characters.
    ///
    /// This is useful if your terminal's font does not support box drawing
    /// characters well and results in output that looks similar to rustc's
    /// diagnostic output.
    pub fn ascii() -> Chars {
        Chars {
            snippet_start: "-->".into(),
            source_border_left: '|',
            source_border_left_break: '.',

            note_bullet: '=',

            single_primary_caret: '^',
            single_secondary_caret: '-',

            multi_primary_caret_start: '^',
            multi_primary_caret_end: '^',
            multi_secondary_caret_start: '\'',
            multi_secondary_caret_end: '\'',
            multi_top_left: '/',
            multi_top: '-',
            multi_bottom_left: '\\',
            multi_bottom: '-',
            multi_left: '|',

            pointer_left: '|',
        }
    }
}
<commit_msg>remove ascii-only feature from documentation<commit_after>use termcolor::{Color, ColorSpec};

use crate::diagnostic::{LabelStyle, Severity};

/// Configures how a diagnostic is rendered.
#[derive(Clone, Debug)]
pub struct Config {
    /// The display style to use when rendering diagnostics.
    /// Defaults to: [`DisplayStyle::Rich`].
    ///
    /// [`DisplayStyle::Rich`]: DisplayStyle::Rich
    pub display_style: DisplayStyle,
    /// Column width of tabs.
    /// Defaults to: `4`.
    pub tab_width: usize,
    /// Styles to use when rendering the diagnostic.
    pub styles: Styles,
    /// Characters to use when rendering the diagnostic.
    pub chars: Chars,
    /// The minimum number of lines to be shown after the line on which a multiline [`Label`] begins.
    ///
    /// Defaults to: `3`.
    pub start_context_lines: usize,
    /// The minimum number of lines to be shown before the line on which a multiline [`Label`] ends.
    ///
    /// Defaults to: `1`.
    pub end_context_lines: usize,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            display_style: DisplayStyle::Rich,
            tab_width: 4,
            styles: Styles::default(),
            chars: Chars::default(),
            start_context_lines: 3,
            end_context_lines: 1,
        }
    }
}

/// The display style to use when rendering diagnostics.
#[derive(Clone, Debug)]
pub enum DisplayStyle {
    /// Output a richly formatted diagnostic, with source code previews.
    ///
    /// ```text
    /// error[E0001]: unexpected type in `+` application
    ///   ┌─ test:2:9
    ///   │
    /// 2 │ (+ test "")
    ///   │         ^^ expected `Int` but found `String`
    ///   │
    ///   = expected type `Int`
    ///        found type `String`
    ///
    /// error[E0002]: Bad config found
    ///
    /// ```
    Rich,
    /// Output a condensed diagnostic, with a line number, severity, message and notes (if any).
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// = expected type `Int`
    ///      found type `String`
    ///
    /// error[E0002]: Bad config found
    /// ```
    Medium,
    /// Output a short diagnostic, with a line number, severity, and message.
    ///
    /// ```text
    /// test:2:9: error[E0001]: unexpected type in `+` application
    /// error[E0002]: Bad config found
    /// ```
    Short,
}

/// Styles to use when rendering the diagnostic.
#[derive(Clone, Debug)]
pub struct Styles {
    /// The style to use when rendering bug headers.
    /// Defaults to `fg:red bold intense`.
    pub header_bug: ColorSpec,
    /// The style to use when rendering error headers.
    /// Defaults to `fg:red bold intense`.
    pub header_error: ColorSpec,
    /// The style to use when rendering warning headers.
    /// Defaults to `fg:yellow bold intense`.
    pub header_warning: ColorSpec,
    /// The style to use when rendering note headers.
    /// Defaults to `fg:green bold intense`.
    pub header_note: ColorSpec,
    /// The style to use when rendering help headers.
    /// Defaults to `fg:cyan bold intense`.
    pub header_help: ColorSpec,
    /// The style to use when the main diagnostic message.
    /// Defaults to `bold intense`.
    pub header_message: ColorSpec,

    /// The style to use when rendering bug labels.
    /// Defaults to `fg:red`.
    pub primary_label_bug: ColorSpec,
    /// The style to use when rendering error labels.
    /// Defaults to `fg:red`.
    pub primary_label_error: ColorSpec,
    /// The style to use when rendering warning labels.
    /// Defaults to `fg:yellow`.
    pub primary_label_warning: ColorSpec,
    /// The style to use when rendering note labels.
    /// Defaults to `fg:green`.
    pub primary_label_note: ColorSpec,
    /// The style to use when rendering help labels.
    /// Defaults to `fg:cyan`.
    pub primary_label_help: ColorSpec,
    /// The style to use when rendering secondary labels.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub secondary_label: ColorSpec,

    /// The style to use when rendering the line numbers.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub line_number: ColorSpec,
    /// The style to use when rendering the source code borders.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub source_border: ColorSpec,
    /// The style to use when rendering the note bullets.
    /// Defaults `fg:blue` (or `fg:cyan` on windows).
    pub note_bullet: ColorSpec,
}

impl Styles {
    /// The style used to mark a header at a given severity.
    pub fn header(&self, severity: Severity) -> &ColorSpec {
        match severity {
            Severity::Bug => &self.header_bug,
            Severity::Error => &self.header_error,
            Severity::Warning => &self.header_warning,
            Severity::Note => &self.header_note,
            Severity::Help => &self.header_help,
        }
    }

    /// The style used to mark a primary or secondary label at a given severity.
    pub fn label(&self, severity: Severity, label_style: LabelStyle) -> &ColorSpec {
        match (label_style, severity) {
            (LabelStyle::Primary, Severity::Bug) => &self.primary_label_bug,
            (LabelStyle::Primary, Severity::Error) => &self.primary_label_error,
            (LabelStyle::Primary, Severity::Warning) => &self.primary_label_warning,
            (LabelStyle::Primary, Severity::Note) => &self.primary_label_note,
            (LabelStyle::Primary, Severity::Help) => &self.primary_label_help,
            (LabelStyle::Secondary, _) => &self.secondary_label,
        }
    }

    #[doc(hidden)]
    pub fn with_blue(blue: Color) -> Styles {
        let header = ColorSpec::new().set_bold(true).set_intense(true).clone();

        Styles {
            header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
            header_error: header.clone().set_fg(Some(Color::Red)).clone(),
            header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
            header_note: header.clone().set_fg(Some(Color::Green)).clone(),
            header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
            header_message: header,

            primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
            primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(),
            primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(),
            primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
            secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(),

            line_number: ColorSpec::new().set_fg(Some(blue)).clone(),
            source_border: ColorSpec::new().set_fg(Some(blue)).clone(),
            note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(),
        }
    }
}

impl Default for Styles {
    fn default() -> Styles {
        // Blue is really difficult to see on the standard windows command line
        #[cfg(windows)]
        const BLUE: Color = Color::Cyan;
        #[cfg(not(windows))]
        const BLUE: Color = Color::Blue;

        Self::with_blue(BLUE)
    }
}

/// Characters to use when rendering the diagnostic.
///
/// By using [`Chars::ascii()`] you can switch to an ASCII-only format suitable
/// for rendering on terminals that do not support box drawing characters.
#[derive(Clone, Debug)]
pub struct Chars {
    /// The characters to use for the top-left border of the snippet.
    /// Defaults to: `"┌─"` or `"-->"` with [`Chars::ascii()`].
    pub snippet_start: String,
    /// The character to use for the left border of the source.
    /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`].
    pub source_border_left: char,
    /// The character to use for the left border break of the source.
    /// Defaults to: `'·'` or `'.'` with [`Chars::ascii()`].
    pub source_border_left_break: char,

    /// The character to use for the note bullet.
    /// Defaults to: `'='`.
    pub note_bullet: char,

    /// The character to use for marking a single-line primary label.
    /// Defaults to: `'^'`.
    pub single_primary_caret: char,
    /// The character to use for marking a single-line secondary label.
    /// Defaults to: `'-'`.
    pub single_secondary_caret: char,

    /// The character to use for marking the start of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multi_primary_caret_start: char,
    /// The character to use for marking the end of a multi-line primary label.
    /// Defaults to: `'^'`.
    pub multi_primary_caret_end: char,
    /// The character to use for marking the start of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multi_secondary_caret_start: char,
    /// The character to use for marking the end of a multi-line secondary label.
    /// Defaults to: `'\''`.
    pub multi_secondary_caret_end: char,
    /// The character to use for the top-left corner of a multi-line label.
    /// Defaults to: `'╭'` or `'/'` with [`Chars::ascii()`].
    pub multi_top_left: char,
    /// The character to use for the top of a multi-line label.
    /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`].
    pub multi_top: char,
    /// The character to use for the bottom-left corner of a multi-line label.
    /// Defaults to: `'╰'` or `'\\'` with [`Chars::ascii()`].
    pub multi_bottom_left: char,
    /// The character to use when marking the bottom of a multi-line label.
    /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`].
    pub multi_bottom: char,
    /// The character to use for the left of a multi-line label.
    /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`].
    pub multi_left: char,

    /// The character to use for the left of a pointer underneath a caret.
    /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`].
    pub pointer_left: char,
}

impl Default for Chars {
    fn default() -> Chars {
        Chars::box_drawing()
    }
}

impl Chars {
    /// A character set that uses Unicode box drawing characters.
    pub fn box_drawing() -> Chars {
        Chars {
            snippet_start: "┌─".into(),
            source_border_left: '│',
            source_border_left_break: '·',

            note_bullet: '=',

            single_primary_caret: '^',
            single_secondary_caret: '-',

            multi_primary_caret_start: '^',
            multi_primary_caret_end: '^',
            multi_secondary_caret_start: '\'',
            multi_secondary_caret_end: '\'',
            multi_top_left: '╭',
            multi_top: '─',
            multi_bottom_left: '╰',
            multi_bottom: '─',
            multi_left: '│',

            pointer_left: '│',
        }
    }

    /// A character set that only uses ASCII characters.
    ///
    /// This is useful if your terminal's font does not support box drawing
    /// characters well and results in output that looks similar to rustc's
    /// diagnostic output.
    pub fn ascii() -> Chars {
        Chars {
            snippet_start: "-->".into(),
            source_border_left: '|',
            source_border_left_break: '.',

            note_bullet: '=',

            single_primary_caret: '^',
            single_secondary_caret: '-',

            multi_primary_caret_start: '^',
            multi_primary_caret_end: '^',
            multi_secondary_caret_start: '\'',
            multi_secondary_caret_end: '\'',
            multi_top_left: '/',
            multi_top: '-',
            multi_bottom_left: '\\',
            multi_bottom: '-',
            multi_left: '|',

            pointer_left: '|',
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused, clippy::needless_pass_by_value)]
#![warn(clippy::map_entry)]

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;

fn foo() {}

fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(k, v);
    }
}

fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v);
    }
}

fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if m.contains_key(&k) {
        None
    } else {
        m.insert(k, v)
    };
}

fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if m.contains_key(&k) {
        None
    } else {
        foo();
        m.insert(k, v)
    };
}

fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(o, v);
    }
}

// should not trigger, because the one uses different HashMap from another one
fn insert_other<K: Eq + Hash, V>(m: &mut HashMap<K, V>, n: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        n.insert(k, v);
    }
}

fn main() {}
<commit_msg>Improve tests<commit_after>#![allow(unused, clippy::needless_pass_by_value)]
#![warn(clippy::map_entry)]

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;

fn foo() {}

fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(k, v);
    }
}

fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v);
    }
}

fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if m.contains_key(&k) {
        None
    } else {
        m.insert(k, v)
    };
}

fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
    if m.contains_key(&k) {
        None
    } else {
        foo();
        m.insert(k, v)
    };
}

fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        foo();
        m.insert(k, v)
    } else {
        None
    };
}

fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) {
    if !m.contains_key(&k) {
        m.insert(o, v);
    }
}

// should not trigger, because the one uses different HashMap from another one
fn insert_from_different_map<K: Eq + Hash, V>(m: HashMap<K, V>, n: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        n.insert(k, v);
    }
}

// should not trigger, because the one uses different HashMap from another one
fn insert_from_different_map2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, n: &mut HashMap<K, V>, k: K, v: V) {
    if !m.contains_key(&k) {
        n.insert(k, v);
    }
}

fn main() {}
<|endoftext|>


<commit_before>// Not all functions are used by all tests.
#![allow(dead_code)]

use std::io::{self, Read, Write};
use std::time::Duration;

use bytes::{Buf, BufMut};
use mio::{Events, Poll};

pub use ports::localhost;

pub trait TryRead {
    fn try_read_buf<B: BufMut>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
    where
        Self: Sized,
    {
        // Reads the length of the slice supplied by buf.mut_bytes into the buffer
        // This is not guaranteed to consume an entire datagram or segment.
        // If your protocol is msg based (instead of continuous stream) you should
        // ensure that your buffer is large enough to hold an entire segment (1532 bytes if not jumbo
        // frames)
        let res = self.try_read(unsafe { buf.bytes_mut() });

        if let Ok(Some(cnt)) = res {
            unsafe {
                buf.advance_mut(cnt);
            }
        }

        res
    }

    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;
}

pub trait TryWrite {
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
    where
        Self: Sized,
    {
        let res = self.try_write(buf.bytes());

        if let Ok(Some(cnt)) = res {
            buf.advance(cnt);
        }

        res
    }

    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;
}

impl<T: Read> TryRead for T {
    fn try_read(&mut self, dst: &mut [u8]) -> io::Result<Option<usize>> {
        self.read(dst).map_non_block()
    }
}

impl<T: Write> TryWrite for T {
    fn try_write(&mut self, src: &[u8]) -> io::Result<Option<usize>> {
        self.write(src).map_non_block()
    }
}

/*
 *
 * ===== Helpers =====
 *
 */

/// A helper trait to provide the map_non_block function on Results.
trait MapNonBlock<T> {
    /// Maps a `Result<T>` to a `Result<Option<T>>` by converting
    /// operation-would-block errors into `Ok(None)`.
    fn map_non_block(self) -> io::Result<Option<T>>;
}

impl<T> MapNonBlock<T> for io::Result<T> {
    fn map_non_block(self) -> io::Result<Option<T>> {
        use std::io::ErrorKind::WouldBlock;

        match self {
            Ok(value) => Ok(Some(value)),
            Err(err) => {
                if let WouldBlock = err.kind() {
                    Ok(None)
                } else {
                    Err(err)
                }
            }
        }
    }
}

mod ports {
    use std::net::SocketAddr;
    use std::str::FromStr;
    use std::sync::atomic::AtomicUsize;
    use std::sync::atomic::Ordering::SeqCst;

    // Helper for getting a unique port for the task run
    // TODO: Reuse ports to not spam the system
    static mut NEXT_PORT: AtomicUsize = AtomicUsize::new(0);
    const FIRST_PORT: usize = 18080;

    fn next_port() -> usize {
        unsafe {
            // If the atomic was never used, set it to the initial port
            NEXT_PORT.compare_and_swap(0, FIRST_PORT, SeqCst);

            // Get and increment the port list
            NEXT_PORT.fetch_add(1, SeqCst)
        }
    }

    pub fn localhost() -> SocketAddr {
        let s = format!("127.0.0.1:{}", next_port());
        FromStr::from_str(&s).unwrap()
    }
}

pub fn expect_no_events(poll: &mut Poll, events: &mut Events) {
    poll.poll(events, Some(Duration::from_millis(50)))
        .expect("unable to poll");
    assert_eq!(
        events.iter().count(),
        0,
        "received events, but didn't expect any"
    );
}
<commit_msg>Use Events::is_empty in expect_no_events<commit_after>// Not all functions are used by all tests.
#![allow(dead_code)]

use std::io::{self, Read, Write};
use std::time::Duration;

use bytes::{Buf, BufMut};
use mio::{Events, Poll};

pub use ports::localhost;

pub trait TryRead {
    fn try_read_buf<B: BufMut>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
    where
        Self: Sized,
    {
        // Reads the length of the slice supplied by buf.mut_bytes into the buffer
        // This is not guaranteed to consume an entire datagram or segment.
        // If your protocol is msg based (instead of continuous stream) you should
        // ensure that your buffer is large enough to hold an entire segment (1532 bytes if not jumbo
        // frames)
        let res = self.try_read(unsafe { buf.bytes_mut() });

        if let Ok(Some(cnt)) = res {
            unsafe {
                buf.advance_mut(cnt);
            }
        }

        res
    }

    fn try_read(&mut self, buf: &mut [u8]) -> io::Result<Option<usize>>;
}

pub trait TryWrite {
    fn try_write_buf<B: Buf>(&mut self, buf: &mut B) -> io::Result<Option<usize>>
    where
        Self: Sized,
    {
        let res = self.try_write(buf.bytes());

        if let Ok(Some(cnt)) = res {
            buf.advance(cnt);
        }

        res
    }

    fn try_write(&mut self, buf: &[u8]) -> io::Result<Option<usize>>;
}

impl<T: Read> TryRead for T {
    fn try_read(&mut self, dst: &mut [u8]) -> io::Result<Option<usize>> {
        self.read(dst).map_non_block()
    }
}

impl<T: Write> TryWrite for T {
    fn try_write(&mut self, src: &[u8]) -> io::Result<Option<usize>> {
        self.write(src).map_non_block()
    }
}

/*
 *
 * ===== Helpers =====
 *
 */

/// A helper trait to provide the map_non_block function on Results.
trait MapNonBlock<T> {
    /// Maps a `Result<T>` to a `Result<Option<T>>` by converting
    /// operation-would-block errors into `Ok(None)`.
    fn map_non_block(self) -> io::Result<Option<T>>;
}

impl<T> MapNonBlock<T> for io::Result<T> {
    fn map_non_block(self) -> io::Result<Option<T>> {
        use std::io::ErrorKind::WouldBlock;

        match self {
            Ok(value) => Ok(Some(value)),
            Err(err) => {
                if let WouldBlock = err.kind() {
                    Ok(None)
                } else {
                    Err(err)
                }
            }
        }
    }
}

mod ports {
    use std::net::SocketAddr;
    use std::str::FromStr;
    use std::sync::atomic::AtomicUsize;
    use std::sync::atomic::Ordering::SeqCst;

    // Helper for getting a unique port for the task run
    // TODO: Reuse ports to not spam the system
    static mut NEXT_PORT: AtomicUsize = AtomicUsize::new(0);
    const FIRST_PORT: usize = 18080;

    fn next_port() -> usize {
        unsafe {
            // If the atomic was never used, set it to the initial port
            NEXT_PORT.compare_and_swap(0, FIRST_PORT, SeqCst);

            // Get and increment the port list
            NEXT_PORT.fetch_add(1, SeqCst)
        }
    }

    pub fn localhost() -> SocketAddr {
        let s = format!("127.0.0.1:{}", next_port());
        FromStr::from_str(&s).unwrap()
    }
}

pub fn expect_no_events(poll: &mut Poll, events: &mut Events) {
    poll.poll(events, Some(Duration::from_millis(50)))
        .expect("unable to poll");
    assert!(events.is_empty(), "received events, but didn't expect any");
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

use super::file::header::data::FileHeaderData;

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
    caused_by: Option<Box<Error>>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
            caused_by: None,
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None,
            caused_by: None,
        }
    }

    pub fn with_cause(mut self, e: Box<Error>) -> ParserError {
        self.caused_by = Some(e);
        self
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

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

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub struct Parser<HP> {
    headerp : HP,
}

impl<HP: FileHeaderParser> Parser<HP> {

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError> {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            let mut p = ParserError::new("Dividing text failed",
                                         s, 0,
                    "Dividing text with divide_text() failed");
            return Err(p.with_cause(Box::new(divided.err().unwrap())));
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    pub fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError> {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        let text = format!("---\n{}\n---\n{}", h_text, data);
        Ok(text)
    }

    fn divide_text(&self, text: &String) -> Result<(Option<String>, Option<String>), ParserError> {
        let re = Regex::new(r"(?sm)^---$(.*)^---$(.*)").unwrap();

        debug!("Splitting: '{}'", text);
        debug!("   regex = {:?}", re);

        re.captures(text).map(|captures| {

            if captures.len() != 3 {
                debug!("Unexpected amount of captures");
                return Err(ParserError::new("Unexpected Regex output",
                                            text.clone(), 0,
                                            "The regex to divide text into header and content had an unexpected output."))
            }

            let header  = captures.at(1).map(|s| String::from(s));
            let content = captures.at(2).map(|s| String::from(s));

            debug!("Splitted, Header = '{:?}'", header.clone().unwrap_or("NONE".into()));
            debug!("Splitted, Data   = '{:?}'", content.clone().unwrap_or("NONE".into()));
            Ok((header, content))
        }).or_else(|| {
            debug!("Cannot capture from text");
            let e = ParserError::new("Cannot run regex on text",
                                     text.clone(), 0,
                                     "Cannot run regex on text to divide it into header and content.");
            Some(Err(e))
        }).unwrap()
    }

}

<commit_msg>Fix: Parser::write() can get reference tuple<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

use super::file::header::data::FileHeaderData;

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
    caused_by: Option<Box<Error>>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
            caused_by: None,
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None,
            caused_by: None,
        }
    }

    pub fn with_cause(mut self, e: Box<Error>) -> ParserError {
        self.caused_by = Some(e);
        self
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

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

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub struct Parser<HP> {
    headerp : HP,
}

impl<HP: FileHeaderParser> Parser<HP> {

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError> {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            let mut p = ParserError::new("Dividing text failed",
                                         s, 0,
                    "Dividing text with divide_text() failed");
            return Err(p.with_cause(Box::new(divided.err().unwrap())));
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result<String, ParserError> {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        let text = format!("---\n{}\n---\n{}", h_text, data);
        Ok(text)
    }

    fn divide_text(&self, text: &String) -> Result<(Option<String>, Option<String>), ParserError> {
        let re = Regex::new(r"(?sm)^---$(.*)^---$(.*)").unwrap();

        debug!("Splitting: '{}'", text);
        debug!("   regex = {:?}", re);

        re.captures(text).map(|captures| {

            if captures.len() != 3 {
                debug!("Unexpected amount of captures");
                return Err(ParserError::new("Unexpected Regex output",
                                            text.clone(), 0,
                                            "The regex to divide text into header and content had an unexpected output."))
            }

            let header  = captures.at(1).map(|s| String::from(s));
            let content = captures.at(2).map(|s| String::from(s));

            debug!("Splitted, Header = '{:?}'", header.clone().unwrap_or("NONE".into()));
            debug!("Splitted, Data   = '{:?}'", content.clone().unwrap_or("NONE".into()));
            Ok((header, content))
        }).or_else(|| {
            debug!("Cannot capture from text");
            let e = ParserError::new("Cannot run regex on text",
                                     text.clone(), 0,
                                     "Cannot run regex on text to divide it into header and content.");
            Some(Err(e))
        }).unwrap()
    }

}

<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{sys, SBError, SBStream};
use std::ffi::CString;
use std::fmt;
use std::ptr;

/// The value of a variable, register or expression.
pub struct SBStructuredData {
    /// The underlying raw `SBStructuredDataRef`.
    pub raw: sys::SBStructuredDataRef,
}

impl SBStructuredData {
    /// Construct a new `SBStructuredData`.
    pub(crate) fn wrap(raw: sys::SBStructuredDataRef) -> SBStructuredData {
        SBStructuredData { raw }
    }

    /// Construct a new `Some(SBStructuredData)` or `None`.
    pub(crate) fn maybe_wrap(raw: sys::SBStructuredDataRef) -> Option<SBStructuredData> {
        if unsafe { sys::SBStructuredDataIsValid(raw) } {
            Some(SBStructuredData { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBStructuredData` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBStructuredDataIsValid(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn clear(&self) {
        unsafe { sys::SBStructuredDataClear(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn set_from_json(&self, stream: &SBStream) -> Result<(), SBError> {
        let e = SBError::wrap(unsafe { sys::SBStructuredDataSetFromJSON(self.raw, stream.raw) });
        if e.is_success() {
            Ok(())
        } else {
            Err(e)
        }
    }

    #[allow(missing_docs)]
    pub fn get_as_json(&self) -> Result<SBStream, SBError> {
        let stream = SBStream::new();
        let e = SBError::wrap(unsafe { sys::SBStructuredDataGetAsJSON(self.raw, stream.raw) });
        if e.is_success() {
            Ok(stream)
        } else {
            Err(e)
        }
    }

    /// Return the type of data in this data structure.
    pub fn data_type(&self) -> sys::StructuredDataType {
        unsafe { sys::SBStructuredDataGetType(self.raw) }
    }

    /// Return the size (number of elements) in this data structure
    /// if it is an array or dictionary type. For other types,
    /// `0` will be returned.
    pub fn size(&self) -> usize {
        unsafe { sys::SBStructuredDataGetSize(self.raw) }
    }

    /// Return the value corresponding to a key if this data structure
    /// is a dictionary type.
    pub fn value_for_key(&self, key: &str) -> Option<SBStructuredData> {
        let key = CString::new(key).unwrap();
        SBStructuredData::maybe_wrap(unsafe {
            sys::SBStructuredDataGetValueForKey(self.raw, key.as_ptr())
        })
    }

    /// Return the value corresponding to an index if this data structure
    /// is array.
    pub fn item_at_index(&self, idx: usize) -> Option<SBStructuredData> {
        SBStructuredData::maybe_wrap(unsafe { sys::SBStructuredDataGetItemAtIndex(self.raw, idx) })
    }

    /// Return the integer value if this data structure is an integer type.
    pub fn integer_value(&self) -> Option<u64> {
        if self.data_type() == sys::StructuredDataType::Integer {
            Some(unsafe { sys::SBStructuredDataGetIntegerValue(self.raw, 0) })
        } else {
            None
        }
    }

    /// Return the floating point value if this data structure is a floating
    /// type.
    pub fn float_value(&self) -> Option<f64> {
        if self.data_type() == sys::StructuredDataType::Float {
            Some(unsafe { sys::SBStructuredDataGetFloatValue(self.raw, 0.0) })
        } else {
            None
        }
    }

    /// Return the boolean value if this data structure is a boolean type.
    pub fn boolean_value(&self) -> Option<bool> {
        if self.data_type() == sys::StructuredDataType::Boolean {
            Some(unsafe { sys::SBStructuredDataGetBooleanValue(self.raw, false) })
        } else {
            None
        }
    }

    /// Provides the string value if this data structure is a string type.
    pub fn string_value(&self) -> Option<String> {
        if self.data_type() == sys::StructuredDataType::String {
            unsafe {
                let sz = sys::SBStructuredDataGetStringValue(self.raw, ptr::null_mut(), 0) + 1;
                let mut buf: Vec<u8> = Vec::with_capacity(sz);
                sys::SBStructuredDataGetStringValue(self.raw, buf.as_mut_ptr() as *mut i8, sz);
                buf.set_len(sz);
                String::from_utf8(buf).ok()
            }
        } else {
            None
        }
    }
}

impl Clone for SBStructuredData {
    fn clone(&self) -> SBStructuredData {
        SBStructuredData {
            raw: unsafe { sys::CloneSBStructuredData(self.raw) },
        }
    }
}

impl fmt::Debug for SBStructuredData {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBStructuredDataGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBStructuredData {{ {} }}", stream.data())
    }
}

impl Drop for SBStructuredData {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBStructuredData(self.raw) };
    }
}

unsafe impl Send for SBStructuredData {}
unsafe impl Sync for SBStructuredData {}

#[cfg(feature = "graphql")]
#[graphql_object]
impl SBStructuredData {
    fn is_valid() -> bool {
        self.is_valid()
    }
}
<commit_msg>SBStructuredData: Add keys accessor.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{sys, SBError, SBStream, SBStringList};
use std::ffi::CString;
use std::fmt;
use std::ptr;

/// The value of a variable, register or expression.
pub struct SBStructuredData {
    /// The underlying raw `SBStructuredDataRef`.
    pub raw: sys::SBStructuredDataRef,
}

impl SBStructuredData {
    /// Construct a new `SBStructuredData`.
    pub(crate) fn wrap(raw: sys::SBStructuredDataRef) -> SBStructuredData {
        SBStructuredData { raw }
    }

    /// Construct a new `Some(SBStructuredData)` or `None`.
    pub(crate) fn maybe_wrap(raw: sys::SBStructuredDataRef) -> Option<SBStructuredData> {
        if unsafe { sys::SBStructuredDataIsValid(raw) } {
            Some(SBStructuredData { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBStructuredData` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBStructuredDataIsValid(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn clear(&self) {
        unsafe { sys::SBStructuredDataClear(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn set_from_json(&self, stream: &SBStream) -> Result<(), SBError> {
        let e = SBError::wrap(unsafe { sys::SBStructuredDataSetFromJSON(self.raw, stream.raw) });
        if e.is_success() {
            Ok(())
        } else {
            Err(e)
        }
    }

    #[allow(missing_docs)]
    pub fn get_as_json(&self) -> Result<SBStream, SBError> {
        let stream = SBStream::new();
        let e = SBError::wrap(unsafe { sys::SBStructuredDataGetAsJSON(self.raw, stream.raw) });
        if e.is_success() {
            Ok(stream)
        } else {
            Err(e)
        }
    }

    /// Return the type of data in this data structure.
    pub fn data_type(&self) -> sys::StructuredDataType {
        unsafe { sys::SBStructuredDataGetType(self.raw) }
    }

    /// Return the size (number of elements) in this data structure
    /// if it is an array or dictionary type. For other types,
    /// `0` will be returned.
    pub fn size(&self) -> usize {
        unsafe { sys::SBStructuredDataGetSize(self.raw) }
    }

    /// Return the keys in the structured data if this data structure
    /// is a dictionary type.
    pub fn keys(&self) -> SBStringList {
        let names = SBStringList::new();
        unsafe { sys::SBStructuredDataGetKeys(self.raw, names.raw) };
        names
    }

    /// Return the value corresponding to a key if this data structure
    /// is a dictionary type.
    pub fn value_for_key(&self, key: &str) -> Option<SBStructuredData> {
        let key = CString::new(key).unwrap();
        SBStructuredData::maybe_wrap(unsafe {
            sys::SBStructuredDataGetValueForKey(self.raw, key.as_ptr())
        })
    }

    /// Return the value corresponding to an index if this data structure
    /// is array.
    pub fn item_at_index(&self, idx: usize) -> Option<SBStructuredData> {
        SBStructuredData::maybe_wrap(unsafe { sys::SBStructuredDataGetItemAtIndex(self.raw, idx) })
    }

    /// Return the integer value if this data structure is an integer type.
    pub fn integer_value(&self) -> Option<u64> {
        if self.data_type() == sys::StructuredDataType::Integer {
            Some(unsafe { sys::SBStructuredDataGetIntegerValue(self.raw, 0) })
        } else {
            None
        }
    }

    /// Return the floating point value if this data structure is a floating
    /// type.
    pub fn float_value(&self) -> Option<f64> {
        if self.data_type() == sys::StructuredDataType::Float {
            Some(unsafe { sys::SBStructuredDataGetFloatValue(self.raw, 0.0) })
        } else {
            None
        }
    }

    /// Return the boolean value if this data structure is a boolean type.
    pub fn boolean_value(&self) -> Option<bool> {
        if self.data_type() == sys::StructuredDataType::Boolean {
            Some(unsafe { sys::SBStructuredDataGetBooleanValue(self.raw, false) })
        } else {
            None
        }
    }

    /// Provides the string value if this data structure is a string type.
    pub fn string_value(&self) -> Option<String> {
        if self.data_type() == sys::StructuredDataType::String {
            unsafe {
                let sz = sys::SBStructuredDataGetStringValue(self.raw, ptr::null_mut(), 0) + 1;
                let mut buf: Vec<u8> = Vec::with_capacity(sz);
                sys::SBStructuredDataGetStringValue(self.raw, buf.as_mut_ptr() as *mut i8, sz);
                buf.set_len(sz);
                String::from_utf8(buf).ok()
            }
        } else {
            None
        }
    }
}

impl Clone for SBStructuredData {
    fn clone(&self) -> SBStructuredData {
        SBStructuredData {
            raw: unsafe { sys::CloneSBStructuredData(self.raw) },
        }
    }
}

impl fmt::Debug for SBStructuredData {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBStructuredDataGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBStructuredData {{ {} }}", stream.data())
    }
}

impl Drop for SBStructuredData {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBStructuredData(self.raw) };
    }
}

unsafe impl Send for SBStructuredData {}
unsafe impl Sync for SBStructuredData {}

#[cfg(feature = "graphql")]
#[graphql_object]
impl SBStructuredData {
    fn is_valid() -> bool {
        self.is_valid()
    }
}
<|endoftext|>


<commit_before>use crate::cache::{AssetLoadContext, MMappedAsset};
use crate::coordinates;
use anyhow::Error;
use bit_vec::BitVec;
use crossbeam::channel::{self, Receiver, Sender};
use futures::{Future, future::BoxFuture};
use lru_cache::LruCache;
use memmap::Mmap;
use serde::{Deserialize, Serialize};
use std::f64::consts::PI;
use std::ops::{Deref, Index};
use std::{
    collections::{HashMap, HashSet},
    sync::{Arc, Weak},
};
use futures::FutureExt;
use vec_map::VecMap;

pub trait Scalar: Copy + 'static {
    fn from_f64(_: f64) -> Self;
    fn to_f64(self) -> f64;
}

/// Wrapper around BitVec that converts values to f64's so that it can be uses as a backing for a
/// GlobalRaster.
pub struct BitContainer(pub BitVec<u32>);
impl Index<usize> for BitContainer {
    type Output = u8;
    fn index(&self, i: usize) -> &u8 {
        if self.0[i] {
            &255
        } else {
            &0
        }
    }
}

#[derive(Serialize, Deserialize)]
pub(crate) struct MMappedRasterHeader {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub cell_size: f64,

    pub latitude_llcorner: f64,
    pub longitude_llcorner: f64,
}

/// Currently assumes that values are taken at the lower left corner of each cell.
#[derive(Clone, Serialize, Deserialize)]
pub struct Raster<T: Into<f64> + Copy, C: Deref<Target = [T]> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub cell_size: f64,

    pub latitude_llcorner: f64,
    pub longitude_llcorner: f64,

    pub values: C,
}

impl Raster<u8, Mmap> {
    #[allow(unused)]
    pub(crate) fn from_mmapped_raster<MR: MMappedAsset<Header = MMappedRasterHeader>>(
        asset: MR,
        context: &mut AssetLoadContext,
    ) -> Result<Self, Error> {
        let (header, mmap) = asset.load(context)?;

        Ok(Self {
            width: header.width,
            height: header.height,
            bands: header.bands,
            cell_size: header.cell_size,
            latitude_llcorner: header.latitude_llcorner,
            longitude_llcorner: header.longitude_llcorner,
            values: mmap.make_read_only()?,
        })
    }
}

impl<T: Into<f64> + Copy, C: Deref<Target = [T]>> Raster<T, C> {
    /// Returns the vertical spacing between cells, in meters.
    #[allow(unused)]
    pub fn vertical_spacing(&self) -> f64 {
        self.cell_size.to_radians() * coordinates::PLANET_RADIUS
    }

    /// Returns the horizontal spacing between cells, in meters.
    #[allow(unused)]
    pub fn horizontal_spacing(&self, y: usize) -> f64 {
        self.vertical_spacing()
            * (self.latitude_llcorner + self.cell_size * y as f64).to_radians().cos()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> Option<f64> {
        assert!(band < self.bands);

        let x = (longitude - self.longitude_llcorner) / self.cell_size;
        let y = (self.height - 1) as f64 - (latitude - self.latitude_llcorner) / self.cell_size;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;

        if x < 0.0 || fx >= self.width || y < 0.0 || fy >= self.height {
            return None;
        }

        // TODO: These should be interpolating across tiles...
        let fx_1 = (fx + 1).min(self.width - 1);
        let fy_1 = (fy + 1).min(self.height - 1);

        let h00 = self.values[(fx + fy * self.width) * self.bands + band].into();
        let h10 = self.values[(fx_1 + fy * self.width) * self.bands + band].into();
        let h01 = self.values[(fx + fy_1 * self.width) * self.bands + band].into();
        let h11 = self.values[(fx_1 + fy_1 * self.width) * self.bands + band].into();
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        Some(h0 + (h1 - h0) * (x - fx as f64))
    }

    pub fn nearest3(&self, latitude: f64, longitude: f64) -> Option<[f64; 3]> {
        assert!(self.bands >= 3);

        let x = (longitude - self.longitude_llcorner) / self.cell_size;
        let y = self.height as f64 - (latitude - self.latitude_llcorner) / self.cell_size;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;

        if x < 0.0 || fx >= self.width || y < 0.0 || fy >= self.height {
            return None;
        }

        let slice = &self.values[(fx + fy * self.width) * self.bands..][..3];
        Some([slice[0].into(), slice[1].into(), slice[2].into()])
    }
}

#[async_trait::async_trait]
pub(crate) trait RasterSource: Send + Sync {
    type Type: Into<f64> + Copy;
    type Container: Deref<Target = [Self::Type]>;
    async fn load(
        &self,
        latitude: i16,
        longitude: i16,
    ) -> Result<Option<Raster<Self::Type, Self::Container>>, Error>;
    fn bands(&self) -> usize;

    /// Degrees of latitude and longitude covered by each raster.
    fn raster_size(&self) -> i16 {
        1
    }
}

pub(crate) struct RasterCache<T: Into<f64> + Copy + 'static, C: Deref<Target = [T]> + Send + Sync + 'static> {
    source: Arc<dyn RasterSource<Type = T, Container = C>>,
    holes: HashSet<(i16, i16)>,

    weak: HashMap<(i16, i16), Weak<Raster<T, C>>>,
    strong: LruCache<(i16, i16), Arc<Raster<T, C>>>,
    sender: Sender<((i16, i16), Option<Arc<Raster<T, C>>>)>,
    receiver: Receiver<((i16, i16), Option<Arc<Raster<T, C>>>)>,
}
impl<T: Into<f64> + Copy + 'static, C: Deref<Target = [T]> + Send + Sync + 'static> RasterCache<T, C> {
    pub fn new(source: Arc<dyn RasterSource<Type = T, Container = C>>, capacity: usize) -> Self {
        let (sender, receiver) = channel::unbounded();

        Self {
            source,
            holes: HashSet::new(),
            weak: HashMap::default(),
            strong: LruCache::new(capacity),
            sender,
            receiver,
        }
    }
    fn insert(&mut self, key: (i16, i16), raster: Option<Arc<Raster<T, C>>>) {
        match raster {
            Some(a) => {
                self.weak.insert(key, Arc::downgrade(&a));
                self.strong.insert(key, a);
            }
            None => {
                self.holes.insert(key);
            }
        }
    }
    fn try_get(&mut self, key: (i16, i16)) -> Option<Option<Arc<Raster<T, C>>>> {
        if self.holes.contains(&key) {
            return Some(None);
        }

        let mut found = None;
        while let Ok(t) = self.receiver.try_recv() {
            if t.0 == key {
                found = t.1.clone();
            }
            self.insert(t.0, t.1);
        }
        if found.is_some() {
            return Some(found);
        }

        match self.strong.get_mut(&key) {
            Some(e) => Some(Some(Arc::clone(e))),
            None => match self.weak.get(&key).and_then(|w| w.upgrade()) {
                Some(t) => {
                    self.strong.insert(key, t.clone());
                    Some(Some(Arc::clone(&t)))
                }
                None => {
                    self.weak.remove(&key);
                    None
                }
            },
        }
    }

    pub fn get(&mut self, latitude: i16, longitude: i16) -> BoxFuture<'static, Result<Option<Arc<Raster<T, C>>>, Error>> {
        let rs = self.source.raster_size();
        let key = (latitude - (latitude % rs + rs) % rs, longitude - (longitude % rs + rs) % rs);

        if let Some(raster) = self.try_get(key) {
            return futures::future::ready(Ok(raster)).boxed();
        }

        let source = Arc::clone(&self.source);
        let sender = self.sender.clone();
        async move {
            let raster = source.load(latitude, longitude).await?.map(Arc::new);
            sender.send((key, raster.clone()))?;
            Ok(raster)
        }.boxed()
    }

    #[allow(unused)]
    pub async fn interpolate(
        &mut self,
        latitude: f64,
        longitude: f64,
        band: usize,
    ) -> Result<Option<f64>, Error> {
        Ok(self
            .get(latitude.floor() as i16, longitude.floor() as i16).await?
            .and_then(|raster| raster.interpolate(latitude, longitude, band)))
    }

    #[allow(unused)]
    pub async fn nearest3(&mut self, latitude: f64, longitude: f64) -> Result<Option<[f64; 3]>, Error> {
        Ok(self
            .get(latitude.floor() as i16, longitude.floor() as i16).await?
            .and_then(|raster| raster.nearest3(latitude, longitude)))
    }
}

/// Currently assumes that values are taken at the *center* of cells.
pub(crate) struct GlobalRaster<T: Into<f64> + Copy, C: Index<usize, Output = T> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub values: C,
}
impl<T: Into<f64> + Copy, C: Index<usize, Output = T>> GlobalRaster<T, C> {
    /// Returns the approximate grid spacing in meters.
    #[allow(unused)]
    pub fn spacing(&self) -> f64 {
        let sx = 2.0 * PI * coordinates::PLANET_RADIUS / self.width as f64;
        let sy = PI * coordinates::PLANET_RADIUS / self.height as f64;
        sx.min(sy)
    }

    fn get(&self, x: i64, y: i64, band: usize) -> f64 {
        let y = y.max(0).min(self.height as i64 - 1) as usize;
        let x = (((x % self.width as i64) + self.width as i64) % self.width as i64) as usize;
        self.values[(x + y * self.width) * self.bands + band].into()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> f64 {
        assert!(latitude >= -90.0 && latitude <= 90.0);
        assert!(longitude >= -180.0 && latitude <= 180.0);

        let x = (longitude + 180.0) / 360.0 * self.width as f64 - 0.5;
        let y = (90.0 - latitude) / 180.0 * self.height as f64 - 0.5;

        let fx = x.floor() as i64;
        let fy = y.floor() as i64;

        let h00 = self.get(fx, fy, band);
        let h10 = self.get(fx + 1, fy, band);
        let h01 = self.get(fx, fy + 1, band);
        let h11 = self.get(fx + 1, fy + 1, band);
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        h0 + (h1 - h0) * (x - fx as f64)
    }
}
<commit_msg>Remove Raster<u8, Mmap><commit_after>use crate::coordinates;
use anyhow::Error;
use bit_vec::BitVec;
use crossbeam::channel::{self, Receiver, Sender};
use futures::future::BoxFuture;
use lru_cache::LruCache;
use serde::{Deserialize, Serialize};
use std::f64::consts::PI;
use std::ops::{Deref, Index};
use std::{
    collections::{HashMap, HashSet},
    sync::{Arc, Weak},
};
use futures::FutureExt;

pub trait Scalar: Copy + 'static {
    fn from_f64(_: f64) -> Self;
    fn to_f64(self) -> f64;
}

/// Wrapper around BitVec that converts values to f64's so that it can be uses as a backing for a
/// GlobalRaster.
pub struct BitContainer(pub BitVec<u32>);
impl Index<usize> for BitContainer {
    type Output = u8;
    fn index(&self, i: usize) -> &u8 {
        if self.0[i] {
            &255
        } else {
            &0
        }
    }
}

#[derive(Serialize, Deserialize)]
pub(crate) struct MMappedRasterHeader {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub cell_size: f64,

    pub latitude_llcorner: f64,
    pub longitude_llcorner: f64,
}

/// Currently assumes that values are taken at the lower left corner of each cell.
#[derive(Clone, Serialize, Deserialize)]
pub struct Raster<T: Into<f64> + Copy, C: Deref<Target = [T]> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub cell_size: f64,

    pub latitude_llcorner: f64,
    pub longitude_llcorner: f64,

    pub values: C,
}

impl<T: Into<f64> + Copy, C: Deref<Target = [T]>> Raster<T, C> {
    /// Returns the vertical spacing between cells, in meters.
    #[allow(unused)]
    pub fn vertical_spacing(&self) -> f64 {
        self.cell_size.to_radians() * coordinates::PLANET_RADIUS
    }

    /// Returns the horizontal spacing between cells, in meters.
    #[allow(unused)]
    pub fn horizontal_spacing(&self, y: usize) -> f64 {
        self.vertical_spacing()
            * (self.latitude_llcorner + self.cell_size * y as f64).to_radians().cos()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> Option<f64> {
        assert!(band < self.bands);

        let x = (longitude - self.longitude_llcorner) / self.cell_size;
        let y = (self.height - 1) as f64 - (latitude - self.latitude_llcorner) / self.cell_size;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;

        if x < 0.0 || fx >= self.width || y < 0.0 || fy >= self.height {
            return None;
        }

        // TODO: These should be interpolating across tiles...
        let fx_1 = (fx + 1).min(self.width - 1);
        let fy_1 = (fy + 1).min(self.height - 1);

        let h00 = self.values[(fx + fy * self.width) * self.bands + band].into();
        let h10 = self.values[(fx_1 + fy * self.width) * self.bands + band].into();
        let h01 = self.values[(fx + fy_1 * self.width) * self.bands + band].into();
        let h11 = self.values[(fx_1 + fy_1 * self.width) * self.bands + band].into();
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        Some(h0 + (h1 - h0) * (x - fx as f64))
    }

    pub fn nearest3(&self, latitude: f64, longitude: f64) -> Option<[f64; 3]> {
        assert!(self.bands >= 3);

        let x = (longitude - self.longitude_llcorner) / self.cell_size;
        let y = self.height as f64 - (latitude - self.latitude_llcorner) / self.cell_size;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;

        if x < 0.0 || fx >= self.width || y < 0.0 || fy >= self.height {
            return None;
        }

        let slice = &self.values[(fx + fy * self.width) * self.bands..][..3];
        Some([slice[0].into(), slice[1].into(), slice[2].into()])
    }
}

#[async_trait::async_trait]
pub(crate) trait RasterSource: Send + Sync {
    type Type: Into<f64> + Copy;
    type Container: Deref<Target = [Self::Type]>;
    async fn load(
        &self,
        latitude: i16,
        longitude: i16,
    ) -> Result<Option<Raster<Self::Type, Self::Container>>, Error>;
    fn bands(&self) -> usize;

    /// Degrees of latitude and longitude covered by each raster.
    fn raster_size(&self) -> i16 {
        1
    }
}

pub(crate) struct RasterCache<T: Into<f64> + Copy + 'static, C: Deref<Target = [T]> + Send + Sync + 'static> {
    source: Arc<dyn RasterSource<Type = T, Container = C>>,
    holes: HashSet<(i16, i16)>,

    weak: HashMap<(i16, i16), Weak<Raster<T, C>>>,
    strong: LruCache<(i16, i16), Arc<Raster<T, C>>>,
    sender: Sender<((i16, i16), Option<Arc<Raster<T, C>>>)>,
    receiver: Receiver<((i16, i16), Option<Arc<Raster<T, C>>>)>,
}
impl<T: Into<f64> + Copy + 'static, C: Deref<Target = [T]> + Send + Sync + 'static> RasterCache<T, C> {
    pub fn new(source: Arc<dyn RasterSource<Type = T, Container = C>>, capacity: usize) -> Self {
        let (sender, receiver) = channel::unbounded();

        Self {
            source,
            holes: HashSet::new(),
            weak: HashMap::default(),
            strong: LruCache::new(capacity),
            sender,
            receiver,
        }
    }
    fn insert(&mut self, key: (i16, i16), raster: Option<Arc<Raster<T, C>>>) {
        match raster {
            Some(a) => {
                self.weak.insert(key, Arc::downgrade(&a));
                self.strong.insert(key, a);
            }
            None => {
                self.holes.insert(key);
            }
        }
    }
    fn try_get(&mut self, key: (i16, i16)) -> Option<Option<Arc<Raster<T, C>>>> {
        if self.holes.contains(&key) {
            return Some(None);
        }

        let mut found = None;
        while let Ok(t) = self.receiver.try_recv() {
            if t.0 == key {
                found = t.1.clone();
            }
            self.insert(t.0, t.1);
        }
        if found.is_some() {
            return Some(found);
        }

        match self.strong.get_mut(&key) {
            Some(e) => Some(Some(Arc::clone(e))),
            None => match self.weak.get(&key).and_then(|w| w.upgrade()) {
                Some(t) => {
                    self.strong.insert(key, t.clone());
                    Some(Some(Arc::clone(&t)))
                }
                None => {
                    self.weak.remove(&key);
                    None
                }
            },
        }
    }

    pub fn get(&mut self, latitude: i16, longitude: i16) -> BoxFuture<'static, Result<Option<Arc<Raster<T, C>>>, Error>> {
        let rs = self.source.raster_size();
        let key = (latitude - (latitude % rs + rs) % rs, longitude - (longitude % rs + rs) % rs);

        if let Some(raster) = self.try_get(key) {
            return futures::future::ready(Ok(raster)).boxed();
        }

        let source = Arc::clone(&self.source);
        let sender = self.sender.clone();
        async move {
            let raster = source.load(latitude, longitude).await?.map(Arc::new);
            sender.send((key, raster.clone()))?;
            Ok(raster)
        }.boxed()
    }

    #[allow(unused)]
    pub async fn interpolate(
        &mut self,
        latitude: f64,
        longitude: f64,
        band: usize,
    ) -> Result<Option<f64>, Error> {
        Ok(self
            .get(latitude.floor() as i16, longitude.floor() as i16).await?
            .and_then(|raster| raster.interpolate(latitude, longitude, band)))
    }

    #[allow(unused)]
    pub async fn nearest3(&mut self, latitude: f64, longitude: f64) -> Result<Option<[f64; 3]>, Error> {
        Ok(self
            .get(latitude.floor() as i16, longitude.floor() as i16).await?
            .and_then(|raster| raster.nearest3(latitude, longitude)))
    }
}

/// Currently assumes that values are taken at the *center* of cells.
pub(crate) struct GlobalRaster<T: Into<f64> + Copy, C: Index<usize, Output = T> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub values: C,
}
impl<T: Into<f64> + Copy, C: Index<usize, Output = T>> GlobalRaster<T, C> {
    /// Returns the approximate grid spacing in meters.
    #[allow(unused)]
    pub fn spacing(&self) -> f64 {
        let sx = 2.0 * PI * coordinates::PLANET_RADIUS / self.width as f64;
        let sy = PI * coordinates::PLANET_RADIUS / self.height as f64;
        sx.min(sy)
    }

    fn get(&self, x: i64, y: i64, band: usize) -> f64 {
        let y = y.max(0).min(self.height as i64 - 1) as usize;
        let x = (((x % self.width as i64) + self.width as i64) % self.width as i64) as usize;
        self.values[(x + y * self.width) * self.bands + band].into()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> f64 {
        assert!(latitude >= -90.0 && latitude <= 90.0);
        assert!(longitude >= -180.0 && latitude <= 180.0);

        let x = (longitude + 180.0) / 360.0 * self.width as f64 - 0.5;
        let y = (90.0 - latitude) / 180.0 * self.height as f64 - 0.5;

        let fx = x.floor() as i64;
        let fy = y.floor() as i64;

        let h00 = self.get(fx, fy, band);
        let h10 = self.get(fx + 1, fy, band);
        let h01 = self.get(fx, fy + 1, band);
        let h11 = self.get(fx + 1, fy + 1, band);
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        h0 + (h1 - h0) * (x - fx as f64)
    }
}
<|endoftext|>


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

use result::Result;
use tag::Tag;
pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> {

    unimplemented!()
}
<commit_msg>Implement: add::add_tag()<commit_after>use toml::Value;

use libimagstore::store::Entry;

use result::Result;
use tag::Tag;
use error::{TagError, TagErrorKind};

pub fn add_tag(e: &mut Entry, t: &Tag) -> Result<()> {
    let tags = e.get_header().read("imag.tags");
    if tags.is_err() {
        let kind = TagErrorKind::HeaderReadError;
        return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
    }
    let tags = tags.unwrap();

    if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
        return Err(TagError::new(TagErrorKind::TagTypeError, None));
    }

    if tags.is_none() {
        return Ok(());
    }
    let tags = tags.unwrap();

    if !match tags { Value::Array(_) => true, _ => false } {
        return Err(TagError::new(TagErrorKind::TagTypeError, None));
    }

    match tags {
        Value::Array(tag_array) => {
            let mut new_tags = tag_array.clone();
            new_tags.push(Value::String(t.clone()));

            e.get_header_mut()
                .set("imag.tags", Value::Array(new_tags))
                .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e))))
                .map(|_| ())
        },

        _ => unreachable!(),
    }
}
<|endoftext|>