<commit_before>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

use std::io::{Write, StdoutLock};
use std::usize;

use search::{FileResult, Match};
use options::Colors;

/// A trait for printing search results to stdout.
pub trait DisplayMode {
    /// Print results from a single file.
    fn print_result(&mut self, res: FileResult);
}

/// The default mode, used when printing to tty stdout.
///
/// Uses grouping by file names by default and can use colors.  Can print context.
pub struct DefaultMode<'a> {
    colors: Colors,
    grouping: bool,
    heading: bool,
    is_first: bool,
    out: StdoutLock<'a>,
}

macro_rules! w {
    ($out:expr, $first:expr, $($rest:expr),*) => {
        let _ = $out.write($first);
        w!($out, $($rest),*);
    };
    ($out:expr, $first:expr) => {
        let _ = $out.write($first);
    }
}

impl<'a> DefaultMode<'a> {
    pub fn new(out: StdoutLock<'a>, colors: Colors, grouping: bool, heading: bool) -> DefaultMode<'a> {
        DefaultMode {
            colors: colors,
            grouping: grouping,
            heading: heading,
            is_first: true,
            out: out,
        }
    }

    fn print_separator(&mut self) {
        w!(self.out, &self.colors.punct, b"--", &self.colors.reset, b"\n");
    }

    /// Helper: print a line with matched spans highlighted.
    fn print_line_with_spans(&mut self, m: &Match) {
        if self.colors.empty {
            w!(self.out, &m.line, b"\n");
        } else {
            let mut pos = 0;
            for &(start, end) in &m.spans {
                if start > pos {
                    w!(self.out, &m.line[pos..start]);
                }
                w!(self.out, &self.colors.span, &m.line[start..end], &self.colors.reset);
                pos = end;
            }
            w!(self.out, &m.line[pos..], b"\n");
        }
    }

    /// Helper: print a match with custom callbacks for file header and match line.
    fn match_printer<FF, LF>(&mut self, res: &FileResult, file_func: FF, line_func: LF)
        where FF: Fn(&mut Self, &FileResult), LF: Fn(&mut Self, &FileResult, usize, &'static [u8])
    {
        // (maybe) print a heading for the whole file
        file_func(self, &res);
        // easy case without context lines
        if !res.has_context {
            for m in &res.matches {
                line_func(self, res, m.lineno, b":");
                self.print_line_with_spans(&m);
            }
            return;
        }
        // remember the last printed line: to be able to print "--" separators
        // between non-consecutive lines in context mode
        let mut last_printed_line = 0;
        for (im, m) in res.matches.iter().enumerate() {
            // print before-context
            for (i, line) in m.before.iter().enumerate() {
                let lno = m.lineno - m.before.len() + i;
                if last_printed_line > 0 && lno > last_printed_line + 1 {
                    self.print_separator();
                }
                // only print this line if we didn't print it before, e.g.
                // as a match line or after-context line
                if lno > last_printed_line {
                    line_func(self, res, lno, b"-");
                    w!(self.out, &line, b"\n");
                    last_printed_line = lno;
                }
            }
            if last_printed_line > 0 && m.lineno > last_printed_line + 1 {
                self.print_separator();
            }
            line_func(self, res, m.lineno, b":");
            self.print_line_with_spans(&m);
            // print after-context
            last_printed_line = m.lineno;
            // determine line number of next match, since we have to stop
            // printing context *before* that line
            let next_match_line = if im < res.matches.len() - 1 {
                res.matches[im + 1].lineno
            } else {
                usize::MAX
            };
            for (i, line) in m.after.iter().enumerate() {
                let lno = m.lineno + i + 1;
                // stop when we hit the next match
                if lno >= next_match_line {
                    break;
                }
                line_func(self, res, lno, b"-");
                w!(self.out, &line, b"\n");
                last_printed_line = lno;
            }
        }
    }
}

impl<'a> DisplayMode for DefaultMode<'a> {

    fn print_result(&mut self, res: FileResult) {
        // files with no matches never print anything
        if res.matches.is_empty() {
            return;
        }
        // grouping separator, but not on the first file
        if !self.is_first && self.grouping {
            w!(self.out, b"\n");
            if res.has_context && !self.heading {
                // in context mode, we have to print a "--" separator between files
                self.print_separator();
            }
        }
        if res.is_binary {
            // special message for binary files
            w!(self.out, b"Binary file ", res.fname.as_bytes(), b" matches.\n");
        } else if self.heading {
            // headings mode: print file name first, then omit it from match lines
            self.match_printer(&res, |slf, res| {
                w!(slf.out,
                   &slf.colors.path, res.fname.as_bytes(), &slf.colors.reset, b"\n");
            }, |slf, _, lineno, sep| {
                w!(slf.out,
                   &slf.colors.lineno, format!("{}", lineno).as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset);
            });
        } else {
            // no headings mode: print file name on every match line
            self.match_printer(&res, |_, _| { }, |slf, res, lineno, sep| {
                w!(slf.out,
                   &slf.colors.path, res.fname.as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset,
                   &slf.colors.lineno, format!("{}", lineno).as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset);
            });
        }
        self.is_first = false;
    }
}

/// The mode used for --ackmate mode.
///
/// No colors, one matched line per line, all spans indicated numerically.
pub struct AckMateMode<'a> {
    is_first: bool,
    out: StdoutLock<'a>,
}

impl<'a> AckMateMode<'a> {
    pub fn new(out: StdoutLock<'a>) -> AckMateMode<'a> {
        AckMateMode {
            is_first: true,
            out: out,
        }
    }
}

impl<'a> DisplayMode for AckMateMode<'a> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        if !self.is_first {
            w!(self.out, b"\n");
        }
        if res.is_binary {
            w!(self.out, b"Binary file ", res.fname.as_bytes(), b" matches.\n");
        } else {
            w!(self.out, b":", res.fname.as_bytes());
            for m in res.matches {
                let spans = m.spans.iter()
                                   .map(|&(s, e)| format!("{} {}", s, e - s))
                                   .collect::<Vec<_>>().join(",");
                w!(self.out,
                   &format!("{};{}:", m.lineno, spans).as_bytes(),
                   &m.line, b"\n");
            }
        }
        self.is_first = false;
    }
}

/// The mode used for --vimgrep mode.
///
/// No colors, one match per line (so lines with multiple matches are printed
/// multiple times).
pub struct VimGrepMode<'a> {
    out: StdoutLock<'a>,
}

impl<'a> VimGrepMode<'a> {
    pub fn new(out: StdoutLock<'a>) -> VimGrepMode<'a> {
        VimGrepMode {
            out: out,
        }
    }
}

impl<'a> DisplayMode for VimGrepMode<'a> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        if res.is_binary {
            println!("Binary file {} matches.", res.fname);
        } else {
            for m in res.matches {
                for s in &m.spans {
                    w!(self.out,
                       &format!("{}:{}:{}:", res.fname, m.lineno, s.0 + 1).as_bytes(),
                       &m.line, b"\n");
                }
            }
        }
    }
}

/// The mode used for --files-with-matches and --files-without-matches.
///
/// One file per line, no contents printed.
pub struct FilesOnlyMode<'a> {
    colors: Colors,
    need_match: bool,
    out: StdoutLock<'a>,
}

impl<'a> FilesOnlyMode<'a> {
    pub fn new(out: StdoutLock<'a>, colors: Colors, need_match: bool) -> FilesOnlyMode<'a> {
        FilesOnlyMode {
            colors: colors,
            need_match: need_match,
            out: out,
        }
    }
}

impl<'a> DisplayMode for FilesOnlyMode<'a> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() != self.need_match {
            w!(self.out, &self.colors.path, &res.fname.as_bytes(), &self.colors.reset, b"\n");
        }
    }
}

/// The mode used for --count mode.
///
/// One file per line, followed by match count (not matched line count).
pub struct CountMode<'a> {
    colors: Colors,
    out: StdoutLock<'a>,
}

