<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.

use context::GraphicsContextMethods;

use std::libc::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
use std::ptr::null;
use sync::Arc;

// Constants.

static GLX_RGBA: c_int = 4;
/*static GLX_RED_SIZE: c_int = 8;
static GLX_GREEN_SIZE: c_int = 9;
static GLX_BLUE_SIZE: c_int = 10;*/
static GLX_DEPTH_SIZE: c_int = 12;

static ATTRIBUTES: [c_int, ..4] = [
    GLX_RGBA,
    GLX_DEPTH_SIZE, 24,
    0,
];

// External bindings to Xlib.

// Opaque structures.
struct _XPrivate;
struct _XrmHashBucketRec;
struct Depth;
struct GLXContextOpaque;
struct Visual;

// Sadly we need to copy some of this definition in here because the Xlib macros need to access it.
struct Display {
    ext_data: *XExtData,
    private1: *_XPrivate,
    fd: c_int,
    private2: c_int,
    proto_major_version: c_int,
    proto_minor_version: c_int,
    vendor: *c_char,
    private3: XID,
    private4: XID,
    private5: XID,
    private6: c_int,
    resource_alloc: *c_void,
    byte_order: c_int,
    bitmap_unit: c_int,
    bitmap_pad: c_int,
    bitmap_bit_order: c_int,
    nformats: c_int,
    pixmap_format: *ScreenFormat,
    private8: c_int,
    release: c_int,
    private9: *_XPrivate,
    private10: *_XPrivate,
    qlen: c_int,
    last_request_read: c_ulong,
    request: c_ulong,
    private11: XPointer,
    private12: XPointer,
    private13: XPointer,
    private14: XPointer,
    max_request_size: c_uint,
    db: *_XrmHashBucketRec,
    private15: *c_void,
    display_name: *c_char,

    // FIXME(pcwalton): These are needed for some reason...
    pad: *c_void,
    pad1: *c_void,

    default_screen: c_int,
    nscreens: c_int,
    screens: *Screen,
}

struct Screen {
    ext_data: *XExtData,
    display: *Display,
    root: Window,
    width: c_int,
    height: c_int,
    mwidth: c_int,
    mheight: c_int,
    ndepths: c_int,
    depths: *Depth,
    root_depth: c_int,
    root_visual: *Visual,
    default_gc: GC,
    cmap: Colormap,
    white_pixel: c_ulong,
    black_pixel: c_ulong,
    max_maps: c_int,
    min_maps: c_int,
    backing_store: c_int,
    save_unders: Bool,
    root_input_mask: c_long,
    pad: *c_void,
}

struct ScreenFormat;
struct XExtData;

struct XVisualInfo {
    visual: *Visual,
    visualid: VisualID,
    screen: c_int,
    depth: c_int,
    class: c_int,
    red_mask: c_ulong,
    green_mask: c_ulong,
    blue_mask: c_ulong,
    colormap_size: c_int,
    bits_per_rgb: c_int,
}

type Bool = c_int;
type Colormap = XID;
type Drawable = c_uint;                 // compatible with Window
type GC = *c_void;
type GLXContext = *GLXContextOpaque;
type GLXDrawable = c_uint;              // compatible with GLXPixmap
type GLXPixmap = c_uint;                // compatible with GLXDrawable
type Pixmap = c_uint;
type VisualID = c_ulong;
type Window = c_uint;                   // compatible with Drawable
type XID = c_uint;
type XPointer = *c_void;

#[link(name = "X11")]
#[link(name = "GL")]
extern {
    fn XOpenDisplay(n: c_int) -> *Display;
    fn XCreatePixmap(display: *Display, d: Drawable, width: c_uint, height: c_uint, depth: c_uint)
                     -> Pixmap;

    fn glXChooseVisual(dpy: *Display, screen: c_int, attribList: *c_int) -> *XVisualInfo;
    fn glXCreateContext(dpy: *Display, vis: *XVisualInfo, shareList: GLXContext, direct: Bool)
                        -> GLXContext;
    fn glXCreateGLXPixmap(dpy: *Display, vis: *XVisualInfo, pixmap: Pixmap) -> GLXPixmap;
    fn glXMakeContextCurrent(dpy: *Display, draw: GLXDrawable, read: GLXDrawable, ctx: GLXContext)
                             -> Bool;
}

// X11 macros

fn DefaultScreen(dpy: *Display) -> c_int {
    unsafe {
        (*dpy).default_screen
    }
}
fn RootWindow(dpy: *Display, scr: c_int) -> Window {
    unsafe {
        (*ScreenOfDisplay(dpy, scr)).root
    }
}
fn ScreenOfDisplay(dpy: *Display, scr: c_int) -> *Screen {
    unsafe {
        (&(*dpy).screens).offset(scr as int)
    }
}

// Implementation

/// Linux-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    display: *Display,
    pixmap: GLXPixmap,
    context: Arc<GLXContext>,
}

impl GraphicsContext {
    // Creates a new, possibly shared, GLX context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        let (display, visual, pixmap) = GraphicsContext::create_display_visual_and_pixmap();

        unsafe {
            let context = match share_context {
                None => glXCreateContext(display, visual, null(), 1),
                Some(share_context) => {
                    let native_share_context = share_context.native();
                    glXCreateContext(display, visual, *native_share_context.get(), 1)
                }
            };

            assert!(context != null());

            GraphicsContext {
                display: display,
                pixmap: pixmap,
                context: Arc::new(context),
            }
        }
    }

    fn create_display_visual_and_pixmap() -> (*Display, *XVisualInfo, GLXPixmap) {
        unsafe {
            // Get a connection.
            let display = XOpenDisplay(0);

            // Get an appropriate visual.
            let visual = glXChooseVisual(display, DefaultScreen(display), &ATTRIBUTES[0]);

            // Create the pixmap.
            let root_window = RootWindow(display, DefaultScreen(display));
            let pixmap = XCreatePixmap(display, root_window, 10, 10, 24);
            let glx_pixmap = glXCreateGLXPixmap(display, visual, pixmap);

            debug!("XCreatePixmap returned {}, glXCreateGLXPixmap returned {}",
                   pixmap,
                   glx_pixmap);

            (display, visual, glx_pixmap)
        }
    }
}

impl GraphicsContextMethods<GLXContext> for GraphicsContext {
    /// Wraps the given instance of the native GLX graphics context, bumping the reference count in
    /// the process.
    fn wrap(instance: Arc<GLXContext>) -> GraphicsContext {
        let (display, _, pixmap) = GraphicsContext::create_display_visual_and_pixmap();
        GraphicsContext {
            display: display,
            pixmap: pixmap,
            context: instance.clone(),
        }
    }

    /// Returns the underlying native 3D context.
    fn native(&self) -> Arc<GLXContext> {
        self.context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let result = glXMakeContextCurrent(self.display,
                                               self.pixmap,
                                               self.pixmap,
                                               *self.context.get());
            assert!(result != 0);
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContext {
            display: self.display,
            pixmap: self.pixmap,
            context: self.context.clone(),
        }
    }
}

<commit_msg>Update to current rust: RefCell::{get, set} are gone.<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.

use context::GraphicsContextMethods;

use std::libc::{c_char, c_int, c_long, c_uint, c_ulong, c_void};
use std::ptr::null;
use sync::Arc;

// Constants.

static GLX_RGBA: c_int = 4;
/*static GLX_RED_SIZE: c_int = 8;
static GLX_GREEN_SIZE: c_int = 9;
static GLX_BLUE_SIZE: c_int = 10;*/
static GLX_DEPTH_SIZE: c_int = 12;

static ATTRIBUTES: [c_int, ..4] = [
    GLX_RGBA,
    GLX_DEPTH_SIZE, 24,
    0,
];

// External bindings to Xlib.

// Opaque structures.
struct _XPrivate;
struct _XrmHashBucketRec;
struct Depth;
struct GLXContextOpaque;
struct Visual;