impl<'a> CountMode<'a> {
    pub fn new(out: StdoutLock<'a>, colors: Colors) -> CountMode<'a> {
        CountMode {
            colors: colors,
            out: out,
        }
    }
}

impl<'a> DisplayMode for CountMode<'a> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        let count: usize = res.matches.iter().map(|m| m.spans.iter().count())
                                             .fold(0, |a, v| a + v);
        w!(self.out,
           &self.colors.path, &res.fname.as_bytes(), &self.colors.reset,
           &self.colors.punct, b":", &self.colors.reset,
           &self.colors.lineno, &format!("{}", count).as_bytes(), &self.colors.reset,
           b"\n");
    }
}
<commit_msg>Make displays generic over Write types<commit_after>// ---------------------------------------------------------------------------------------
// Ruthenium, an ack-like searcher, (c) 2015 Georg Brandl.
// Licensed under the MIT license.
// ---------------------------------------------------------------------------------------

use std::io::Write;
use std::usize;

use search::{FileResult, Match};
use options::Colors;

/// A trait for printing search results to stdout.
pub trait DisplayMode {
    /// Print results from a single file.
    fn print_result(&mut self, res: FileResult);
}

/// The default mode, used when printing to tty stdout.
///
/// Uses grouping by file names by default and can use colors.  Can print context.
pub struct DefaultMode<T: Write> {
    colors: Colors,
    grouping: bool,
    heading: bool,
    is_first: bool,
    out: T,
}

macro_rules! w {
    ($out:expr, $first:expr, $($rest:expr),*) => {
        let _ = $out.write($first);
        w!($out, $($rest),*);
    };
    ($out:expr, $first:expr) => {
        let _ = $out.write($first);
    }
}

impl<T: Write> DefaultMode<T> {
    pub fn new(out: T, colors: Colors, grouping: bool, heading: bool) -> DefaultMode<T> {
        DefaultMode {
            colors: colors,
            grouping: grouping,
            heading: heading,
            is_first: true,
            out: out,
        }
    }

    fn print_separator(&mut self) {
        w!(self.out, &self.colors.punct, b"--", &self.colors.reset, b"\n");
    }

    /// Helper: print a line with matched spans highlighted.
    fn print_line_with_spans(&mut self, m: &Match) {
        if self.colors.empty {
            w!(self.out, &m.line, b"\n");
        } else {
            let mut pos = 0;
            for &(start, end) in &m.spans {
                if start > pos {
                    w!(self.out, &m.line[pos..start]);
                }
                w!(self.out, &self.colors.span, &m.line[start..end], &self.colors.reset);
                pos = end;
            }
            w!(self.out, &m.line[pos..], b"\n");
        }
    }

    /// Helper: print a match with custom callbacks for file header and match line.
    fn match_printer<FF, LF>(&mut self, res: &FileResult, file_func: FF, line_func: LF)
        where FF: Fn(&mut Self, &FileResult), LF: Fn(&mut Self, &FileResult, usize, &'static [u8])
    {
        // (maybe) print a heading for the whole file
        file_func(self, &res);
        // easy case without context lines
        if !res.has_context {
            for m in &res.matches {
                line_func(self, res, m.lineno, b":");
                self.print_line_with_spans(&m);
            }
            return;
        }
        // remember the last printed line: to be able to print "--" separators
        // between non-consecutive lines in context mode
        let mut last_printed_line = 0;
        for (im, m) in res.matches.iter().enumerate() {
            // print before-context
            for (i, line) in m.before.iter().enumerate() {
                let lno = m.lineno - m.before.len() + i;
                if last_printed_line > 0 && lno > last_printed_line + 1 {
                    self.print_separator();
                }
                // only print this line if we didn't print it before, e.g.
                // as a match line or after-context line
                if lno > last_printed_line {
                    line_func(self, res, lno, b"-");
                    w!(self.out, &line, b"\n");
                    last_printed_line = lno;
                }
            }
            if last_printed_line > 0 && m.lineno > last_printed_line + 1 {
                self.print_separator();
            }
            line_func(self, res, m.lineno, b":");
            self.print_line_with_spans(&m);
            // print after-context
            last_printed_line = m.lineno;
            // determine line number of next match, since we have to stop
            // printing context *before* that line
            let next_match_line = if im < res.matches.len() - 1 {
                res.matches[im + 1].lineno
            } else {
                usize::MAX
            };
            for (i, line) in m.after.iter().enumerate() {
                let lno = m.lineno + i + 1;
                // stop when we hit the next match
                if lno >= next_match_line {
                    break;
                }
                line_func(self, res, lno, b"-");
                w!(self.out, &line, b"\n");
                last_printed_line = lno;
            }
        }
    }
}

impl<T: Write> DisplayMode for DefaultMode<T> {

    fn print_result(&mut self, res: FileResult) {
        // files with no matches never print anything
        if res.matches.is_empty() {
            return;
        }
        // grouping separator, but not on the first file
        if !self.is_first && self.grouping {
            w!(self.out, b"\n");
            if res.has_context && !self.heading {
                // in context mode, we have to print a "--" separator between files
                self.print_separator();
            }
        }
        if res.is_binary {
            // special message for binary files
            w!(self.out, b"Binary file ", res.fname.as_bytes(), b" matches.\n");
        } else if self.heading {
            // headings mode: print file name first, then omit it from match lines
            self.match_printer(&res, |slf, res| {
                w!(slf.out,
                   &slf.colors.path, res.fname.as_bytes(), &slf.colors.reset, b"\n");
            }, |slf, _, lineno, sep| {
                w!(slf.out,
                   &slf.colors.lineno, format!("{}", lineno).as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset);
            });
        } else {
            // no headings mode: print file name on every match line
            self.match_printer(&res, |_, _| { }, |slf, res, lineno, sep| {
                w!(slf.out,
                   &slf.colors.path, res.fname.as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset,
                   &slf.colors.lineno, format!("{}", lineno).as_bytes(), &slf.colors.reset,
                   &slf.colors.punct, sep, &slf.colors.reset);
            });
        }
        self.is_first = false;
    }
}

/// The mode used for --ackmate mode.
///
/// No colors, one matched line per line, all spans indicated numerically.
pub struct AckMateMode<T: Write> {
    is_first: bool,
    out: T,
}

impl<T: Write> AckMateMode<T> {
    pub fn new(out: T) -> AckMateMode<T> {
        AckMateMode {
            is_first: true,
            out: out,
        }
    }
}

impl<T: Write> DisplayMode for AckMateMode<T> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        if !self.is_first {
            w!(self.out, b"\n");
        }
        if res.is_binary {
            w!(self.out, b"Binary file ", res.fname.as_bytes(), b" matches.\n");
        } else {
            w!(self.out, b":", res.fname.as_bytes());
            for m in res.matches {
                let spans = m.spans.iter()
                                   .map(|&(s, e)| format!("{} {}", s, e - s))
                                   .collect::<Vec<_>>().join(",");
                w!(self.out,
                   &format!("{};{}:", m.lineno, spans).as_bytes(),
                   &m.line, b"\n");
            }
        }
        self.is_first = false;
    }
}

/// The mode used for --vimgrep mode.
///
/// No colors, one match per line (so lines with multiple matches are printed
/// multiple times).
pub struct VimGrepMode<T: Write> {
    out: T,
}

impl<T: Write> VimGrepMode<T> {
    pub fn new(out: T) -> VimGrepMode<T> {
        VimGrepMode {
            out: out,
        }
    }
}

impl<T: Write> DisplayMode for VimGrepMode<T> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        if res.is_binary {
            println!("Binary file {} matches.", res.fname);
        } else {
            for m in res.matches {
                for s in &m.spans {
                    w!(self.out,
                       &format!("{}:{}:{}:", res.fname, m.lineno, s.0 + 1).as_bytes(),
                       &m.line, b"\n");
                }
            }
        }
    }
}

/// The mode used for --files-with-matches and --files-without-matches.
///
/// One file per line, no contents printed.
pub struct FilesOnlyMode<T: Write> {
    colors: Colors,
    need_match: bool,
    out: T,
}

impl<T: Write> FilesOnlyMode<T> {
    pub fn new(out: T, colors: Colors, need_match: bool) -> FilesOnlyMode<T> {
        FilesOnlyMode {
            colors: colors,
            need_match: need_match,
            out: out,
        }
    }
}

impl<T: Write> DisplayMode for FilesOnlyMode<T> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() != self.need_match {
            w!(self.out, &self.colors.path, &res.fname.as_bytes(), &self.colors.reset, b"\n");
        }
    }
}

/// The mode used for --count mode.
///
/// One file per line, followed by match count (not matched line count).
pub struct CountMode<T: Write> {
    colors: Colors,
    out: T,
}

impl<T: Write> CountMode<T> {
    pub fn new(out: T, colors: Colors) -> CountMode<T> {
        CountMode {
            colors: colors,
            out: out,
        }
    }
}

impl<T: Write> DisplayMode for CountMode<T> {
    fn print_result(&mut self, res: FileResult) {
        if res.matches.is_empty() {
            return;
        }
        let count: usize = res.matches.iter().map(|m| m.spans.iter().count())
                                             .fold(0, |a, v| a + v);
        w!(self.out,
           &self.colors.path, &res.fname.as_bytes(), &self.colors.reset,
           &self.colors.punct, b":", &self.colors.reset,
           &self.colors.lineno, &format!("{}", count).as_bytes(), &self.colors.reset,
           b"\n");
    }
}
<|endoftext|>


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

// this file defines CGFloat, as well as stubbed data types.

use libc;
use base::{CGError, boolean_t};
use geometry::{CGRect, CGPoint, CGSize};

pub type CGDirectDisplayID = libc::uint32_t;

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

}
<commit_msg>update src/display.rs<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// this file defines CGFloat, as well as stubbed data types.
extern crate core_foundation;

pub use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub const kCGWindowListOptionAll:          libc::uint32_t        = 0;
pub const kCGWindowListOptionOnScreenOnly: libc::uint32_t        = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: libc::uint32_t = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: libc::uint32_t = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  libc::uint32_t    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: libc::uint32_t    = 1 << 4;

pub enum CGWindowListOption {
    kCGWindowListOptionAll,
    kCGWindowListOptionOnScreenOnly,
    kCGWindowListOptionOnScreenAboveWindow,
    kCGWindowListOptionOnScreenBelowWindow,
    kCGWindowListOptionIncludingWindow,
    kCGWindowListExcludeDesktopElements,
}

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef };
pub use core_foundation::array::{ CFArray, CFArrayRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Supports writing a trace file created during each layout scope
//! that can be viewed by an external tool to make layout debugging easier.

// for thread_local
#![allow(unsafe_code)]

use flow;
use flow_ref::FlowRef;
use serde_json::{to_string, to_value, Value};
use std::borrow::ToOwned;
use std::cell::RefCell;
use std::fs::File;
use std::io::Write;
#[cfg(debug_assertions)]
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));

#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Scope;

#[macro_export]
macro_rules! layout_debug_scope(
    ($($arg:tt)*) => (
        if cfg!(debug_assertions) {
            layout_debug::Scope::new(format!($($arg)*))
        } else {
            layout_debug::Scope
        }
    )
);

#[derive(Serialize)]
struct ScopeData {
    name: String,
    pre: Value,
    post: Value,
    children: Vec<Box<ScopeData>>,
}

impl ScopeData {
    fn new(name: String, pre: Value) -> ScopeData {
        ScopeData {
            name: name,
            pre: pre,
            post: Value::Null,
            children: vec!(),
        }
    }
}

struct State {
    flow_root: FlowRef,
    scope_stack: Vec<Box<ScopeData>>,
}

/// A layout debugging scope. The entire state of the flow tree
/// will be output at the beginning and end of this scope.
impl Scope {
    pub fn new(name: String) -> Scope {
        STATE_KEY.with(|ref r| {
            match *r.borrow_mut() {
                Some(ref mut state) => {
                    let flow_trace = to_value(&flow::base(&*state.flow_root));
                    let data = box ScopeData::new(name.clone(), flow_trace);
                    state.scope_stack.push(data);
                }
                None => {}
            }
        });
        Scope
    }
}

#[cfg(debug_assertions)]
impl Drop for Scope {
    fn drop(&mut self) {
        STATE_KEY.with(|ref r| {
            match *r.borrow_mut() {
                 Some(ref mut state) => {
                    let mut current_scope = state.scope_stack.pop().unwrap();
                    current_scope.post = to_value(&flow::base(&*state.flow_root));
                    let previous_scope = state.scope_stack.last_mut().unwrap();
                    previous_scope.children.push(current_scope);
                }
                None => {}
            }
        });
    }
}

/// Generate a unique ID. This is used for items such as Fragment
/// which are often reallocated but represent essentially the
/// same data.
#[cfg(debug_assertions)]
pub fn generate_unique_debug_id() -> u16 {
    DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16
}

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(flow_root: FlowRef) {
    assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));

    STATE_KEY.with(|ref r| {
        let flow_trace = to_value(&flow::base(&*flow_root));
        let state = State {
            scope_stack: vec![box ScopeData::new("root".to_owned(), flow_trace)],
            flow_root: flow_root.clone(),
        };
        *r.borrow_mut() = Some(state);
    });
}

/// End the debug layout trace. This will write the layout
/// trace to disk in the current directory. The output
/// file can then be viewed with an external tool.
pub fn end_trace(generation: u32) {
    let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap());
    assert!(thread_state.scope_stack.len() == 1);
    let mut root_scope = thread_state.scope_stack.pop().unwrap();
    root_scope.post = to_value(&flow::base(&*thread_state.flow_root));

    let result = to_string(&root_scope).unwrap();
    let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap();
    file.write_all(result.as_bytes()).unwrap();
}
<commit_msg>layout: Simplify layout debugging scope.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Supports writing a trace file created during each layout scope
//! that can be viewed by an external tool to make layout debugging easier.

// for thread_local
#![allow(unsafe_code)]

use flow;
use flow_ref::FlowRef;
use serde_json::{to_string, to_value, Value};
use std::borrow::ToOwned;
use std::cell::RefCell;
use std::fs::File;
use std::io::Write;
#[cfg(debug_assertions)]
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));

#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Scope;

#[macro_export]
macro_rules! layout_debug_scope(
    ($($arg:tt)*) => (
        if cfg!(debug_assertions) {
            layout_debug::Scope::new(format!($($arg)*))
        } else {
            layout_debug::Scope
        }
    )
);

#[derive(Serialize)]
struct ScopeData {
    name: String,
    pre: Value,
    post: Value,
    children: Vec<Box<ScopeData>>,
}

impl ScopeData {
    fn new(name: String, pre: Value) -> ScopeData {
        ScopeData {
            name: name,
            pre: pre,
            post: Value::Null,
            children: vec!(),
        }
    }
}

struct State {
    flow_root: FlowRef,
    scope_stack: Vec<Box<ScopeData>>,
}

/// A layout debugging scope. The entire state of the flow tree
/// will be output at the beginning and end of this scope.
impl Scope {
    pub fn new(name: String) -> Scope {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let flow_trace = to_value(&flow::base(&*state.flow_root));
                let data = box ScopeData::new(name.clone(), flow_trace);
                state.scope_stack.push(data);
            }
        });
        Scope
    }
}

#[cfg(debug_assertions)]
impl Drop for Scope {
    fn drop(&mut self) {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let mut current_scope = state.scope_stack.pop().unwrap();
                current_scope.post = to_value(&flow::base(&*state.flow_root));
                let previous_scope = state.scope_stack.last_mut().unwrap();
                previous_scope.children.push(current_scope);
            }
        });
    }
}

/// Generate a unique ID. This is used for items such as Fragment
/// which are often reallocated but represent essentially the
/// same data.
#[cfg(debug_assertions)]
pub fn generate_unique_debug_id() -> u16 {
    DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16
}

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(flow_root: FlowRef) {
    assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));

    STATE_KEY.with(|ref r| {
        let flow_trace = to_value(&flow::base(&*flow_root));
        let state = State {
            scope_stack: vec![box ScopeData::new("root".to_owned(), flow_trace)],
            flow_root: flow_root.clone(),
        };
        *r.borrow_mut() = Some(state);
    });
}

/// End the debug layout trace. This will write the layout
/// trace to disk in the current directory. The output
/// file can then be viewed with an external tool.
pub fn end_trace(generation: u32) {
    let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap());
    assert!(thread_state.scope_stack.len() == 1);
    let mut root_scope = thread_state.scope_stack.pop().unwrap();
    root_scope.post = to_value(&flow::base(&*thread_state.flow_root));

    let result = to_string(&root_scope).unwrap();
    let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap();
    file.write_all(result.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::ext::base::ExtCtxt;
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::ast::{Item, MetaItem, Expr};
use syntax::ast;
use syntax::attr;
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty};
use syntax::parse::token::InternedString;