// Sadly we need to copy some of this definition in here because the Xlib macros need to access it.
struct Display {
    ext_data: *XExtData,
    private1: *_XPrivate,
    fd: c_int,
    private2: c_int,
    proto_major_version: c_int,
    proto_minor_version: c_int,
    vendor: *c_char,
    private3: XID,
    private4: XID,
    private5: XID,
    private6: c_int,
    resource_alloc: *c_void,
    byte_order: c_int,
    bitmap_unit: c_int,
    bitmap_pad: c_int,
    bitmap_bit_order: c_int,
    nformats: c_int,
    pixmap_format: *ScreenFormat,
    private8: c_int,
    release: c_int,
    private9: *_XPrivate,
    private10: *_XPrivate,
    qlen: c_int,
    last_request_read: c_ulong,
    request: c_ulong,
    private11: XPointer,
    private12: XPointer,
    private13: XPointer,
    private14: XPointer,
    max_request_size: c_uint,
    db: *_XrmHashBucketRec,
    private15: *c_void,
    display_name: *c_char,

    // FIXME(pcwalton): These are needed for some reason...
    pad: *c_void,
    pad1: *c_void,

    default_screen: c_int,
    nscreens: c_int,
    screens: *Screen,
}

struct Screen {
    ext_data: *XExtData,
    display: *Display,
    root: Window,
    width: c_int,
    height: c_int,
    mwidth: c_int,
    mheight: c_int,
    ndepths: c_int,
    depths: *Depth,
    root_depth: c_int,
    root_visual: *Visual,
    default_gc: GC,
    cmap: Colormap,
    white_pixel: c_ulong,
    black_pixel: c_ulong,
    max_maps: c_int,
    min_maps: c_int,
    backing_store: c_int,
    save_unders: Bool,
    root_input_mask: c_long,
    pad: *c_void,
}

struct ScreenFormat;
struct XExtData;

struct XVisualInfo {
    visual: *Visual,
    visualid: VisualID,
    screen: c_int,
    depth: c_int,
    class: c_int,
    red_mask: c_ulong,
    green_mask: c_ulong,
    blue_mask: c_ulong,
    colormap_size: c_int,
    bits_per_rgb: c_int,
}

type Bool = c_int;
type Colormap = XID;
type Drawable = c_uint;                 // compatible with Window
type GC = *c_void;
type GLXContext = *GLXContextOpaque;
type GLXDrawable = c_uint;              // compatible with GLXPixmap
type GLXPixmap = c_uint;                // compatible with GLXDrawable
type Pixmap = c_uint;
type VisualID = c_ulong;
type Window = c_uint;                   // compatible with Drawable
type XID = c_uint;
type XPointer = *c_void;

#[link(name = "X11")]
#[link(name = "GL")]
extern {
    fn XOpenDisplay(n: c_int) -> *Display;
    fn XCreatePixmap(display: *Display, d: Drawable, width: c_uint, height: c_uint, depth: c_uint)
                     -> Pixmap;

    fn glXChooseVisual(dpy: *Display, screen: c_int, attribList: *c_int) -> *XVisualInfo;
    fn glXCreateContext(dpy: *Display, vis: *XVisualInfo, shareList: GLXContext, direct: Bool)
                        -> GLXContext;
    fn glXCreateGLXPixmap(dpy: *Display, vis: *XVisualInfo, pixmap: Pixmap) -> GLXPixmap;
    fn glXMakeContextCurrent(dpy: *Display, draw: GLXDrawable, read: GLXDrawable, ctx: GLXContext)
                             -> Bool;
}

// X11 macros

fn DefaultScreen(dpy: *Display) -> c_int {
    unsafe {
        (*dpy).default_screen
    }
}
fn RootWindow(dpy: *Display, scr: c_int) -> Window {
    unsafe {
        (*ScreenOfDisplay(dpy, scr)).root
    }
}
fn ScreenOfDisplay(dpy: *Display, scr: c_int) -> *Screen {
    unsafe {
        (&(*dpy).screens).offset(scr as int)
    }
}

// Implementation

/// Linux-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    display: *Display,
    pixmap: GLXPixmap,
    context: Arc<GLXContext>,
}

impl GraphicsContext {
    // Creates a new, possibly shared, GLX context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        let (display, visual, pixmap) = GraphicsContext::create_display_visual_and_pixmap();

        unsafe {
            let context = match share_context {
                None => glXCreateContext(display, visual, null(), 1),
                Some(share_context) => {
                    let native_share_context = share_context.native();
                    glXCreateContext(display, visual, *native_share_context, 1)
                }
            };

            assert!(context != null());

            GraphicsContext {
                display: display,
                pixmap: pixmap,
                context: Arc::new(context),
            }
        }
    }

    fn create_display_visual_and_pixmap() -> (*Display, *XVisualInfo, GLXPixmap) {
        unsafe {
            // Get a connection.
            let display = XOpenDisplay(0);

            // Get an appropriate visual.
            let visual = glXChooseVisual(display, DefaultScreen(display), &ATTRIBUTES[0]);

            // Create the pixmap.
            let root_window = RootWindow(display, DefaultScreen(display));
            let pixmap = XCreatePixmap(display, root_window, 10, 10, 24);
            let glx_pixmap = glXCreateGLXPixmap(display, visual, pixmap);

            debug!("XCreatePixmap returned {}, glXCreateGLXPixmap returned {}",
                   pixmap,
                   glx_pixmap);

            (display, visual, glx_pixmap)
        }
    }
}

impl GraphicsContextMethods<GLXContext> for GraphicsContext {
    /// Wraps the given instance of the native GLX graphics context, bumping the reference count in
    /// the process.
    fn wrap(instance: Arc<GLXContext>) -> GraphicsContext {
        let (display, _, pixmap) = GraphicsContext::create_display_visual_and_pixmap();
        GraphicsContext {
            display: display,
            pixmap: pixmap,
            context: instance.clone(),
        }
    }

    /// Returns the underlying native 3D context.
    fn native(&self) -> Arc<GLXContext> {
        self.context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let result = glXMakeContextCurrent(self.display,
                                               self.pixmap,
                                               self.pixmap,
                                               *self.context);
            assert!(result != 0);
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContext {
            display: self.display,
            pixmap: self.pixmap,
            context: self.context.clone(),
        }
    }
}

<|endoftext|>


<commit_before>//! A module for inter-process communication

<commit_msg>Working on IPC abstractions<commit_after>//! A module for inter-process communication
//!
//! In os1, IPC is accomplished primarily through typed
//! shared data structures. A page is shared by one
//! process and accepted by the other.
//!
//! This module provides some useful primitives and
//! abstractions for IPC.

/// A thread-safe abstraction for managing shared memory
///
/// A `SharedMemAllocator` is constructed by a process
/// that wants to share memory with another process. The
/// page-aligned address of the memory the process wants
/// to share is given to the constructor, which will share
/// the memory and return a handle to it.
///
/// The handle can then be used to allocate some of the memory
/// and return parts of it.
pub struct SharedMemAllocator;
<|endoftext|>


<commit_before>use std::collections::VecDeque;

// https://leetcode.com/problems/nearest-exit-from-entrance-in-maze/
pub fn nearest_exit(maze: Vec<Vec<char>>, entrance: Vec<i32>) -> i32 {
    let mut answer = 0;
    let mut found_exit = false;
    let max_rows = maze.len();
    let max_cols = if max_rows == 0 { 0 } else { maze[0].len() };
    let mut visited: Vec<Vec<bool>> = vec![vec![false; max_cols]; max_rows];
    let mut deque: VecDeque<Vec<i32>> = VecDeque::new();
    deque.push_back(entrance.clone());
    'outer: while !deque.is_empty() {
        let length = deque.len();
        for _ in 0..length {
            let v = deque.pop_front().unwrap();
            visited[v[0] as usize][v[1] as usize] = true;
            for (r, c) in vec![(-1, 0), (0, 1), (1, 0), (0, -1)] {
                let row = v[0] + r;
                let col = v[1] + c;
                if v[0] == entrance[0]
                    && v[1] == entrance[1]
                    && (row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32)
                {
                    continue;
                }
                if row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32 {
                    found_exit = true;
                    break 'outer;
                }
                if visited[row as usize][col as usize] {
                    continue;
                }
                if maze[row as usize][col as usize] == '+' {
                    continue;
                }
                deque.push_back(vec![v[0] + r, v[1] + c]);
            }
        }
        answer += 1;
    }
    if !found_exit {
        -1
    } else {
        answer
    }
}