pub fn expand_dom_struct(_: &mut ExtCtxt, _: Span, _: &MetaItem, item: P<Item>) -> P<Item> {
    let mut item2 = (*item).clone();
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("must_root"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("privatize"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("jstraceable"))));
    P(item2)
}

/// Provides the hook to expand `#[jstraceable]` into an implementation of `JSTraceable`
///
/// The expansion basically calls `trace()` on all of the fields of the struct/enum, erroring if they do not implement the method.
pub fn expand_jstraceable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Item, push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: ty::Path::new(vec!("dom","bindings","trace","JSTraceable")),
        additional_bounds: Vec::new(),
        generics: ty::LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "trace",
                generics: ty::LifetimeBounds::empty(),
                explicit_self: ty::borrowed_explicit_self(),
                args: vec!(ty::Ptr(box ty::Literal(ty::Path::new(vec!("js","jsapi","JSTracer"))), ty::Raw(ast::MutMutable))),
                ret_ty: ty::nil_ty(),
                attributes: vec!(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("inline")))),
                combine_substructure: combine_substructure(|a, b, c| {
                    jstraceable_substructure(a, b, c)
                })
            }
        )
    };
    trait_def.expand(cx, mitem, item, push)
}

// Mostly copied from syntax::ext::deriving::hash
/// Defines how the implementation for `trace()` is to be generated
fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    let state_expr = match substr.nonself_args {
        [ref state_expr] => state_expr,
        _ => cx.span_bug(trait_span, "incorrect number of arguments in `jstraceable`")
    };
    let trace_ident = substr.method_ident;
    let call_trace = |span, thing_expr| {
        let expr = cx.expr_method_call(span, thing_expr, trace_ident, vec!(state_expr.clone()));
        cx.stmt_expr(expr)
    };
    let mut stmts = Vec::new();

    let fields = match *substr.fields {
        Struct(ref fs) | EnumMatching(_, _, ref fs) => fs,
        _ => cx.span_bug(trait_span, "impossible substructure in `jstraceable`")
    };

    for &FieldInfo { ref self_, span, .. } in fields.iter() {
        stmts.push(call_trace(span, self_.clone()));
    }

    cx.expr_block(cx.block(trait_span, stmts, None))
}
<commit_msg>Use inline(always) for trace()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::ext::base::ExtCtxt;
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::ast::{Item, MetaItem, Expr};
use syntax::ast;
use syntax::attr;
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{combine_substructure, EnumMatching, FieldInfo, MethodDef, Struct, Substructure, TraitDef, ty};
use syntax::parse::token::InternedString;

pub fn expand_dom_struct(_: &mut ExtCtxt, _: Span, _: &MetaItem, item: P<Item>) -> P<Item> {
    let mut item2 = (*item).clone();
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("must_root"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("privatize"))));
    item2.attrs.push(attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(InternedString::new("jstraceable"))));
    P(item2)
}

/// Provides the hook to expand `#[jstraceable]` into an implementation of `JSTraceable`
///
/// The expansion basically calls `trace()` on all of the fields of the struct/enum, erroring if they do not implement the method.
pub fn expand_jstraceable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Item, push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: ty::Path::new(vec!("dom","bindings","trace","JSTraceable")),
        additional_bounds: Vec::new(),
        generics: ty::LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "trace",
                generics: ty::LifetimeBounds::empty(),
                explicit_self: ty::borrowed_explicit_self(),
                args: vec!(ty::Ptr(box ty::Literal(ty::Path::new(vec!("js","jsapi","JSTracer"))), ty::Raw(ast::MutMutable))),
                ret_ty: ty::nil_ty(),
                attributes: vec!(attr::mk_attr_outer(attr::mk_attr_id(),
                                                     attr::mk_name_value_item_str(InternedString::new("inline"),
                                                                                InternedString::new("always")))),
                combine_substructure: combine_substructure(|a, b, c| {
                    jstraceable_substructure(a, b, c)
                })
            }
        )
    };
    trait_def.expand(cx, mitem, item, push)
}

// Mostly copied from syntax::ext::deriving::hash
/// Defines how the implementation for `trace()` is to be generated
fn jstraceable_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    let state_expr = match substr.nonself_args {
        [ref state_expr] => state_expr,
        _ => cx.span_bug(trait_span, "incorrect number of arguments in `jstraceable`")
    };
    let trace_ident = substr.method_ident;
    let call_trace = |span, thing_expr| {
        let expr = cx.expr_method_call(span, thing_expr, trace_ident, vec!(state_expr.clone()));
        cx.stmt_expr(expr)
    };
    let mut stmts = Vec::new();

    let fields = match *substr.fields {
        Struct(ref fs) | EnumMatching(_, _, ref fs) => fs,
        _ => cx.span_bug(trait_span, "impossible substructure in `jstraceable`")
    };

    for &FieldInfo { ref self_, span, .. } in fields.iter() {
        stmts.push(call_trace(span, self_.clone()));
    }

    cx.expr_block(cx.block(trait_span, stmts, None))
}
<|endoftext|>


<commit_before>extern crate mdbook;
extern crate tempdir;

use std::path::PathBuf;
use mdbook::MDBook;
use tempdir::TempDir;

/// Run `mdbook init` in an empty directory and make sure the default files
/// are created.
#[test]
fn base_mdbook_init_should_create_default_content() {
    let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"];

    let temp = TempDir::new("mdbook").unwrap();
    for file in &created_files {
        assert!(!temp.path().join(file).exists());
    }

    let mut md = MDBook::new(temp.path());
    md.init().unwrap();

    for file in &created_files {
        let target = temp.path().join(file);
        println!("{}", target.display());
        assert!(target.exists(), "{} doesn't exist", file);
    }
}

/// Set some custom arguments for where to place the source and destination
/// files, then call `mdbook init`.
#[test]
fn run_mdbook_init_with_custom_book_and_src_locations() {
    let created_files = vec!["out", "in", "in/SUMMARY.md", "in/chapter_1.md"];

    let temp = TempDir::new("mdbook").unwrap();
    for file in &created_files {
        assert!(!temp.path().join(file).exists(),
                "{} shouldn't exist yet!",
                file);
    }

    let mut md = MDBook::new(temp.path());
    md.config.book.src = PathBuf::from("in");
    md.config.build.build_dir = PathBuf::from("out");

    md.init().unwrap();

    for file in &created_files {
        let target = temp.path().join(file);
        assert!(target.exists(), "{} should have been created by `mdbook init`", file);
    }
}
<commit_msg>Added a test to make sure book.toml isn't required<commit_after>extern crate mdbook;
extern crate tempdir;

use std::path::PathBuf;
use mdbook::MDBook;
use tempdir::TempDir;

/// Run `mdbook init` in an empty directory and make sure the default files
/// are created.
#[test]
fn base_mdbook_init_should_create_default_content() {
    let created_files = vec!["book", "src", "src/SUMMARY.md", "src/chapter_1.md"];

    let temp = TempDir::new("mdbook").unwrap();
    for file in &created_files {
        assert!(!temp.path().join(file).exists());
    }

    let mut md = MDBook::new(temp.path());
    md.init().unwrap();

    for file in &created_files {
        let target = temp.path().join(file);
        println!("{}", target.display());
        assert!(target.exists(), "{} doesn't exist", file);
    }
}

/// Set some custom arguments for where to place the source and destination
/// files, then call `mdbook init`.
#[test]
fn run_mdbook_init_with_custom_book_and_src_locations() {
    let created_files = vec!["out", "in", "in/SUMMARY.md", "in/chapter_1.md"];

    let temp = TempDir::new("mdbook").unwrap();
    for file in &created_files {
        assert!(!temp.path().join(file).exists(),
                "{} shouldn't exist yet!",
                file);
    }

    let mut md = MDBook::new(temp.path());
    md.config.book.src = PathBuf::from("in");
    md.config.build.build_dir = PathBuf::from("out");

    md.init().unwrap();

    for file in &created_files {
        let target = temp.path().join(file);
        assert!(target.exists(), "{} should have been created by `mdbook init`", file);
    }
}

#[test]
fn book_toml_isnt_required() {
    let temp = TempDir::new("mdbook").unwrap();
    let mut md = MDBook::new(temp.path());
    md.init().unwrap();

    assert!(!temp.path().join("book.toml").exists());

    md.read_config().unwrap().build().unwrap();
}
<|endoftext|>


<commit_before>extern crate protein_translation as proteins;

#[test]
fn test_methionine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("ATG"), Ok("methionine"));
}

#[test]
#[ignore]
fn test_cysteine_tgt() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("TGT"), Ok("cysteine"));
}

#[test]
#[ignore]
fn test_stop() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("TAA"), Ok("stop codon"));
}

#[test]
#[ignore]
fn test_valine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("GTT"), Ok("valine"));
}

#[test]
#[ignore]
fn test_isoleucine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("ATT"), Ok("isoleucine"));
}

#[test]
#[ignore]
fn test_arginine_name() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("CGA"), Ok("arginine"));
    assert_eq!(info.name_for("AGA"), Ok("arginine"));
    assert_eq!(info.name_for("AGG"), Ok("arginine"));
}

#[test]
#[ignore]
fn empty_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("").is_err());
}

#[test]
#[ignore]
fn x_is_not_shorthand_so_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("VWX").is_err());
}

#[test]
#[ignore]
fn too_short_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("AT").is_err());
}

#[test]
#[ignore]
fn too_long_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("ATTA").is_err());
}

#[test]
#[ignore]
fn test_translates_rna_strand_into_correct_protein() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("AUGUUUUGG").unwrap(),
               vec!["methionine", "phenylalanine", "tryptophan"]);
}

#[test]
#[ignore]
fn test_stops_translation_if_stop_codon_present() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("AUGUUUUAA").unwrap(),
               vec!["methionine", "phenylalanine"]);
}

#[test]
#[ignore]
fn test_stops_translation_of_longer_strand() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("UGGUGUUAUUAAUGGUUU").unwrap(),
               vec!["tryptophan", "cysteine", "tyrosine"]);
}

#[test]
#[ignore]
fn test_invalid_codons() {
    let info = proteins::parse(make_pairs());
    assert!(info.of_rna("CARROT").is_err());
}

// The input data constructor. Returns a list of codon, name pairs.
fn make_pairs() -> Vec<(&'static str, &'static str)> {
    let grouped = vec![
        ("isoleucine", vec!["ATT", "ATC", "ATA"]),
        ("leucine", vec!["CTT", "CTC", "CTA", "CTG", "TTA", "TTG"]),
        ("valine", vec!["GTT", "GTC", "GTA", "GTG"]),
        ("phenylalanine", vec!["UUU", "TTT", "TTC"]),
        ("methionine", vec!["AUG", "ATG"]),
        ("cysteine", vec!["UGU", "TGT", "TGC"]),
        ("alanine", vec!["GCT", "GCC", "GCA", "GCG"]),
        ("glycine", vec!["GGT", "GGC", "GGA", "GGG"]),
        ("proline", vec!["CCT", "CCC", "CCA", "CCG"]),
        ("threonine", vec!["ACT", "ACC", "ACA", "ACG"]),
        ("serine", vec!["TCT", "TCC", "TCA", "TCG", "AGT", "AGC"]),
        ("tyrosine", vec!["UAU", "TAT", "TAC"]),
        ("tryptophan", vec!["UGG", "TGG"]),
        ("glutamine", vec!["CAA", "CAG"]),
        ("asparagine", vec!["AAT", "AAC"]),
        ("histidine", vec!["CAT", "CAC"]),
        ("glutamic acid", vec!["GAA", "GAG"]),
        ("aspartic acid", vec!["GAT", "GAC"]),
        ("lysine", vec!["AAA", "AAG"]),
        ("arginine", vec!["CGT", "CGC", "CGA", "CGG", "AGA", "AGG"]),
        ("stop codon", vec!["UAA", "TAA", "TAG", "TGA"])];
    let mut pairs = Vec::<(&'static str, &'static str)>::new();
    for (name, codons) in grouped.into_iter() {
        for codon in codons {
            pairs.push((codon, name));
        }
    };
    pairs.sort_by(|&(_, a), &(_, b)| a.cmp(b));
    return pairs
}
<commit_msg>Replace DNA codons with RNA codons<commit_after>extern crate protein_translation as proteins;

#[test]
fn test_methionine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("AUG"), Ok("methionine"));
}

#[test]
#[ignore]
fn test_cysteine_tgt() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("UGU"), Ok("cysteine"));
}

#[test]
#[ignore]
fn test_stop() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("UAA"), Ok("stop codon"));
}

#[test]
#[ignore]
fn test_valine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("GUU"), Ok("valine"));
}

#[test]
#[ignore]
fn test_isoleucine() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("AUU"), Ok("isoleucine"));
}

#[test]
#[ignore]
fn test_arginine_name() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.name_for("CGA"), Ok("arginine"));
    assert_eq!(info.name_for("AGA"), Ok("arginine"));
    assert_eq!(info.name_for("AGG"), Ok("arginine"));
}

#[test]
#[ignore]
fn empty_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("").is_err());
}

#[test]
#[ignore]
fn x_is_not_shorthand_so_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("VWX").is_err());
}

#[test]
#[ignore]
fn too_short_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("AU").is_err());
}

#[test]
#[ignore]
fn too_long_is_invalid() {
    let info = proteins::parse(make_pairs());
    assert!(info.name_for("ATTA").is_err());
}

#[test]
#[ignore]
fn test_translates_rna_strand_into_correct_protein() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("AUGUUUUGG").unwrap(),
               vec!["methionine", "phenylalanine", "tryptophan"]);
}

#[test]
#[ignore]
fn test_stops_translation_if_stop_codon_present() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("AUGUUUUAA").unwrap(),
               vec!["methionine", "phenylalanine"]);
}

#[test]
#[ignore]
fn test_stops_translation_of_longer_strand() {
    let info = proteins::parse(make_pairs());
    assert_eq!(info.of_rna("UGGUGUUAUUAAUGGUUU").unwrap(),
               vec!["tryptophan", "cysteine", "tyrosine"]);
}

#[test]
#[ignore]
fn test_invalid_codons() {
    let info = proteins::parse(make_pairs());
    assert!(info.of_rna("CARROT").is_err());
}

// The input data constructor. Returns a list of codon, name pairs.
fn make_pairs() -> Vec<(&'static str, &'static str)> {
    let grouped = vec![
        ("isoleucine", vec!["AUU", "AUC", "AUA"]),
        ("valine", vec!["GUU", "GUC", "GUA", "GUG"]),
        ("phenylalanine", vec!["UUU", "UUC"]),
        ("methionine", vec!["AUG"]),
        ("cysteine", vec!["UGU", "UGC"]),
        ("alanine", vec!["GCU", "GCC", "GCA", "GCG"]),
        ("glycine", vec!["GGU", "GGC", "GGA", "GGG"]),
        ("proline", vec!["CCU", "CCC", "CCA", "CCG"]),
        ("threonine", vec!["ACU", "ACC", "ACA", "ACG"]),
        ("serine", vec!["AGU", "AGC"]),
        ("tyrosine", vec!["UAU", "UAC"]),
        ("tryptophan", vec!["UGG"]),
        ("glutamine", vec!["CAA", "CAG"]),
        ("asparagine", vec!["AAU", "AAC"]),
        ("histidine", vec!["CAU", "CAC"]),
        ("glutamic acid", vec!["GAA", "GAG"]),
        ("aspartic acid", vec!["GAU", "GAC"]),
        ("lysine", vec!["AAA", "AAG"]),
        ("arginine", vec!["CGU", "CGC", "CGA", "CGG", "AGA", "AGG"]),
        ("stop codon", vec!["UAA", "UAG", "UGA"])];
    let mut pairs = Vec::<(&'static str, &'static str)>::new();
    for (name, codons) in grouped.into_iter() {
        for codon in codons {
            pairs.push((codon, name));
        }
    };
    pairs.sort_by(|&(_, a), &(_, b)| a.cmp(b));
    return pairs
}
<|endoftext|>


<commit_before>#[feature(globs)];
#[feature(macro_rules)];

#[link_args="-lwxc"];

extern mod native;
extern mod wx;

use std::libc::c_void;

use wx::_unsafe::*;
use wx::defs::*;
use wx::base::*;
use wx::core::*;

mod macros;

wxApp!(wx_main)

extern "C"
fn wx_main() {
    let frame = MyFrame::new();
    frame.asFrame().show();
    frame.asFrame().raise();
}