fn main() {
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '.', '+'],
                vec!['.', '.', '.', '+'],
                vec!['+', '+', '+', '.']
            ],
            vec![1, 2]
        )
    ); // 1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '+'],
                vec!['.', '.', '.'],
                vec!['+', '+', '+']
            ],
            vec![1, 0]
        )
    ); // 2
    println!("{}", nearest_exit(vec![vec!['.', '+']], vec![0, 0])); // -1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '.', '+', '+', '+', '+', '+'],
                vec!['+', '.', '+', '.', '.', '.', '+'],
                vec!['+', '.', '+', '.', '+', '.', '+'],
                vec!['+', '.', '.', '.', '+', '.', '+'],
                vec!['+', '+', '+', '+', '+', '+', '.']
            ],
            vec![0, 1]
        )
    ); // -1
}
<commit_msg>Solve problem 1926<commit_after>use std::collections::VecDeque;

// https://leetcode.com/problems/nearest-exit-from-entrance-in-maze/
pub fn nearest_exit(maze: Vec<Vec<char>>, entrance: Vec<i32>) -> i32 {
    let mut answer = 0;
    let mut found_exit = false;
    let max_rows = maze.len();
    let max_cols = if max_rows == 0 { 0 } else { maze[0].len() };
    let mut visited: Vec<Vec<bool>> = vec![vec![false; max_cols]; max_rows];
    let mut deque: VecDeque<Vec<i32>> = VecDeque::new();
    deque.push_back(entrance.clone());
    visited[entrance[0] as usize][entrance[1] as usize] = true;
    'outer: while !deque.is_empty() {
        let length = deque.len();
        for _ in 0..length {
            let v = deque.pop_front().unwrap();
            for (r, c) in vec![(-1, 0), (0, 1), (1, 0), (0, -1)] {
                let row = v[0] + r;
                let col = v[1] + c;
                if v[0] == entrance[0]
                    && v[1] == entrance[1]
                    && (row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32)
                {
                    continue;
                }
                if row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32 {
                    found_exit = true;
                    break 'outer;
                }
                if visited[row as usize][col as usize] {
                    continue;
                }
                if maze[row as usize][col as usize] == '+' {
                    continue;
                }
                visited[row as usize][col as usize] = true;
                deque.push_back(vec![row, col]);
            }
        }
        answer += 1;
    }
    if !found_exit {
        -1
    } else {
        answer
    }
}

fn main() {
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '.', '+'],
                vec!['.', '.', '.', '+'],
                vec!['+', '+', '+', '.']
            ],
            vec![1, 2]
        )
    ); // 1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '+'],
                vec!['.', '.', '.'],
                vec!['+', '+', '+']
            ],
            vec![1, 0]
        )
    ); // 2
    println!("{}", nearest_exit(vec![vec!['.', '+']], vec![0, 0])); // -1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '.', '+', '+', '+', '+', '+'],
                vec!['+', '.', '+', '.', '.', '.', '+'],
                vec!['+', '.', '+', '.', '+', '.', '+'],
                vec!['+', '.', '.', '.', '+', '.', '+'],
                vec!['+', '+', '+', '+', '+', '+', '.']
            ],
            vec![0, 1]
        )
    ); // -1
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/operations-on-tree/
struct LockingTree {}