struct MyFrame { base: WxFrame }
impl MyFrame {
    fn new() -> MyFrame {
        let frame = WxFrame::new(&WxWindow::null(), wxID_ANY, "Hello, wxRust!", -1, -1, -1, -1, wxDEFAULT_FRAME_STYLE);
        let menubar = MyMenuBar::new();
        frame.setMenuBar(&menubar.asMenuBar());

        MyButton::new(&frame);

        MyFrame { base: frame }
    }
    fn asFrame(&self) -> WxFrame {
        return self.base;
    }
}

struct MyMenuBar { base: WxMenuBar }
impl MyMenuBar {
    fn new() -> MyMenuBar {
        let menubar = WxMenuBar::new(0);

        let fileMenu = WxMenu::new("", 0);
        let fileNew = WxMenuItem::newEx(wxID_ANY, "New", "Create a new file.", 0, &WxMenu::null());
        fileMenu.appendItem(&fileNew);

        menubar.append(&fileMenu, "File");
        MyMenuBar { base: menubar }
    }
    fn asMenuBar(&self) -> WxMenuBar {
        return self.base;
    }
}

extern "C"
fn MyButton_clicked(fun: *mut c_void, data: *mut c_void, evt: *mut c_void) {
    if evt == 0 as *mut c_void {
        // Comes here when the target widget is destroyed.
        return;
    }

    println!("hello!");
    let parent = WxWindow::from(data);
    let msgDlg = WxMessageDialog::new(&parent, "Pushed!!", "The Button", wxOK);
    msgDlg.showModal();
}

struct MyButton(WxButton);
impl MyButton {
    fn new<T: TWxWindow>(parent: &T) -> MyButton {
        let button = WxButton::new(parent, wxID_ANY, "Push me!", 10, 10, 50, 30, 0);
        let closure = WxClosure::new(MyButton_clicked as *mut c_void, parent.ptr());
        unsafe {
            button.connect(wxID_ANY, wxID_ANY, expEVT_COMMAND_BUTTON_CLICKED(), closure.ptr());
        }

        MyButton(button)
    }
}
<commit_msg>Simplify sample code.<commit_after>#[feature(globs)];
#[feature(macro_rules)];

#[link_args="-lwxc"];

extern mod native;
extern mod wx;

use std::libc::c_void;

use wx::_unsafe::*;
use wx::defs::*;
use wx::base::*;
use wx::core::*;

mod macros;

wxApp!(wx_main)

extern "C"
fn wx_main() {
    let frame = make_frame();
    frame.show();
    frame.raise();
}

fn make_frame() -> WxFrame {
    let frame = WxFrame::new(&WxWindow::null(), wxID_ANY, "Hello, wxRust!", -1, -1, -1, -1, wxDEFAULT_FRAME_STYLE);
    let menubar = make_menubar();
    frame.setMenuBar(&menubar);

    make_button(&frame);

    frame
}

fn make_menubar() -> WxMenuBar {
    let menubar = WxMenuBar::new(0);

    let fileMenu = WxMenu::new("", 0);
    let fileNew = WxMenuItem::newEx(wxID_ANY, "New", "Create a new file.", 0, &WxMenu::null());
    fileMenu.appendItem(&fileNew);

    menubar.append(&fileMenu, "File");
    menubar
}

extern "C"
fn MyButton_clicked(fun: *mut c_void, data: *mut c_void, evt: *mut c_void) {
    if evt == 0 as *mut c_void {
        // Comes here when the target widget is destroyed.
        return;
    }

    println!("hello!");
    let parent = WxWindow::from(data);
    let msgDlg = WxMessageDialog::new(&parent, "Pushed!!", "The Button", wxOK);
    msgDlg.showModal();
}

fn make_button<T: TWxWindow>(parent: &T) -> WxButton {
    let button = WxButton::new(parent, wxID_ANY, "Push me!", 10, 10, 50, 30, 0);
    let closure = WxClosure::new(MyButton_clicked as *mut c_void, parent.ptr());
    unsafe {
        button.connect(wxID_ANY, wxID_ANY, expEVT_COMMAND_BUTTON_CLICKED(), closure.ptr());
    }

    button
}
<|endoftext|>


<commit_before>extern crate easystring;

#[cfg(test)]
mod length {
    use easystring::Text;

    #[test]
    fn zero() {
        assert_eq!(Text::new().len(), 0);
    }

    #[test]
    fn non_zero() {
        let text = Text::from("1234567890");
        assert_eq!(text.len(), 10);
    }

    #[test]
    fn empty() {
        assert!(Text::new().is_empty());
    }

    #[test]
    fn not_empty() {
        let text = Text::from("1234567890");
        assert!(!text.is_empty());
    }
}

#[cfg(test)]
mod from {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";
    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn string() {
        let string = String::from(STRING);
        let text = Text::from(string);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(path);
        assert_eq!(&text, STRING)
    }

    #[test]
    fn pathbuf() {
        let path = PathBuf::from(STRING);
        let text = Text::from(path);
        assert_eq!(&text, STRING)
    }
}

#[cfg(test)]
mod partial_equality_direct {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";

    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(text, STRING);
    }

    #[test]
    fn string() {
        let text = Text::from(STRING);
        let string = String::from(STRING);
        assert_eq!(text, string);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(STRING);
        assert_eq!(text, path);
    }

    #[test]
    fn pathbuf() {
        let pathbuf = PathBuf::from(STRING);
        let text = Text::from(STRING);
        assert_eq!(text, pathbuf);
    }
}

#[cfg(test)]
mod partial_equality_as_ref {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";

    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn string() {
        let text = Text::from(STRING);
        let string = String::from(STRING);
        assert_eq!(&text, string);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(STRING);
        assert_eq!(&text, path);
    }

    #[test]
    fn pathbuf() {
        let pathbuf = PathBuf::from(STRING);
        let text = Text::from(STRING);
        assert_eq!(&text, pathbuf);
    }
}

#[cfg(test)]
mod ops {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    #[test]
    fn add_text() {
        let t1 = Text::from("123");
        let t2 = Text::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_string() {
        let t1 = Text::from("123");
        let t2 = String::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_path() {
        let t1 = Text::from("123");
        let t2 = Path::new("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_pathbuf() {
        let t1 = Text::from("123");
        let t2 = PathBuf::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }
}
<commit_msg>Another test for multi add<commit_after>extern crate easystring;

#[cfg(test)]
mod length {
    use easystring::Text;

    #[test]
    fn zero() {
        assert_eq!(Text::new().len(), 0);
    }

    #[test]
    fn non_zero() {
        let text = Text::from("1234567890");
        assert_eq!(text.len(), 10);
    }

    #[test]
    fn empty() {
        assert!(Text::new().is_empty());
    }

    #[test]
    fn not_empty() {
        let text = Text::from("1234567890");
        assert!(!text.is_empty());
    }
}

#[cfg(test)]
mod from {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";
    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn string() {
        let string = String::from(STRING);
        let text = Text::from(string);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(path);
        assert_eq!(&text, STRING)
    }

    #[test]
    fn pathbuf() {
        let path = PathBuf::from(STRING);
        let text = Text::from(path);
        assert_eq!(&text, STRING)
    }
}

#[cfg(test)]
mod partial_equality_direct {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";

    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(text, STRING);
    }

    #[test]
    fn string() {
        let text = Text::from(STRING);
        let string = String::from(STRING);
        assert_eq!(text, string);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(STRING);
        assert_eq!(text, path);
    }

    #[test]
    fn pathbuf() {
        let pathbuf = PathBuf::from(STRING);
        let text = Text::from(STRING);
        assert_eq!(text, pathbuf);
    }
}

#[cfg(test)]
mod partial_equality_as_ref {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    const STRING: &'static str = "EaSyStRiNg";

    #[test]
    fn str() {
        let text = Text::from(STRING);
        assert_eq!(&text, STRING);
    }

    #[test]
    fn string() {
        let text = Text::from(STRING);
        let string = String::from(STRING);
        assert_eq!(&text, string);
    }

    #[test]
    fn path() {
        let path = Path::new(STRING);
        let text = Text::from(STRING);
        assert_eq!(&text, path);
    }

    #[test]
    fn pathbuf() {
        let pathbuf = PathBuf::from(STRING);
        let text = Text::from(STRING);
        assert_eq!(&text, pathbuf);
    }
}

#[cfg(test)]
mod ops {
    use std::path::{Path, PathBuf};
    use easystring::Text;

    #[test]
    fn add_text() {
        let t1 = Text::from("123");
        let t2 = Text::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_string() {
        let t1 = Text::from("123");
        let t2 = String::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_path() {
        let t1 = Text::from("123");
        let t2 = Path::new("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_pathbuf() {
        let t1 = Text::from("123");
        let t2 = PathBuf::from("456");
        let text = t1 + t2;
        assert_eq!(text, "123456");
    }

    #[test]
    fn add_multi() {
        let t0 = Text::new();
        let t1 = String::from("123");
        let t2 = Path::new("456");
        let t3 = PathBuf::from("789");
        let text: Text = t0 + t1 + t2 + t3;
        assert_eq!(text, "123456789");
    }
}
<|endoftext|>


<commit_before>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use rusqlite::{Connection, Row};

use crate::catalog::CatalogVersion;
use crate::content::Content;
use crate::fromdb::FromDb;
use crate::lrobject::{LrId, LrObject};

/// A folder define the container for `LibraryFiles`
/// They are all attached to a `RootFolder`
#[derive(Clone)]
pub struct Folder {
    id: LrId,
    uuid: String,
    /// Path from the `RootFolder`
    pub path_from_root: String,
    /// Id of the `RootFolder`
    pub root_folder: LrId,
    pub content: Option<Content>,
}

impl LrObject for Folder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl FromDb for Folder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(Folder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            path_from_root: row.get(2)?,
            root_folder: row.get(3)?,
            content: None,
        })
    }
    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryFolder"
    }
    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,pathFromRoot,rootFolder"
    }
}