/**
 * `&self` means the method takes an immutable reference
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl LockingTree {
    fn new(parent: Vec<i32>) -> Self {
        LockingTree {}
    }

    fn lock(&self, num: i32, user: i32) -> bool {
        todo!()
    }

    fn unlock(&self, num: i32, user: i32) -> bool {
        todo!()
    }

    fn upgrade(&self, num: i32, user: i32) -> bool {
        todo!()
    }
}

fn main() {
    let tree = LockingTree::new(vec![-1, 0, 0, 1, 1, 2, 2]);
    println!("{}", tree.lock(2, 2)); // true
    println!("{}", tree.unlock(2, 3)); // false
    println!("{}", tree.unlock(2, 2)); // true
    println!("{}", tree.lock(4, 5)); // true
    println!("{}", tree.upgrade(0, 1)); // true
    println!("{}", tree.lock(0, 1)); // false
    println!("{}", tree.upgrade(3, 1)); // false
}
<commit_msg>Update problem 1993<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/operations-on-tree/
struct LockingTree {
    tree: HashMap<i32, Vec<i32>>,
    locks: HashMap<i32, i32>,
}

/**
 * `&self` means the method takes an immutable reference
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl LockingTree {
    fn new(parent: Vec<i32>) -> Self {
        let mut tree = HashMap::new();
        for (num, parent) in parent.into_iter().enumerate() {
            let children = tree.entry(parent).or_insert(vec![]);
            (*children).push(num as i32);
        }
        LockingTree {
            tree,
            locks: HashMap::new(),
        }
    }

    fn lock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                self.locks.insert(num, user);
                true
            }
        }
    }

    fn unlock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(u) => {
                if user != *u {
                    return false;
                }
                self.locks.insert(num, user);
                true
            }
            None => false,
        }
    }

    fn upgrade(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                todo!()
            }
        }
    }
}

fn main() {
    let mut tree = LockingTree::new(vec![-1, 0, 0, 1, 1, 2, 2]);
    println!("{}", tree.lock(2, 2)); // true
    println!("{}", tree.unlock(2, 3)); // false
    println!("{}", tree.unlock(2, 2)); // true
    println!("{}", tree.lock(4, 5)); // true
    println!("{}", tree.upgrade(0, 1)); // true
    println!("{}", tree.lock(0, 1)); // false
    println!("{}", tree.upgrade(3, 1)); // false
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/number-of-arithmetic-triplets/
pub fn arithmetic_triplets(nums: Vec<i32>, diff: i32) -> i32 {
    todo!()
}

fn main() {
    println!("{}", arithmetic_triplets(vec![0, 1, 4, 6, 7, 10], 3)); // 2
    println!("{}", arithmetic_triplets(vec![4, 5, 6, 7, 8, 9], 2)); // 2
}
<commit_msg>Solve problem 2367<commit_after>use std::collections::HashSet;

// https://leetcode.com/problems/number-of-arithmetic-triplets/
pub fn arithmetic_triplets(nums: Vec<i32>, diff: i32) -> i32 {
    let mut set: HashSet<i32> = HashSet::new();
    for num in nums.iter() {
        set.insert(*num);
    }
    let mut answer = 0;
    for num in nums.into_iter() {
        let a = num + diff;
        let b = a + diff;
        if set.get(&a).is_some() && set.get(&b).is_some() {
            answer += 1;
        }
    }
    answer
}

fn main() {
    println!("{}", arithmetic_triplets(vec![0, 1, 4, 6, 7, 10], 3)); // 2
    println!("{}", arithmetic_triplets(vec![4, 5, 6, 7, 8, 9], 2)); // 2
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]

use std::intrinsics;

struct Foo {
    bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
    //~^ ERROR cycle detected when const-evaluating + checking
    x: usize,
}

fn main() {}
<commit_msg>Update compile-fail tests<commit_after>#![feature(core_intrinsics)]

use std::intrinsics;

struct Foo {
    bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
    //~^ ERROR cycle detected when simplifying constant for the type system
    x: usize,
}

fn main() {}
<|endoftext|>


<commit_before>// Test proc-macro crate can be built without addtional RUSTFLAGS
// on musl target
// override -Ctarget-feature=-crt-static from compiletest
// compile-flags: -Ctarget-feature=
// build-pass
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Foo)]
pub fn derive_foo(input: TokenStream) -> TokenStream {
    input
}
<commit_msg>Ignore wasm32<commit_after>// Test proc-macro crate can be built without addtional RUSTFLAGS
// on musl target
// override -Ctarget-feature=-crt-static from compiletest
// compile-flags: -Ctarget-feature=
// ignore-wasm32
// build-pass
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Foo)]
pub fn derive_foo(input: TokenStream) -> TokenStream {
    input
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::{BTreeMap, BinaryHeap};
use std::cmp::Ordering;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};
use url::form_urlencoded;

use query::Query;
use query::parse::parse_query;
use super::persistent;
use super::utils::json_response;
use super::super::{Globals, Document, Index};

#[derive(Debug)]
struct SearchHit<'a> {
    doc: &'a Document,
    score: f64,
}

impl<'a> SearchHit<'a> {
    fn as_json(&self) -> Json {
        let mut pk_field: Vec<Json> = Vec::new();
        pk_field.push(self.doc.fields.get("pk").unwrap().as_json());

        let mut fields = BTreeMap::new();
        fields.insert("pk".to_owned(), Json::Array(pk_field));

        let mut hit = BTreeMap::new();
        hit.insert("_score".to_owned(), Json::F64(self.score));
        hit.insert("fields".to_owned(), Json::Object(fields));
        Json::Object(hit)
    }
}

#[derive(Debug)]
struct SearchResponse<'a> {
    total_hits: usize,
    hits: Vec<SearchHit<'a>>,
}

#[derive(Debug)]
struct SearchRequest {
    query: Query,
    offset: usize,
    limit: usize,
}

impl SearchRequest {
    fn run<'a>(&self, index: &'a Index) -> SearchResponse<'a> {
        // Find all hits
        let mut hits = Vec::new();
        for (_, doc) in index.docs.iter() {
            if let Some(score) = self.query.rank(&doc) {
                hits.push(SearchHit {
                    doc: &doc,
                    score: score,
                });
            }
        }

        // Sort by score
        hits.sort_by(|a, b| a.score.partial_cmp(&b.score).unwrap_or(Ordering::Less));

        // Pagination
        let total_hits = hits.len();
        if self.offset > 0 {
            hits.drain(..self.offset);
        }
        hits.truncate(self.limit);

        SearchResponse {
            total_hits: total_hits,
            hits: hits,
        }
    }
}

pub fn view_count(req: &mut Request) -> IronResult<Response> {
    let ref glob = get_globals!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.read().unwrap();

    // Get index
    let index = get_index_or_404!(indices, *index_name);

    let count = match json_from_request_body!(req) {
        Some(query_json) => {
            // Parse query
            let query = parse_query(query_json.as_object().unwrap().get("query").unwrap());
            debug!("{:#?}", query);

            match query {
                Ok(query) => {
                    let request = SearchRequest {
                        query: query,
                        offset: 0,
                        limit: 0,
                    };

                    request.run(&index).total_hits
                }
                Err(error) => {
                    // TODO: What specifically is bad about the Query?
                    let mut response = Response::with((status::BadRequest,
                                                       "{\"message\": \"Query error\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            }
        }
        None => index.docs.len()
    };

    return Ok(json_response(status::Ok, format!("{{\"count\": {}}}", count)));
}

pub fn view_search(req: &mut Request) -> IronResult<Response> {
    let ref glob = get_globals!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.read().unwrap();

    // Get index
    let index = get_index_or_404!(indices, *index_name);

    match json_from_request_body!(req) {
        Some(query_json) => {
            // Parse query
            let query = parse_query(query_json.as_object().unwrap().get("query").unwrap());
            debug!("{:#?}", query);

            match query {
                Ok(query) => {
                    let mut request = SearchRequest {
                        query: query,
                        offset: 0,
                        limit: 10,
                    };

                    // TODO: Rewrite this
                    if let Some(ref url_query) = req.url.query {
                        for (key, value) in form_urlencoded::parse(url_query.as_bytes()) {
                            match key.as_ref() {
                                "from" => {
                                    request.offset = value.as_ref().parse().expect("need a number");
                                }
                                "size" => {
                                    request.limit = value.as_ref().parse().expect("need a number");
                                }
                                _ => warn!("unrecognised GET parameter {:?}", key),
                            }
                        }
                    }

                    let response = request.run(&index);

                    // TODO: {"took":5,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"wagtail","_type":"searchtests_searchtest_searchtests_searchtestchild","_id":"searchtests_searchtest:5380","_score":1.0,"fields":{"pk":["5380"]}},{"_index":"wagtail","_type":"searchtests_searchtest","_id":"searchtests_searchtest:5379","_score":1.0,"fields":{"pk":["5379"]}}]}}
                    Ok(json_response(status::Ok, format!("{{\"hits\": {{\"total\": {}, \"hits\": {}}}}}", response.total_hits, json::encode(&Json::Array(response.hits.iter().map(|hit| hit.as_json()).collect())).unwrap())))
                }
                Err(error) => {
                    // TODO: What specifically is bad about the Query?
                    let mut response = Response::with((status::BadRequest,
                                                       "{\"message\": \"Query error\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    Ok(response)
                }
            }
        }
        None => {
            Ok(json_response(status::BadRequest, "{\"message\": \"Missing query\"}"))
        }
    }
}
<commit_msg>Note the GET parameters we don't support yet<commit_after>use std::io::Read;
use std::collections::{BTreeMap, BinaryHeap};
use std::cmp::Ordering;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json::{self, Json};
use url::form_urlencoded;

use query::Query;
use query::parse::parse_query;
use super::persistent;
use super::utils::json_response;
use super::super::{Globals, Document, Index};

#[derive(Debug)]
struct SearchHit<'a> {
    doc: &'a Document,
    score: f64,
}

impl<'a> SearchHit<'a> {
    fn as_json(&self) -> Json {
        let mut pk_field: Vec<Json> = Vec::new();
        pk_field.push(self.doc.fields.get("pk").unwrap().as_json());

        let mut fields = BTreeMap::new();
        fields.insert("pk".to_owned(), Json::Array(pk_field));

        let mut hit = BTreeMap::new();
        hit.insert("_score".to_owned(), Json::F64(self.score));
        hit.insert("fields".to_owned(), Json::Object(fields));
        Json::Object(hit)
    }
}

#[derive(Debug)]
struct SearchResponse<'a> {
    total_hits: usize,
    hits: Vec<SearchHit<'a>>,
}

#[derive(Debug)]
struct SearchRequest {
    query: Query,
    offset: usize,
    limit: usize,
}

impl SearchRequest {
    fn run<'a>(&self, index: &'a Index) -> SearchResponse<'a> {
        // Find all hits
        let mut hits = Vec::new();
        for (_, doc) in index.docs.iter() {
            if let Some(score) = self.query.rank(&doc) {
                hits.push(SearchHit {
                    doc: &doc,
                    score: score,
                });
            }
        }

        // Sort by score
        hits.sort_by(|a, b| a.score.partial_cmp(&b.score).unwrap_or(Ordering::Less));

        // Pagination
        let total_hits = hits.len();
        if self.offset > 0 {
            hits.drain(..self.offset);
        }
        hits.truncate(self.limit);

        SearchResponse {
            total_hits: total_hits,
            hits: hits,
        }
    }
}

pub fn view_count(req: &mut Request) -> IronResult<Response> {
    let ref glob = get_globals!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.read().unwrap();

    // Get index
    let index = get_index_or_404!(indices, *index_name);

    let count = match json_from_request_body!(req) {
        Some(query_json) => {
            // Parse query
            let query = parse_query(query_json.as_object().unwrap().get("query").unwrap());
            debug!("{:#?}", query);

            match query {
                Ok(query) => {
                    let request = SearchRequest {
                        query: query,
                        offset: 0,
                        limit: 0,
                    };

                    request.run(&index).total_hits
                }
                Err(error) => {
                    // TODO: What specifically is bad about the Query?
                    let mut response = Response::with((status::BadRequest,
                                                       "{\"message\": \"Query error\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    return Ok(response);
                }
            }
        }
        None => index.docs.len()
    };

    return Ok(json_response(status::Ok, format!("{{\"count\": {}}}", count)));
}

pub fn view_search(req: &mut Request) -> IronResult<Response> {
    let ref glob = get_globals!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = glob.indices.read().unwrap();

    // Get index
    let index = get_index_or_404!(indices, *index_name);

    match json_from_request_body!(req) {
        Some(query_json) => {
            // Parse query
            let query = parse_query(query_json.as_object().unwrap().get("query").unwrap());
            debug!("{:#?}", query);

            match query {
                Ok(query) => {
                    let mut request = SearchRequest {
                        query: query,
                        offset: 0,
                        limit: 10,
                    };

                    // TODO: Rewrite this
                    if let Some(ref url_query) = req.url.query {
                        for (key, value) in form_urlencoded::parse(url_query.as_bytes()) {
                            match key.as_ref() {
                                "from" => {
                                    request.offset = value.as_ref().parse().expect("need a number");
                                }
                                "size" => {
                                    request.limit = value.as_ref().parse().expect("need a number");
                                }
                                // explain
                                // version
                                // timeout
                                // terminate_after
                                // fields
                                // fielddata_fields
                                // track_scores
                                // stats
                                // suggest_field
                                _ => warn!("unrecognised GET parameter {:?}", key),
                            }
                        }
                    }

                    let response = request.run(&index);

                    // TODO: {"took":5,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"wagtail","_type":"searchtests_searchtest_searchtests_searchtestchild","_id":"searchtests_searchtest:5380","_score":1.0,"fields":{"pk":["5380"]}},{"_index":"wagtail","_type":"searchtests_searchtest","_id":"searchtests_searchtest:5379","_score":1.0,"fields":{"pk":["5379"]}}]}}
                    Ok(json_response(status::Ok, format!("{{\"hits\": {{\"total\": {}, \"hits\": {}}}}}", response.total_hits, json::encode(&Json::Array(response.hits.iter().map(|hit| hit.as_json()).collect())).unwrap())))
                }
                Err(error) => {
                    // TODO: What specifically is bad about the Query?
                    let mut response = Response::with((status::BadRequest,
                                                       "{\"message\": \"Query error\"}"));
                    response.headers.set_raw("Content-Type", vec![b"application/json".to_vec()]);
                    Ok(response)
                }
            }
        }
        None => {
            Ok(json_response(status::BadRequest, "{\"message\": \"Missing query\"}"))
        }
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    Ok(quote! {
        #[doc = "An iterator over the variants of [Self]"]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<commit_msg>add allows to prevent lint errors (#231)<commit_after>use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};

use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};

pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
    let name = &ast.ident;
    let gen = &ast.generics;
    let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
    let vis = &ast.vis;
    let type_properties = ast.get_type_properties()?;
    let strum_module_path = type_properties.crate_module_path();

    if gen.lifetimes().count() > 0 {
        return Err(syn::Error::new(
            Span::call_site(),
            "This macro doesn't support enums with lifetimes. \
             The resulting enums would be unbounded.",
        ));
    }

    let phantom_data = if gen.type_params().count() > 0 {
        let g = gen.type_params().map(|param| &param.ident);
        quote! { < ( #(#g),* ) > }
    } else {
        quote! { < () > }
    };

    let variants = match &ast.data {
        Data::Enum(v) => &v.variants,
        _ => return Err(non_enum_error()),
    };

    let mut arms = Vec::new();
    let mut idx = 0usize;
    for variant in variants {
        if variant.get_variant_properties()?.disabled.is_some() {
            continue;
        }

        let ident = &variant.ident;
        let params = match &variant.fields {
            Fields::Unit => quote! {},
            Fields::Unnamed(fields) => {
                let defaults = ::core::iter::repeat(quote!(::core::default::Default::default()))
                    .take(fields.unnamed.len());
                quote! { (#(#defaults),*) }
            }
            Fields::Named(fields) => {
                let fields = fields
                    .named
                    .iter()
                    .map(|field| field.ident.as_ref().unwrap());
                quote! { {#(#fields: ::core::default::Default::default()),*} }
            }
        };

        arms.push(quote! {#idx => ::core::option::Option::Some(#name::#ident #params)});
        idx += 1;
    }

    let variant_count = arms.len();
    arms.push(quote! { _ => ::core::option::Option::None });
    let iter_name = syn::parse_str::<Ident>(&format!("{}Iter", name)).unwrap();

    Ok(quote! {
        #[doc = "An iterator over the variants of [Self]"]
        #[allow(
            missing_copy_implementations,
            missing_debug_implementations,
        )]
        #vis struct #iter_name #ty_generics {
            idx: usize,
            back_idx: usize,
            marker: ::core::marker::PhantomData #phantom_data,
        }

        impl #impl_generics #iter_name #ty_generics #where_clause {
            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
                match idx {
                    #(#arms),*
                }
            }
        }

        impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
            type Iterator = #iter_name #ty_generics;
            fn iter() -> #iter_name #ty_generics {
                #iter_name {
                    idx: 0,
                    back_idx: 0,
                    marker: ::core::marker::PhantomData,
                }
            }
        }

        impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
            type Item = #name #ty_generics;

            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
                self.nth(0)
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                (t, Some(t))
            }

            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
                let idx = self.idx + n + 1;
                if idx + self.back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.idx = idx;
                    self.get(idx - 1)
                }
            }
        }

        impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
            fn len(&self) -> usize {
                self.size_hint().0
            }
        }

        impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
                let back_idx = self.back_idx + 1;

                if self.idx + back_idx > #variant_count {
                    // We went past the end of the iterator. Freeze back_idx at #variant_count
                    // so that it doesn't overflow if the user calls this repeatedly.
                    // See PR #76 for context.
                    self.back_idx = #variant_count;
                    ::core::option::Option::None
                } else {
                    self.back_idx = back_idx;
                    self.get(#variant_count - self.back_idx)
                }
            }
        }

        impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
            fn clone(&self) -> #iter_name #ty_generics {
                #iter_name {
                    idx: self.idx,
                    back_idx: self.back_idx,
                    marker: self.marker.clone(),
                }
            }
        }
    })
}
<|endoftext|>


<commit_before>extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::CStr;
use std::num::NonZeroU32;
use std::os::raw as libc;
use std::rc::Rc;
use std::{slice, str};

use super::raw::RawResult;
use super::row::PgRow;
use crate::result::{DatabaseErrorInformation, DatabaseErrorKind, Error, QueryResult};
use crate::util::OnceCell;

// Message after a database connection has been unexpectedly closed.
const CLOSED_CONNECTION_MSG: &str = "server closed the connection unexpectedly\n\t\
This probably means the server terminated abnormally\n\tbefore or while processing the request.\n";

pub(crate) struct PgResult {
    internal_result: RawResult,
    column_count: usize,
    row_count: usize,
    // We store field names as pointer
    // as we cannot put a correct lifetime here
    // The value is valid as long as we haven't freed `RawResult`
    column_name_map: OnceCell<Vec<Option<*const str>>>,
}

impl PgResult {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(internal_result: RawResult) -> QueryResult<Self> {
        let result_status = unsafe { PQresultStatus(internal_result.as_ptr()) };
        match result_status {
            ExecStatusType::PGRES_COMMAND_OK | ExecStatusType::PGRES_TUPLES_OK => {
                let column_count = unsafe { PQnfields(internal_result.as_ptr()) as usize };
                let row_count = unsafe { PQntuples(internal_result.as_ptr()) as usize };
                Ok(PgResult {
                    internal_result,
                    column_count,
                    row_count,
                    column_name_map: OnceCell::new(),
                })
            }
            ExecStatusType::PGRES_EMPTY_QUERY => {
                let error_message = "Received an empty query".to_string();
                Err(Error::DatabaseError(
                    DatabaseErrorKind::Unknown,
                    Box::new(error_message),
                ))
            }
            _ => {
                let mut error_kind =
                    match get_result_field(internal_result.as_ptr(), ResultField::SqlState) {
                        Some(error_codes::UNIQUE_VIOLATION) => DatabaseErrorKind::UniqueViolation,
                        Some(error_codes::FOREIGN_KEY_VIOLATION) => {
                            DatabaseErrorKind::ForeignKeyViolation
                        }
                        Some(error_codes::SERIALIZATION_FAILURE) => {
                            DatabaseErrorKind::SerializationFailure
                        }
                        Some(error_codes::READ_ONLY_TRANSACTION) => {
                            DatabaseErrorKind::ReadOnlyTransaction
                        }
                        Some(error_codes::NOT_NULL_VIOLATION) => {
                            DatabaseErrorKind::NotNullViolation
                        }
                        Some(error_codes::CHECK_VIOLATION) => DatabaseErrorKind::CheckViolation,
                        _ => DatabaseErrorKind::Unknown,
                    };
                let error_information = Box::new(PgErrorInformation(internal_result));
                if error_information.message() == CLOSED_CONNECTION_MSG {
                    error_kind = DatabaseErrorKind::ClosedConnection;
                }
                Err(Error::DatabaseError(error_kind, error_information))
            }
        }
    }

    pub fn rows_affected(&self) -> usize {
        unsafe {
            let count_char_ptr = PQcmdTuples(self.internal_result.as_ptr());
            let count_bytes = CStr::from_ptr(count_char_ptr).to_bytes();
            // Using from_utf8_unchecked is ok here because, we've set the
            // client encoding to utf8
            let count_str = str::from_utf8_unchecked(count_bytes);
            match count_str {
                "" => 0,
                _ => count_str
                    .parse()
                    .expect("Error parsing `rows_affected` as integer value"),
            }
        }
    }

    pub fn num_rows(&self) -> usize {
        self.row_count
    }

    pub fn get_row(self: Rc<Self>, idx: usize) -> PgRow {
        PgRow::new(self, idx)
    }

    pub fn get(&self, row_idx: usize, col_idx: usize) -> Option<&[u8]> {
        if self.is_null(row_idx, col_idx) {
            None
        } else {
            let row_idx = row_idx as libc::c_int;
            let col_idx = col_idx as libc::c_int;
            unsafe {
                let value_ptr =
                    PQgetvalue(self.internal_result.as_ptr(), row_idx, col_idx) as *const u8;
                let num_bytes = PQgetlength(self.internal_result.as_ptr(), row_idx, col_idx);
                Some(slice::from_raw_parts(value_ptr, num_bytes as usize))
            }
        }
    }

    pub fn is_null(&self, row_idx: usize, col_idx: usize) -> bool {
        unsafe {
            0 != PQgetisnull(
                self.internal_result.as_ptr(),
                row_idx as libc::c_int,
                col_idx as libc::c_int,
            )
        }
    }

    pub fn column_type(&self, col_idx: usize) -> NonZeroU32 {
        let type_oid = unsafe { PQftype(self.internal_result.as_ptr(), col_idx as libc::c_int) };
        NonZeroU32::new(type_oid).expect(
            "Got a zero oid from postgres. If you see this error message \
             please report it as issue on the diesel github bug tracker.",
        )
    }

    pub fn column_name(&self, col_idx: usize) -> Option<&str> {
        self.column_name_map
            .get_or_init(|| {
                (0..self.column_count)
                    .map(|idx| unsafe {
                        // https://www.postgresql.org/docs/13/libpq-exec.html#LIBPQ-PQFNAME
                        // states that the returned ptr is valid till the underlying result is freed
                        // That means we can couple the lifetime to self
                        let ptr = PQfname(self.internal_result.as_ptr(), idx as libc::c_int);
                        if ptr.is_null() {
                            None
                        } else {
                            Some(CStr::from_ptr(ptr).to_str().expect(
                                "Expect postgres field names to be UTF-8, because we \
                     requested UTF-8 encoding on connection setup",
                            ) as *const str)
                        }
                    })
                    .collect()
            })
            .get(col_idx)
            .and_then(|n| {
                n.map(|n: *const str| unsafe {
                    // The pointer is valid for the same lifetime as &self
                    // so we can dereference it without any check
                    &*n
                })
            })
    }

    pub fn column_count(&self) -> usize {
        self.column_count
    }
}

struct PgErrorInformation(RawResult);

impl DatabaseErrorInformation for PgErrorInformation {
    fn message(&self) -> &str {
        get_result_field(self.0.as_ptr(), ResultField::MessagePrimary)
            .unwrap_or_else(|| self.0.error_message())
    }

    fn details(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageDetail)
    }

    fn hint(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageHint)
    }

    fn table_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::TableName)
    }

    fn column_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ColumnName)
    }

    fn constraint_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ConstraintName)
    }

    fn statement_position(&self) -> Option<i32> {
        let str_pos = get_result_field(self.0.as_ptr(), ResultField::StatementPosition)?;
        str_pos.parse::<i32>().ok()
    }
}

/// Represents valid options to
/// [`PQresultErrorField`](https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQRESULTERRORFIELD)
/// Their values are defined as C preprocessor macros, and therefore are not exported by libpq-sys.
/// Their values can be found in `postgres_ext.h`
#[repr(i32)]
enum ResultField {
    SqlState = 'C' as i32,
    MessagePrimary = 'M' as i32,
    MessageDetail = 'D' as i32,
    MessageHint = 'H' as i32,
    TableName = 't' as i32,
    ColumnName = 'c' as i32,
    ConstraintName = 'n' as i32,
    StatementPosition = 'P' as i32,
}

fn get_result_field<'a>(res: *mut PGresult, field: ResultField) -> Option<&'a str> {
    let ptr = unsafe { PQresultErrorField(res, field as libc::c_int) };
    if ptr.is_null() {
        return None;
    }

    let c_str = unsafe { CStr::from_ptr(ptr) };
    c_str.to_str().ok()
}

mod error_codes {
    //! These error codes are documented at
    //! <https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html>
    //!
    //! They are not exposed programmatically through libpq.
    pub const UNIQUE_VIOLATION: &str = "23505";
    pub const FOREIGN_KEY_VIOLATION: &str = "23503";
    pub const SERIALIZATION_FAILURE: &str = "40001";
    pub const READ_ONLY_TRANSACTION: &str = "25006";
    pub const NOT_NULL_VIOLATION: &str = "23502";
    pub const CHECK_VIOLATION: &str = "23514";
}
<commit_msg>Post rebase format fixes<commit_after>extern crate pq_sys;

use self::pq_sys::*;
use std::ffi::CStr;
use std::num::NonZeroU32;
use std::os::raw as libc;
use std::rc::Rc;
use std::{slice, str};

use super::raw::RawResult;
use super::row::PgRow;
use crate::result::{DatabaseErrorInformation, DatabaseErrorKind, Error, QueryResult};
use crate::util::OnceCell;

// Message after a database connection has been unexpectedly closed.
const CLOSED_CONNECTION_MSG: &str = "server closed the connection unexpectedly\n\t\
This probably means the server terminated abnormally\n\tbefore or while processing the request.\n";

pub(crate) struct PgResult {
    internal_result: RawResult,
    column_count: usize,
    row_count: usize,
    // We store field names as pointer
    // as we cannot put a correct lifetime here
    // The value is valid as long as we haven't freed `RawResult`
    column_name_map: OnceCell<Vec<Option<*const str>>>,
}

impl PgResult {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(internal_result: RawResult) -> QueryResult<Self> {
        let result_status = unsafe { PQresultStatus(internal_result.as_ptr()) };
        match result_status {
            ExecStatusType::PGRES_COMMAND_OK | ExecStatusType::PGRES_TUPLES_OK => {
                let column_count = unsafe { PQnfields(internal_result.as_ptr()) as usize };
                let row_count = unsafe { PQntuples(internal_result.as_ptr()) as usize };
                Ok(PgResult {
                    internal_result,
                    column_count,
                    row_count,
                    column_name_map: OnceCell::new(),
                })
            }
            ExecStatusType::PGRES_EMPTY_QUERY => {
                let error_message = "Received an empty query".to_string();
                Err(Error::DatabaseError(
                    DatabaseErrorKind::Unknown,
                    Box::new(error_message),
                ))
            }
            _ => {
                let mut error_kind =
                    match get_result_field(internal_result.as_ptr(), ResultField::SqlState) {
                        Some(error_codes::UNIQUE_VIOLATION) => DatabaseErrorKind::UniqueViolation,
                        Some(error_codes::FOREIGN_KEY_VIOLATION) => {
                            DatabaseErrorKind::ForeignKeyViolation
                        }
                        Some(error_codes::SERIALIZATION_FAILURE) => {
                            DatabaseErrorKind::SerializationFailure
                        }
                        Some(error_codes::READ_ONLY_TRANSACTION) => {
                            DatabaseErrorKind::ReadOnlyTransaction
                        }
                        Some(error_codes::NOT_NULL_VIOLATION) => {
                            DatabaseErrorKind::NotNullViolation
                        }
                        Some(error_codes::CHECK_VIOLATION) => DatabaseErrorKind::CheckViolation,
                        _ => DatabaseErrorKind::Unknown,
                    };
                let error_information = Box::new(PgErrorInformation(internal_result));
                if error_information.message() == CLOSED_CONNECTION_MSG {
                    error_kind = DatabaseErrorKind::ClosedConnection;
                }
                Err(Error::DatabaseError(error_kind, error_information))
            }
        }
    }

    pub fn rows_affected(&self) -> usize {
        unsafe {
            let count_char_ptr = PQcmdTuples(self.internal_result.as_ptr());
            let count_bytes = CStr::from_ptr(count_char_ptr).to_bytes();
            // Using from_utf8_unchecked is ok here because, we've set the
            // client encoding to utf8
            let count_str = str::from_utf8_unchecked(count_bytes);
            match count_str {
                "" => 0,
                _ => count_str
                    .parse()
                    .expect("Error parsing `rows_affected` as integer value"),
            }
        }
    }

    pub fn num_rows(&self) -> usize {
        self.row_count
    }

    pub fn get_row(self: Rc<Self>, idx: usize) -> PgRow {
        PgRow::new(self, idx)
    }

    pub fn get(&self, row_idx: usize, col_idx: usize) -> Option<&[u8]> {
        if self.is_null(row_idx, col_idx) {
            None
        } else {
            let row_idx = row_idx as libc::c_int;
            let col_idx = col_idx as libc::c_int;
            unsafe {
                let value_ptr =
                    PQgetvalue(self.internal_result.as_ptr(), row_idx, col_idx) as *const u8;
                let num_bytes = PQgetlength(self.internal_result.as_ptr(), row_idx, col_idx);
                Some(slice::from_raw_parts(value_ptr, num_bytes as usize))
            }
        }
    }

    pub fn is_null(&self, row_idx: usize, col_idx: usize) -> bool {
        unsafe {
            0 != PQgetisnull(
                self.internal_result.as_ptr(),
                row_idx as libc::c_int,
                col_idx as libc::c_int,
            )
        }
    }

    pub fn column_type(&self, col_idx: usize) -> NonZeroU32 {
        let type_oid = unsafe { PQftype(self.internal_result.as_ptr(), col_idx as libc::c_int) };
        NonZeroU32::new(type_oid).expect(
            "Got a zero oid from postgres. If you see this error message \
             please report it as issue on the diesel github bug tracker.",
        )
    }

    pub fn column_name(&self, col_idx: usize) -> Option<&str> {
        self.column_name_map
            .get_or_init(|| {
                (0..self.column_count)
                    .map(|idx| unsafe {
                        // https://www.postgresql.org/docs/13/libpq-exec.html#LIBPQ-PQFNAME
                        // states that the returned ptr is valid till the underlying result is freed
                        // That means we can couple the lifetime to self
                        let ptr = PQfname(self.internal_result.as_ptr(), idx as libc::c_int);
                        if ptr.is_null() {
                            None
                        } else {
                            Some(CStr::from_ptr(ptr).to_str().expect(
                                "Expect postgres field names to be UTF-8, because we \
                     requested UTF-8 encoding on connection setup",
                            ) as *const str)
                        }
                    })
                    .collect()
            })
            .get(col_idx)
            .and_then(|n| {
                n.map(|n: *const str| unsafe {
                    // The pointer is valid for the same lifetime as &self
                    // so we can dereference it without any check
                    &*n
                })
            })
    }

    pub fn column_count(&self) -> usize {
        self.column_count
    }
}

struct PgErrorInformation(RawResult);

impl DatabaseErrorInformation for PgErrorInformation {
    fn message(&self) -> &str {
        get_result_field(self.0.as_ptr(), ResultField::MessagePrimary)
            .unwrap_or_else(|| self.0.error_message())
    }

    fn details(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageDetail)
    }

    fn hint(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::MessageHint)
    }

    fn table_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::TableName)
    }

    fn column_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ColumnName)
    }

    fn constraint_name(&self) -> Option<&str> {
        get_result_field(self.0.as_ptr(), ResultField::ConstraintName)
    }

    fn statement_position(&self) -> Option<i32> {
        let str_pos = get_result_field(self.0.as_ptr(), ResultField::StatementPosition)?;
        str_pos.parse::<i32>().ok()
    }
}

/// Represents valid options to
/// [`PQresultErrorField`](https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQRESULTERRORFIELD)
/// Their values are defined as C preprocessor macros, and therefore are not exported by libpq-sys.
/// Their values can be found in `postgres_ext.h`
#[repr(i32)]
enum ResultField {
    SqlState = 'C' as i32,
    MessagePrimary = 'M' as i32,
    MessageDetail = 'D' as i32,
    MessageHint = 'H' as i32,
    TableName = 't' as i32,
    ColumnName = 'c' as i32,
    ConstraintName = 'n' as i32,
    StatementPosition = 'P' as i32,
}

fn get_result_field<'a>(res: *mut PGresult, field: ResultField) -> Option<&'a str> {
    let ptr = unsafe { PQresultErrorField(res, field as libc::c_int) };
    if ptr.is_null() {
        return None;
    }

    let c_str = unsafe { CStr::from_ptr(ptr) };
    c_str.to_str().ok()
}

mod error_codes {
    //! These error codes are documented at
    //! <https://www.postgresql.org/docs/9.5/static/errcodes-appendix.html>
    //!
    //! They are not exposed programmatically through libpq.
    pub const UNIQUE_VIOLATION: &str = "23505";
    pub const FOREIGN_KEY_VIOLATION: &str = "23503";
    pub const SERIALIZATION_FAILURE: &str = "40001";
    pub const READ_ONLY_TRANSACTION: &str = "25006";
    pub const NOT_NULL_VIOLATION: &str = "23502";
    pub const CHECK_VIOLATION: &str = "23514";
}
<|endoftext|>


<commit_before>use diesel::prelude::*;
use std::path::{Path, PathBuf};

use super::*;
use crate::app::{config, user, vfs};
use crate::db::{self, directories, songs};
use crate::test_name;

#[test]
fn test_populate() {
	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();
	index.update().unwrap(); // Validates that subsequent updates don't run into conflicts

	let connection = db.connect().unwrap();
	let all_directories: Vec<Directory> = directories::table.load(&connection).unwrap();
	let all_songs: Vec<Song> = songs::table.load(&connection).unwrap();
	assert_eq!(all_directories.len(), 6);
	assert_eq!(all_songs.len(), 13);
}

#[test]
fn test_metadata() {
	let target: PathBuf = ["test-data", "small-collection", "Tobokegao", "Picnic"]
		.iter()
		.collect();

	let mut song_path = target.clone();
	song_path.push("05 - シャーベット (Sherbet).mp3");

	let mut artwork_path = target.clone();
	artwork_path.push("Folder.png");

	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("シャーベット (Sherbet)"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(song.path, song_path.to_string_lossy().as_ref());
	assert_eq!(song.track_number, Some(5));
	assert_eq!(song.disc_number, None);
	assert_eq!(song.title, Some("シャーベット (Sherbet)".to_owned()));
	assert_eq!(song.artist, Some("Tobokegao".to_owned()));
	assert_eq!(song.album_artist, None);
	assert_eq!(song.album, Some("Picnic".to_owned()));
	assert_eq!(song.year, Some(2016));
	assert_eq!(
		song.artwork,
		Some(artwork_path.to_string_lossy().into_owned())
	);
}

#[test]
fn test_artwork_pattern_case_insensitive() {
	let target: PathBuf = ["test-data", "small-collection", "Khemmis", "Hunted"]
		.iter()
		.collect();

	let mut song_path = target.clone();
	song_path.push("05 - Hunted.mp3");

	let mut artwork_path = target.clone();
	artwork_path.push("folder.jpg");

	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("Hunted"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(
		song.artwork,
		Some(artwork_path.to_string_lossy().into_owned())
	);
}

#[test]
fn test_embedded_artwork() {
	let song_path: PathBuf = [
		"test-data",
		"small-collection",
		"Tobokegao",
		"Picnic",
		"07 - なぜ (Why).mp3",
	]
	.iter()
	.collect();

	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("なぜ (Why?)"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(song.artwork, Some(song_path.to_string_lossy().into_owned()));
}

#[test]
fn test_browse_top_level() {
	let mut root_path = PathBuf::new();
	root_path.push("root");

	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let results = index.browse(Path::new("")).unwrap();

	assert_eq!(results.len(), 1);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_browse() {
	let khemmis_path: PathBuf = ["root", "Khemmis"].iter().collect();
	let tobokegao_path: PathBuf = ["root", "Tobokegao"].iter().collect();

	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let results = index.browse(Path::new("root")).unwrap();

	assert_eq!(results.len(), 2);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
	match results[1] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_flatten() {
	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	// Flatten all
	let results = index.flatten(Path::new("root")).unwrap();
	assert_eq!(results.len(), 13);
	assert_eq!(results[0].title, Some("Above The Water".to_owned()));

	// Flatten a directory
	let path: PathBuf = ["root", "Tobokegao"].iter().collect();
	let results = index.flatten(&path).unwrap();
	assert_eq!(results.len(), 8);

	// Flatten a directory that is a prefix of another directory (Picnic Remixes)
	let path: PathBuf = ["root", "Tobokegao", "Picnic"].iter().collect();
	let results = index.flatten(&path).unwrap();
	assert_eq!(results.len(), 7);
}

#[test]
fn test_random() {
	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let results = index.get_random_albums(1).unwrap();
	assert_eq!(results.len(), 1);
}

#[test]
fn test_recent() {
	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let results = index.get_recent_albums(2).unwrap();
	assert_eq!(results.len(), 2);
	assert!(results[0].date_added >= results[1].date_added);
}

#[test]
fn test_get_song() {
	let db = db::get_test_db(&test_name!());
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	index.update().unwrap();

	let song_path: PathBuf = ["root", "Khemmis", "Hunted", "02 - Candlelight.mp3"]
		.iter()
		.collect();

	let song = index.get_song(&song_path).unwrap();
	assert_eq!(song.title.unwrap(), "Candlelight");
}
<commit_msg>Cosmetic change<commit_after>use diesel::prelude::*;
use std::path::{Path, PathBuf};

use super::*;
use crate::app::{config, user, vfs};
use crate::db::{self, directories, songs};
use crate::test_name;

fn get_context(test_name: &str) -> (db::DB, Index) {
	let db = db::get_test_db(test_name);
	let vfs_manager = vfs::Manager::new(db.clone());
	let user_manager = user::Manager::new(db.clone());
	let config_manager = config::Manager::new(db.clone(), user_manager);
	let index = Index::new(db.clone(), vfs_manager, config_manager);
	(db, index)
}

#[test]
fn test_populate() {
	let (db, index) = get_context(&test_name!());
	index.update().unwrap();
	index.update().unwrap(); // Validates that subsequent updates don't run into conflicts

	let connection = db.connect().unwrap();
	let all_directories: Vec<Directory> = directories::table.load(&connection).unwrap();
	let all_songs: Vec<Song> = songs::table.load(&connection).unwrap();
	assert_eq!(all_directories.len(), 6);
	assert_eq!(all_songs.len(), 13);
}

#[test]
fn test_metadata() {
	let target: PathBuf = ["test-data", "small-collection", "Tobokegao", "Picnic"]
		.iter()
		.collect();

	let mut song_path = target.clone();
	song_path.push("05 - シャーベット (Sherbet).mp3");

	let mut artwork_path = target.clone();
	artwork_path.push("Folder.png");

	let (db, index) = get_context(&test_name!());
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("シャーベット (Sherbet)"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(song.path, song_path.to_string_lossy().as_ref());
	assert_eq!(song.track_number, Some(5));
	assert_eq!(song.disc_number, None);
	assert_eq!(song.title, Some("シャーベット (Sherbet)".to_owned()));
	assert_eq!(song.artist, Some("Tobokegao".to_owned()));
	assert_eq!(song.album_artist, None);
	assert_eq!(song.album, Some("Picnic".to_owned()));
	assert_eq!(song.year, Some(2016));
	assert_eq!(
		song.artwork,
		Some(artwork_path.to_string_lossy().into_owned())
	);
}

#[test]
fn test_artwork_pattern_case_insensitive() {
	let target: PathBuf = ["test-data", "small-collection", "Khemmis", "Hunted"]
		.iter()
		.collect();

	let mut song_path = target.clone();
	song_path.push("05 - Hunted.mp3");

	let mut artwork_path = target.clone();
	artwork_path.push("folder.jpg");

	let (db, index) = get_context(&test_name!());
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("Hunted"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(
		song.artwork,
		Some(artwork_path.to_string_lossy().into_owned())
	);
}

#[test]
fn test_embedded_artwork() {
	let song_path: PathBuf = [
		"test-data",
		"small-collection",
		"Tobokegao",
		"Picnic",
		"07 - なぜ (Why).mp3",
	]
	.iter()
	.collect();

	let (db, index) = get_context(&test_name!());
	index.update().unwrap();

	let connection = db.connect().unwrap();
	let songs: Vec<Song> = songs::table
		.filter(songs::title.eq("なぜ (Why?)"))
		.load(&connection)
		.unwrap();

	assert_eq!(songs.len(), 1);
	let song = &songs[0];
	assert_eq!(song.artwork, Some(song_path.to_string_lossy().into_owned()));
}

#[test]
fn test_browse_top_level() {
	let mut root_path = PathBuf::new();
	root_path.push("root");

	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	let results = index.browse(Path::new("")).unwrap();

	assert_eq!(results.len(), 1);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, root_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_browse() {
	let khemmis_path: PathBuf = ["root", "Khemmis"].iter().collect();
	let tobokegao_path: PathBuf = ["root", "Tobokegao"].iter().collect();

	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	let results = index.browse(Path::new("root")).unwrap();

	assert_eq!(results.len(), 2);
	match results[0] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, khemmis_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
	match results[1] {
		CollectionFile::Directory(ref d) => assert_eq!(d.path, tobokegao_path.to_str().unwrap()),
		_ => panic!("Expected directory"),
	}
}

#[test]
fn test_flatten() {
	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	// Flatten all
	let results = index.flatten(Path::new("root")).unwrap();
	assert_eq!(results.len(), 13);
	assert_eq!(results[0].title, Some("Above The Water".to_owned()));

	// Flatten a directory
	let path: PathBuf = ["root", "Tobokegao"].iter().collect();
	let results = index.flatten(&path).unwrap();
	assert_eq!(results.len(), 8);

	// Flatten a directory that is a prefix of another directory (Picnic Remixes)
	let path: PathBuf = ["root", "Tobokegao", "Picnic"].iter().collect();
	let results = index.flatten(&path).unwrap();
	assert_eq!(results.len(), 7);
}

#[test]
fn test_random() {
	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	let results = index.get_random_albums(1).unwrap();
	assert_eq!(results.len(), 1);
}

#[test]
fn test_recent() {
	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	let results = index.get_recent_albums(2).unwrap();
	assert_eq!(results.len(), 2);
	assert!(results[0].date_added >= results[1].date_added);
}

#[test]
fn test_get_song() {
	let (_db, index) = get_context(&test_name!());
	index.update().unwrap();

	let song_path: PathBuf = ["root", "Khemmis", "Hunted", "02 - Candlelight.mp3"]
		.iter()
		.collect();

	let song = index.get_song(&song_path).unwrap();
	assert_eq!(song.title.unwrap(), "Candlelight");
}
<|endoftext|>