impl Folder {
    pub fn new(id: LrId, uuid: &str) -> Folder {
        Folder {
            id,
            uuid: String::from(uuid),
            path_from_root: String::from(""),
            root_folder: 0,
            content: None,
        }
    }
    pub fn read_content(&self, conn: &Connection) -> Content {
        Content::from_db(conn, "AgFolderContent", "containingFolder", self.id)
    }
}

/// Represent the ancestor of `Folder` and map to
/// an absolute path
#[derive(Clone)]
pub struct RootFolder {
    id: LrId,
    uuid: String,
    /// Absolute path of the `RootFolder`
    pub absolute_path: String,
    /// (User readable) name of the `RootFolder`
    pub name: String,
    /// Eventually if it is possible the path is relative
    /// to the catalog file.
    pub relative_path_from_catalog: Option<String>,
}

impl LrObject for RootFolder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl RootFolder {
    /// Create a new `RootFolder` with an id and uuid
    pub fn new(id: LrId, uuid: &str) -> RootFolder {
        RootFolder {
            id,
            uuid: String::from(uuid),
            absolute_path: String::from(""),
            name: String::from(""),
            relative_path_from_catalog: None,
        }
    }
}

impl FromDb for RootFolder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(RootFolder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            absolute_path: row.get(2)?,
            name: row.get(3)?,
            relative_path_from_catalog: row.get(4).ok(),
        })
    }

    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryRootFolder"
    }

    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,absolutePath,name,relativePathFromCatalog"
    }
}

/// Represent the all the folders
#[derive(Clone, Default)]
pub struct Folders {
    /// The `RootFolder` list
    pub roots: Vec<RootFolder>,
    /// The `Folder` list
    pub folders: Vec<Folder>,
}

impl Folders {
    pub fn new() -> Folders {
        Folders::default()
    }

    /// Return `true` is it is empty
    pub fn is_empty(&self) -> bool {
        self.roots.is_empty() && self.folders.is_empty()
    }

    /// Add a `Folder`
    pub fn add_folder(&mut self, folder: Folder) {
        self.folders.push(folder);
    }

    /// Add a `RootFolder`
    pub fn add_root_folder(&mut self, root_folder: RootFolder) {
        self.roots.push(root_folder);
    }

    /// Append a vector of `Folder`
    pub fn append_folders(&mut self, mut folders: Vec<Folder>) {
        self.folders.append(&mut folders);
    }

    /// Append a vector of `RootFolder`
    pub fn append_root_folders(&mut self, mut root_folders: Vec<RootFolder>) {
        self.roots.append(&mut root_folders);
    }

    /// Return the eventual `RootFolder` with the id.
    pub fn find_root_folder(&self, id: LrId) -> Option<&RootFolder> {
        for root in &self.roots {
            if root.id() == id {
                return Some(root);
            }
        }
        None
    }

    /// Resolve the folder path by providing an absolute path
    /// This does not check if the path exist but merely combine
    /// the `RootFolder` absolute_path and the `Folder` relative path
    pub fn resolve_folder_path(&self, folder: &Folder) -> Option<String> {
        let root_folder = self.find_root_folder(folder.root_folder)?;
        let mut root_path = root_folder.absolute_path.clone();
        root_path += &folder.path_from_root;
        Some(root_path)
    }
}

#[cfg(test)]
#[test]
fn test_resolve_folder_path() {
    let mut folders = Folders::new();

    let mut rfolder = RootFolder::new(24, "toplevel");
    rfolder.absolute_path = String::from("/home/hub/Pictures");
    rfolder.name = String::from("Pictures");
    folders.add_root_folder(rfolder);

    let mut folder = Folder::new(42, "foobar");
    folder.root_folder = 24;
    folder.path_from_root = String::from("/2017/10");
    folders.add_folder(folder);

    let resolved = folders.resolve_folder_path(&folders.folders[0]);
    assert!(resolved.is_some());
    let resolved = resolved.unwrap();
    assert_eq!(resolved, "/home/hub/Pictures/2017/10");
}
<commit_msg>Fix documentation typo<commit_after>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use rusqlite::{Connection, Row};

use crate::catalog::CatalogVersion;
use crate::content::Content;
use crate::fromdb::FromDb;
use crate::lrobject::{LrId, LrObject};

/// A folder define the container for `LibraryFiles`
/// They are all attached to a `RootFolder`
#[derive(Clone)]
pub struct Folder {
    id: LrId,
    uuid: String,
    /// Path from the `RootFolder`
    pub path_from_root: String,
    /// Id of the `RootFolder`
    pub root_folder: LrId,
    pub content: Option<Content>,
}

impl LrObject for Folder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl FromDb for Folder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(Folder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            path_from_root: row.get(2)?,
            root_folder: row.get(3)?,
            content: None,
        })
    }
    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryFolder"
    }
    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,pathFromRoot,rootFolder"
    }
}

impl Folder {
    pub fn new(id: LrId, uuid: &str) -> Folder {
        Folder {
            id,
            uuid: String::from(uuid),
            path_from_root: String::from(""),
            root_folder: 0,
            content: None,
        }
    }
    pub fn read_content(&self, conn: &Connection) -> Content {
        Content::from_db(conn, "AgFolderContent", "containingFolder", self.id)
    }
}

/// Represent the ancestor of `Folder` and map to
/// an absolute path
#[derive(Clone)]
pub struct RootFolder {
    id: LrId,
    uuid: String,
    /// Absolute path of the `RootFolder`
    pub absolute_path: String,
    /// (User readable) name of the `RootFolder`
    pub name: String,
    /// Eventually if it is possible the path is relative
    /// to the catalog file.
    pub relative_path_from_catalog: Option<String>,
}

impl LrObject for RootFolder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl RootFolder {
    /// Create a new `RootFolder` with an id and uuid
    pub fn new(id: LrId, uuid: &str) -> RootFolder {
        RootFolder {
            id,
            uuid: String::from(uuid),
            absolute_path: String::from(""),
            name: String::from(""),
            relative_path_from_catalog: None,
        }
    }
}

impl FromDb for RootFolder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(RootFolder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            absolute_path: row.get(2)?,
            name: row.get(3)?,
            relative_path_from_catalog: row.get(4).ok(),
        })
    }

    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryRootFolder"
    }

    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,absolutePath,name,relativePathFromCatalog"
    }
}

/// Represent all the folders
#[derive(Clone, Default)]
pub struct Folders {
    /// The `RootFolder` list
    pub roots: Vec<RootFolder>,
    /// The `Folder` list
    pub folders: Vec<Folder>,
}

impl Folders {
    pub fn new() -> Folders {
        Folders::default()
    }

    /// Return `true` is it is empty
    pub fn is_empty(&self) -> bool {
        self.roots.is_empty() && self.folders.is_empty()
    }

    /// Add a `Folder`
    pub fn add_folder(&mut self, folder: Folder) {
        self.folders.push(folder);
    }

    /// Add a `RootFolder`
    pub fn add_root_folder(&mut self, root_folder: RootFolder) {
        self.roots.push(root_folder);
    }

    /// Append a vector of `Folder`
    pub fn append_folders(&mut self, mut folders: Vec<Folder>) {
        self.folders.append(&mut folders);
    }

    /// Append a vector of `RootFolder`
    pub fn append_root_folders(&mut self, mut root_folders: Vec<RootFolder>) {
        self.roots.append(&mut root_folders);
    }

    /// Return the eventual `RootFolder` with the id.
    pub fn find_root_folder(&self, id: LrId) -> Option<&RootFolder> {
        for root in &self.roots {
            if root.id() == id {
                return Some(root);
            }
        }
        None
    }

    /// Resolve the folder path by providing an absolute path
    /// This does not check if the path exist but merely combine
    /// the `RootFolder` absolute_path and the `Folder` relative path
    pub fn resolve_folder_path(&self, folder: &Folder) -> Option<String> {
        let root_folder = self.find_root_folder(folder.root_folder)?;
        let mut root_path = root_folder.absolute_path.clone();
        root_path += &folder.path_from_root;
        Some(root_path)
    }
}

#[cfg(test)]
#[test]
fn test_resolve_folder_path() {
    let mut folders = Folders::new();

    let mut rfolder = RootFolder::new(24, "toplevel");
    rfolder.absolute_path = String::from("/home/hub/Pictures");
    rfolder.name = String::from("Pictures");
    folders.add_root_folder(rfolder);

    let mut folder = Folder::new(42, "foobar");
    folder.root_folder = 24;
    folder.path_from_root = String::from("/2017/10");
    folders.add_folder(folder);

    let resolved = folders.resolve_folder_path(&folders.folders[0]);
    assert!(resolved.is_some());
    let resolved = resolved.unwrap();
    assert_eq!(resolved, "/home/hub/Pictures/2017/10");
}
<|endoftext|>


<commit_before>
use BuildQuery;
use Groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

// impl Default for ListingOrderBy {
//     fn default() -> ListingOrderBy { ListingOrderBy::Name }
// }

#[derive(Debug, Copy, Clone)]
pub enum GroupListerOptionsSort {
    Asc,
    Desc,
}

// impl Default for GroupListerOptionsSort {
//     fn default() -> GroupListerOptionsSort { GroupListerOptionsSort::Asc }
// }

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: GroupListerOptionsSort, s: &mut String) {
    s.push_str(match order_by {
        GroupListerOptionsSort::Asc => "asc",
        GroupListerOptionsSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<GroupListerOptionsSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: GroupListerOptionsSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(GroupListerOptionsSort::Asc, &mut s);
    append_group_lister_options_sort(GroupListerOptionsSort::Desc, &mut s);
    append_group_lister_options_sort(GroupListerOptionsSort::Asc, &mut s);
    append_group_lister_options_sort(GroupListerOptionsSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(GroupListerOptionsSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(GroupListerOptionsSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<commit_msg>Rename `GroupListerOptionsSort` to `ListingSort`<commit_after>
use BuildQuery;
use Groups;

// https://docs.gitlab.com/ce/api/groups.html
// List groups:                 GET /groups
// List owned groups:           GET /groups/owned
// List a group's projects:     GET /groups/:id/projects
// Details of a group:          GET /groups/:id
// New group:                   POST /groups
// Transfer project to group:   POST  /groups/:id/projects/:project_id
// Update group:                PUT /groups/:id
// Remove group:                DELETE /groups/:id
// Search for group:            GET /groups?search=foobar

// https://docs.gitlab.com/ce/api/groups.html#list-groups

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Name,
    Path,
}

// impl Default for ListingOrderBy {
//     fn default() -> ListingOrderBy { ListingOrderBy::Name }
// }

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

// impl Default for ListingSort {
//     fn default() -> ListingSort { ListingSort::Asc }
// }

fn append_group_lister_options_order_by(order_by: ListingOrderBy, s: &mut String) {
    s.push_str(match order_by {
        ListingOrderBy::Name => "name",
        ListingOrderBy::Path => "path",
    });
}

fn append_group_lister_options_sort(order_by: ListingSort, s: &mut String) {
    s.push_str(match order_by {
        ListingSort::Asc => "asc",
        ListingSort::Desc => "desc",
    });
}

/// https://docs.gitlab.com/ce/api/groups.html#list-groups
#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Skip the group IDs passes
    skip_groups: Vec<i64>,
    /// Show all the groups you have access to
    all_available: Option<bool>,
    /// Return list of authorized groups matching the search criteria
    search: String,
    /// Order groups by `name` or `path`. Default is `name`
    order_by: Option<ListingOrderBy>,
    /// Order groups in `asc` or `desc` order. Default is `asc`
    sort: Option<ListingSort>,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn skip_groups(&mut self, skip_groups: Vec<i64>) -> &mut Listing {
        self.skip_groups = skip_groups;
        self
    }
    pub fn all_available(&mut self, all_available: bool) -> &mut Listing {
        self.all_available = Some(all_available);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("groups");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?", only if one of the `Option` is `Some(_)`
        query.push_str(match (self.skip_groups.is_empty(),
                              &self.all_available,
                              self.search.is_empty(),
                              &self.order_by,
                              &self.sort) {
            (true, &None, true, &None, &None) => "",
            _ => "?",
        });

        if !self.skip_groups.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            let mut array_split_char = &none_char;
            for skip_group in &self.skip_groups {
                query.push_str(array_split_char);
                query.push_str("skip_groups[]=");
                query.push_str(&skip_group.to_string());
                array_split_char = &amp_char;
            }
        }

        self.all_available.map(|all_available| {
            query.push_str(&split_char);
            split_char = &amp_char;

            if all_available {
                query.push_str("all_available=true")
            } else {
                query.push_str("all_available=false")
            }
        });

        if !self.search.is_empty() {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.order_by.map(|order_by| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            append_group_lister_options_order_by(order_by, &mut query);
        });

        self.sort.map(|sort| {
            query.push_str(&split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            append_group_lister_options_sort(sort, &mut query);
        });

        query
    }
}

#[test]
fn test_append_group_lister_options_order_by() {
    let expected_string = "Initialnamepathpathname";

    let mut s = String::from("Initial");

    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Path, &mut s);
    append_group_lister_options_order_by(ListingOrderBy::Name, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn test_append_group_lister_options_sort() {
    let expected_string = "Initialascdescascdesc";

    let mut s = String::from("Initial");

    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);
    append_group_lister_options_sort(ListingSort::Asc, &mut s);
    append_group_lister_options_sort(ListingSort::Desc, &mut s);

    assert_eq!(s, expected_string);
}

#[test]
fn groups_build_query_default() {
    let expected_string = "groups";
    let listing: Listing = Default::default();
    let query = listing.build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups";
    let listing = Listing::new();
    let query = listing.build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_skip_groups() {
    let expected_string = "groups?skip_groups[]=1&skip_groups[]=2&skip_groups[]=3";
    let query = Listing::new().skip_groups(vec![1,2,3]).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_all_available() {
    let expected_string = "groups?all_available=true";
    let query = Listing::new().all_available(true).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?all_available=false";
    let query = Listing::new().all_available(false).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search() {
    let expected_string = "groups?search=SearchPattern";
    let query = Listing::new().search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_name() {
    let expected_string = "groups?order_by=name";
    let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_order_by_path() {
    let expected_string = "groups?order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_sort() {
    let expected_string = "groups?sort=asc";
    let query = Listing::new().sort(ListingSort::Asc).build_query();
    assert_eq!(query, expected_string);

    let expected_string = "groups?sort=desc";
    let query = Listing::new().sort(ListingSort::Desc).build_query();
    assert_eq!(query, expected_string);
}

#[test]
fn groups_build_query_search_order_by_path() {
    let expected_string = "groups?search=SearchPattern&order_by=path";
    let query = Listing::new().order_by(ListingOrderBy::Path).search(String::from("SearchPattern")).build_query();
    assert_eq!(query, expected_string);
    let query = Listing::new().search(String::from("SearchPattern")).order_by(ListingOrderBy::Path).build_query();
    assert_eq!(query, expected_string);
}
<|endoftext|>