<commit_before>use super::{c, fill_utf16_buf, to_u16s};
use crate::ffi::OsStr;
use crate::io;
use crate::mem;
use crate::path::Path;
use crate::path::Prefix;
use crate::ptr;

#[cfg(test)]
mod tests;

pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';

/// # Safety
///
/// `bytes` must be a valid wtf8 encoded slice
#[inline]
unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr {
    // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8,
    // which is compatible with &[u8].
    mem::transmute(bytes)
}

#[inline]
pub fn is_sep_byte(b: u8) -> bool {
    b == b'/' || b == b'\\'
}

#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
    b == b'\\'
}

pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
    use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};

    if let Some(path) = strip_prefix(path, r"\\") {
        // \\
        if let Some(path) = strip_prefix(path, r"?\") {
            // \\?\
            if let Some(path) = strip_prefix(path, r"UNC\") {
                // \\?\UNC\server\share

                let (server, path) = parse_next_component(path, true);
                let (share, _) = parse_next_component(path, true);

                Some(VerbatimUNC(server, share))
            } else {
                let (prefix, _) = parse_next_component(path, true);

                // in verbatim paths only recognize an exact drive prefix
                if let Some(drive) = parse_drive_exact(prefix) {
                    // \\?\C:
                    Some(VerbatimDisk(drive))
                } else {
                    // \\?\prefix
                    Some(Verbatim(prefix))
                }
            }
        } else if let Some(path) = strip_prefix(path, r".\") {
            // \\.\COM42
            let (prefix, _) = parse_next_component(path, false);
            Some(DeviceNS(prefix))
        } else {
            let (server, path) = parse_next_component(path, false);
            let (share, _) = parse_next_component(path, false);

            if !server.is_empty() && !share.is_empty() {
                // \\server\share
                Some(UNC(server, share))
            } else {
                // no valid prefix beginning with "\\" recognized
                None
            }
        }
    } else if let Some(drive) = parse_drive(path) {
        // C:
        Some(Disk(drive))
    } else {
        // no prefix
        None
    }
}

// Parses a drive prefix, e.g. "C:" and "C:\whatever"
fn parse_drive(prefix: &OsStr) -> Option<u8> {
    // In most DOS systems, it is not possible to have more than 26 drive letters.
    // See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>.
    fn is_valid_drive_letter(drive: &u8) -> bool {
        drive.is_ascii_alphabetic()
    }

    match prefix.bytes() {
        [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
        _ => None,
    }
}

// Parses a drive prefix exactly, e.g. "C:"
fn parse_drive_exact(prefix: &OsStr) -> Option<u8> {
    // only parse two bytes: the drive letter and the drive separator
    if prefix.len() == 2 { parse_drive(prefix) } else { None }
}

fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> {
    // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]`
    // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice.
    match path.bytes().strip_prefix(prefix.as_bytes()) {
        Some(path) => unsafe { Some(bytes_as_os_str(path)) },
        None => None,
    }
}

// Parse the next path component.
//
// Returns the next component and the rest of the path excluding the component and separator.
// Does not recognize `/` as a separator character if `verbatim` is true.
fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
    let separator = if verbatim { is_verbatim_sep } else { is_sep_byte };

    match path.bytes().iter().position(|&x| separator(x)) {
        Some(separator_start) => {
            let mut separator_end = separator_start + 1;

            // a series of multiple separator characters is treated as a single separator,
            // except in verbatim paths
            while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end])
            {
                separator_end += 1;
            }

            let component = &path.bytes()[..separator_start];

            // Panic safe
            // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index.
            let path = &path.bytes()[separator_end..];

            // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
            // is encoded in a single byte, therefore `bytes[separator_start]` and
            // `bytes[separator_end]` must be code point boundaries and thus
            // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices.
            unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) }
        }
        None => (path, OsStr::new("")),
    }
}

/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
///
/// This path may or may not have a verbatim prefix.
pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
    // Normally the MAX path is 260 UTF-16 code units (including the NULL).
    // However, for APIs such as CreateDirectory[1], the limit is 248.
    //
    // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
    const LEGACY_MAX_PATH: usize = 248;
    // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
    // All of these are in the ASCII range so they can be cast directly to `u16`.
    const SEP: u16 = b'\\' as _;
    const ALT_SEP: u16 = b'/' as _;
    const QUERY: u16 = b'?' as _;
    const COLON: u16 = b':' as _;
    const DOT: u16 = b'.' as _;
    const U: u16 = b'U' as _;
    const N: u16 = b'N' as _;
    const C: u16 = b'C' as _;

    // \\?\
    const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP];
    // \??\
    const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP];
    // \\?\UNC\
    const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];

    let mut path = to_u16s(path)?;
    if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) {
        // Early return for paths that are already verbatim.
        return Ok(path);
    } else if path.len() < LEGACY_MAX_PATH {
        // Early return if an absolute path is less < 260 UTF-16 code units.
        // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily.
        match path.as_slice() {
            // Starts with `D:`, `D:\`, `D:/`, etc.
            // Does not match if the path starts with a `\` or `/`.
            [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..]
                if *drive != SEP && *drive != ALT_SEP =>
            {
                return Ok(path);
            }
            // Starts with `\\`, `//`, etc
            [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path),
            _ => {}
        }
    }

    // Firstly, get the absolute path using `GetFullPathNameW`.
    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
    let lpfilename = path.as_ptr();
    fill_utf16_buf(
        // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
        // `lpfilename` is a pointer to a null terminated string that is not
        // invalidated until after `GetFullPathNameW` returns successfully.
        |buffer, size| unsafe {
            // While the docs for `GetFullPathNameW` have the standard note
            // about needing a `\\?\` path for a long lpfilename, this does not
            // appear to be true in practice.
            // See:
            // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
            // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
            c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
        },
        |mut absolute| {
            path.clear();

            // Secondly, add the verbatim prefix. This is easier here because we know the
            // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
            let prefix = match absolute {
                // C:\ => \\?\C:\
                [_, COLON, SEP, ..] => VERBATIM_PREFIX,
                // \\.\ => \\?\
                [SEP, SEP, DOT, SEP, ..] => {
                    absolute = &absolute[4..];
                    VERBATIM_PREFIX
                }
                // Leave \\?\ and \??\ as-is.
                [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
                // \\ => \\?\UNC\
                [SEP, SEP, ..] => {
                    absolute = &absolute[2..];
                    UNC_PREFIX
                }
                // Anything else we leave alone.
                _ => &[],
            };

            path.reserve_exact(prefix.len() + absolute.len() + 1);
            path.extend_from_slice(prefix);
            path.extend_from_slice(absolute);
            path.push(0);
        },
    )?;
    Ok(path)
}
<commit_msg>Fix typo<commit_after>use super::{c, fill_utf16_buf, to_u16s};
use crate::ffi::OsStr;
use crate::io;
use crate::mem;
use crate::path::Path;
use crate::path::Prefix;
use crate::ptr;

#[cfg(test)]
mod tests;

pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';

/// # Safety
///
/// `bytes` must be a valid wtf8 encoded slice
#[inline]
unsafe fn bytes_as_os_str(bytes: &[u8]) -> &OsStr {
    // &OsStr is layout compatible with &Slice, which is compatible with &Wtf8,
    // which is compatible with &[u8].
    mem::transmute(bytes)
}

#[inline]
pub fn is_sep_byte(b: u8) -> bool {
    b == b'/' || b == b'\\'
}

#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
    b == b'\\'
}

pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
    use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};

    if let Some(path) = strip_prefix(path, r"\\") {
        // \\
        if let Some(path) = strip_prefix(path, r"?\") {
            // \\?\
            if let Some(path) = strip_prefix(path, r"UNC\") {
                // \\?\UNC\server\share

                let (server, path) = parse_next_component(path, true);
                let (share, _) = parse_next_component(path, true);

                Some(VerbatimUNC(server, share))
            } else {
                let (prefix, _) = parse_next_component(path, true);

                // in verbatim paths only recognize an exact drive prefix
                if let Some(drive) = parse_drive_exact(prefix) {
                    // \\?\C:
                    Some(VerbatimDisk(drive))
                } else {
                    // \\?\prefix
                    Some(Verbatim(prefix))
                }
            }
        } else if let Some(path) = strip_prefix(path, r".\") {
            // \\.\COM42
            let (prefix, _) = parse_next_component(path, false);
            Some(DeviceNS(prefix))
        } else {
            let (server, path) = parse_next_component(path, false);
            let (share, _) = parse_next_component(path, false);

            if !server.is_empty() && !share.is_empty() {
                // \\server\share
                Some(UNC(server, share))
            } else {
                // no valid prefix beginning with "\\" recognized
                None
            }
        }
    } else if let Some(drive) = parse_drive(path) {
        // C:
        Some(Disk(drive))
    } else {
        // no prefix
        None
    }
}

// Parses a drive prefix, e.g. "C:" and "C:\whatever"
fn parse_drive(prefix: &OsStr) -> Option<u8> {
    // In most DOS systems, it is not possible to have more than 26 drive letters.
    // See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>.
    fn is_valid_drive_letter(drive: &u8) -> bool {
        drive.is_ascii_alphabetic()
    }

    match prefix.bytes() {
        [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
        _ => None,
    }
}

// Parses a drive prefix exactly, e.g. "C:"
fn parse_drive_exact(prefix: &OsStr) -> Option<u8> {
    // only parse two bytes: the drive letter and the drive separator
    if prefix.len() == 2 { parse_drive(prefix) } else { None }
}

fn strip_prefix<'a>(path: &'a OsStr, prefix: &str) -> Option<&'a OsStr> {
    // `path` and `prefix` are valid wtf8 and utf8 encoded slices respectively, `path[prefix.len()]`
    // is thus a code point boundary and `path[prefix.len()..]` is a valid wtf8 encoded slice.
    match path.bytes().strip_prefix(prefix.as_bytes()) {
        Some(path) => unsafe { Some(bytes_as_os_str(path)) },
        None => None,
    }
}

// Parse the next path component.
//
// Returns the next component and the rest of the path excluding the component and separator.
// Does not recognize `/` as a separator character if `verbatim` is true.
fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
    let separator = if verbatim { is_verbatim_sep } else { is_sep_byte };

    match path.bytes().iter().position(|&x| separator(x)) {
        Some(separator_start) => {
            let mut separator_end = separator_start + 1;

            // a series of multiple separator characters is treated as a single separator,
            // except in verbatim paths
            while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end])
            {
                separator_end += 1;
            }

            let component = &path.bytes()[..separator_start];

            // Panic safe
            // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index.
            let path = &path.bytes()[separator_end..];

            // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
            // is encoded in a single byte, therefore `bytes[separator_start]` and
            // `bytes[separator_end]` must be code point boundaries and thus
            // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices.
            unsafe { (bytes_as_os_str(component), bytes_as_os_str(path)) }
        }
        None => (path, OsStr::new("")),
    }
}

/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
///
/// This path may or may not have a verbatim prefix.
pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
    // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
    // However, for APIs such as CreateDirectory[1], the limit is 248.
    //
    // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
    const LEGACY_MAX_PATH: usize = 248;
    // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
    // All of these are in the ASCII range so they can be cast directly to `u16`.
    const SEP: u16 = b'\\' as _;
    const ALT_SEP: u16 = b'/' as _;
    const QUERY: u16 = b'?' as _;
    const COLON: u16 = b':' as _;
    const DOT: u16 = b'.' as _;
    const U: u16 = b'U' as _;
    const N: u16 = b'N' as _;
    const C: u16 = b'C' as _;

    // \\?\
    const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP];
    // \??\
    const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP];
    // \\?\UNC\
    const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];

    let mut path = to_u16s(path)?;
    if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) {
        // Early return for paths that are already verbatim.
        return Ok(path);
    } else if path.len() < LEGACY_MAX_PATH {
        // Early return if an absolute path is less < 260 UTF-16 code units.
        // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily.
        match path.as_slice() {
            // Starts with `D:`, `D:\`, `D:/`, etc.
            // Does not match if the path starts with a `\` or `/`.
            [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..]
                if *drive != SEP && *drive != ALT_SEP =>
            {
                return Ok(path);
            }
            // Starts with `\\`, `//`, etc
            [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path),
            _ => {}
        }
    }

    // Firstly, get the absolute path using `GetFullPathNameW`.
    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
    let lpfilename = path.as_ptr();
    fill_utf16_buf(
        // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
        // `lpfilename` is a pointer to a null terminated string that is not
        // invalidated until after `GetFullPathNameW` returns successfully.
        |buffer, size| unsafe {
            // While the docs for `GetFullPathNameW` have the standard note
            // about needing a `\\?\` path for a long lpfilename, this does not
            // appear to be true in practice.
            // See:
            // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
            // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
            c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
        },
        |mut absolute| {
            path.clear();

            // Secondly, add the verbatim prefix. This is easier here because we know the
            // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
            let prefix = match absolute {
                // C:\ => \\?\C:\
                [_, COLON, SEP, ..] => VERBATIM_PREFIX,
                // \\.\ => \\?\
                [SEP, SEP, DOT, SEP, ..] => {
                    absolute = &absolute[4..];
                    VERBATIM_PREFIX
                }
                // Leave \\?\ and \??\ as-is.
                [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
                // \\ => \\?\UNC\
                [SEP, SEP, ..] => {
                    absolute = &absolute[2..];
                    UNC_PREFIX
                }
                // Anything else we leave alone.
                _ => &[],
            };

            path.reserve_exact(prefix.len() + absolute.len() + 1);
            path.extend_from_slice(prefix);
            path.extend_from_slice(absolute);
            path.push(0);
        },
    )?;
    Ok(path)
}
<|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 eutil::fptr_is_null;
use libc::{c_int};
use std::mem;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_list_t,cef_string_t};

//cef_string_list

#[no_mangle]
extern "C" fn cef_string_list_alloc() -> *mut cef_string_list_t {
    unsafe {
         let lt: Box<Vec<*mut cef_string_t>> = box vec!();
         mem::transmute(lt)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_size(lt: *const cef_string_list_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        v.len() as c_int
    }
}

#[no_mangle]
extern "C" fn cef_string_list_append(lt: *mut cef_string_list_t, value: *const cef_string_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        let cs = cef_string_userfree_utf8_alloc();
        cef_string_utf8_set(mem::transmute((*value).str), (*value).length, cs, 1);
        v.push(cs);
    }
}

#[no_mangle]
extern "C" fn cef_string_list_value(lt: *mut cef_string_list_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if index as uint > v.len() - 1 { return 0; }
        let cs = v.get(index as uint);
        cef_string_utf8_set(mem::transmute((**cs).str), (**cs).length, value, 1)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_clear(lt: *mut cef_string_list_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if v.len() == 0 { return; }
        let mut cs;
        while v.len() != 0 {
            cs = v.pop();
            cef_string_userfree_utf8_free(cs.unwrap());
        }
    }
}
<commit_msg>embedding: cef_string_list_free()<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 eutil::fptr_is_null;
use libc::{c_int};
use std::mem;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_list_t,cef_string_t};

//cef_string_list

#[no_mangle]
extern "C" fn cef_string_list_alloc() -> *mut cef_string_list_t {
    unsafe {
         let lt: Box<Vec<*mut cef_string_t>> = box vec!();
         mem::transmute(lt)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_size(lt: *const cef_string_list_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        v.len() as c_int
    }
}

#[no_mangle]
extern "C" fn cef_string_list_append(lt: *mut cef_string_list_t, value: *const cef_string_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        let cs = cef_string_userfree_utf8_alloc();
        cef_string_utf8_set(mem::transmute((*value).str), (*value).length, cs, 1);
        v.push(cs);
    }
}

#[no_mangle]
extern "C" fn cef_string_list_value(lt: *mut cef_string_list_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(lt)) { return 0; }
        let v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if index as uint > v.len() - 1 { return 0; }
        let cs = v.get(index as uint);
        cef_string_utf8_set(mem::transmute((**cs).str), (**cs).length, value, 1)
    }
}

#[no_mangle]
extern "C" fn cef_string_list_clear(lt: *mut cef_string_list_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        if v.len() == 0 { return; }
        let mut cs;
        while v.len() != 0 {
            cs = v.pop();
            cef_string_userfree_utf8_free(cs.unwrap());
        }
    }
}

#[no_mangle]
extern "C" fn cef_string_list_free(lt: *mut cef_string_list_t) {
    unsafe {
        if fptr_is_null(mem::transmute(lt)) { return; }
        let mut v: Box<Vec<*mut cef_string_t>> = mem::transmute(lt);
        cef_string_list_clear(lt);
        drop(v);
    }
}
<|endoftext|>


<commit_before>use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};

use std::collections::{HashMap, HashSet};
use std::{fmt, fs};

const SIN: [i32; 4] = [0, 1, 0, -1];
const COS: [i32; 4] = [1, 0, -1, 0];

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct PuzzleDense {
    data: [[[i32; 3]; 3]; 3],
}

impl fmt::Display for PuzzleDense {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.data[0])?;
        writeln!(f, "{:?}", self.data[1])?;
        writeln!(f, "{:?}", self.data[2])
    }
}

pub type Piece = Vec<[i32; 3]>;

#[derive(Debug, Deserialize, Serialize)]
pub struct Pieces {
    pub data: Puzzle,
}

pub type Puzzle = Vec<Piece>;

pub fn solve(puzzle: Puzzle) {
    let pieces = push_to_zero(puzzle);
    for piece in &pieces {
        for part in piece {
            println!("{:?}", part);
        }
        println!();
    }

    let zero = vec![PuzzleDense { data: zeros() }];

    let mut solutions = Vec::new();
    for (i, piece) in pieces.iter().enumerate() {
        if i == 0 {
            solutions = all_puts(zero.clone(), (i + 1) as i32, piece);
        } else {
            solutions = all_rotations_and_puts(solutions.clone(), (i + 1) as i32, piece);
        }
    }

    let solutions = unique_pieces(solutions);
    for solution in solutions {
        println!("{:}", solution);
    }
}

fn unique_pieces(puzzles: Vec<PuzzleDense>) -> Vec<PuzzleDense> {
    let mut puzzles_unique = HashSet::new();
    for mut puzzle in puzzles {
        let mut puzzle_unique: HashMap<i32, i32> = HashMap::new();
        let mut piece_count = 0;
        for x in 0..3 {
            for y in 0..3 {
                for z in 0..3 {
                    let value = puzzle.data[x][y][z];
                    if puzzle_unique.contains_key(&value) {
                        puzzle.data[x][y][z] = puzzle_unique[&value]
                    } else {
                        piece_count += 1;
                        puzzle_unique.insert(value, piece_count);
                        puzzle.data[x][y][z] = puzzle_unique[&value]
                    }
                }
            }
        }
        puzzles_unique.insert(puzzle);
    }

    let mut all_puzzles = Vec::new();
    for puzzle in puzzles_unique {
        all_puzzles.push(puzzle);
    }
    all_puzzles
}

fn all_rotations_and_puts(
    already_placed: Vec<PuzzleDense>,
    piece_count: i32,
    piece: &Piece,
) -> Vec<PuzzleDense> {
    let mut solutions = Vec::new();
    for rotation in all_rotations(piece) {
        for s in all_puts(already_placed.clone(), piece_count, &rotation) {
            solutions.push(s);
        }
    }
    solutions
}

fn all_rotations(piece: &Piece) -> Vec<Vec<[i32; 3]>> {
    let mut all_rots = Vec::new();
    for theta in 0..4 {
        let mut rotations = Vec::new();
        for [x, y, z] in piece {
            let rotated_z = [
                x * COS[theta] - y * SIN[theta],
                x * SIN[theta] + y * COS[theta],
                *z,
            ];
            rotations.push(rotated_z);
        }
        all_rots.push(rotations);
    }

    let mut all_rotss = all_rots.clone();
    for piece in &all_rots {
        for theta in 0..4 {
            let mut rotations = Vec::new();
            for [x, y, z] in piece {
                let rotated_yz = [
                    x * COS[theta] + z * SIN[theta],
                    *y,
                    -x * SIN[theta] + z * COS[theta],
                ];
                rotations.push(rotated_yz);
            }
            all_rotss.push(rotations);
        }
    }

    let mut all_rotsss = all_rotss.clone();
    for piece in &all_rotss {
        for theta in 0..4 {
            let mut rotations = Vec::new();
            for [x, y, z] in piece {
                let rotated_xyz = [
                    *x,
                    y * COS[theta] - z * SIN[theta],
                    y * SIN[theta] + z * COS[theta],
                ];
                rotations.push(rotated_xyz);
            }
            all_rotsss.push(rotations)
        }
    }

    let mut unique_solutions = HashSet::new();
    let rots = push_to_zero(all_rotsss);
    for mut solution in rots {
        solution.sort();
        unique_solutions.insert(solution);
    }

    let mut rotations = Vec::new();
    for solution in unique_solutions {
        rotations.push(solution);
    }
    rotations
}

fn max_xyz(piece: &Piece) -> (i32, i32, i32) {
    let mut max_x = -1;
    let mut max_y = -1;
    let mut max_z = -1;

    for [x, y, z] in piece {
        if x > &max_x {
            max_x = *x;
        }
        if y > &max_y {
            max_y = *y;
        }
        if z > &max_z {
            max_z = *z;
        }
    }
    (max_x, max_y, max_z)
}

fn all_puts(already_placed: Vec<PuzzleDense>, piece_count: i32, piece: &Piece) -> Vec<PuzzleDense> {
    let mut all_solutions = Vec::new();
    let (max_x, max_y, max_z) = max_xyz(piece);

    for x_step in 0..3 - max_x {
        for y_step in 0..3 - max_y {
            for z_step in 0..3 - max_z {
                let already_placed = already_placed.clone();
                'next_piece: for mut puzzle in already_placed {
                    for [x, y, z] in piece {
                        if puzzle.data[(x + x_step) as usize][(y + y_step) as usize]
                            [(z + z_step) as usize]
                            > 0
                        {
                            continue 'next_piece;
                        }
                    }

                    for [x, y, z] in piece {
                        puzzle.data[(x + x_step) as usize][(y + y_step) as usize]
                            [(z + z_step) as usize] = piece_count;
                    }

                    all_solutions.push(puzzle);
                }
            }
        }
    }

    all_solutions
}

fn zeros() -> [[[i32; 3]; 3]; 3] {
    [
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
    ]
}

fn push_to_zero(puzzle: Puzzle) -> Puzzle {
    let mut pieces = Vec::new();

    for part in &puzzle {
        let mut piece = Vec::new();
        let mut min_x = 99;
        let mut min_y = 99;
        let mut min_z = 99;

        for [x, y, z] in part {
            if x < &min_x {
                min_x = *x;
            }
            if y < &min_y {
                min_y = *y;
            }
            if z < &min_z {
                min_z = *z;
            }
        }
        for [x, y, z] in part {
            piece.push([x - min_x, y - min_y, z - min_z]);
        }

        pieces.push(piece);
    }

    pieces
}

/// Program to display the 3x3 cube solution(s).
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    /// What puzzle to solve.
    #[arg(value_enum, default_value_t = PuzzleOption::Minotaur)]
    puzzle: PuzzleOption,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum PuzzleOption {
    /// blue
    Blue,
    /// green
    Green,
    /// minotaur
    Minotaur,
    /// orange
    Orange,
    /// red
    Red,
    /// white
    White,
    /// yellow
    Yellow,
}

pub fn choose_puzzle() -> Puzzle {
    let cli = Cli::parse();

    let name = match cli.puzzle {
        PuzzleOption::Blue => "blue",
        PuzzleOption::Green => "green",
        PuzzleOption::Minotaur => "minotaur",
        PuzzleOption::Orange => "orange",
        PuzzleOption::Red => "red",
        PuzzleOption::White => "white",
        PuzzleOption::Yellow => "yellow",
    };

    let decoded: Pieces = bincode::deserialize(&fs::read(format!("puzzles/{}", name)).unwrap()).unwrap();
    decoded.data
}

pub fn get_puzzle(puzzle: &str) -> Puzzle {
    let decoded: Pieces = bincode::deserialize(&fs::read(format!("puzzles/{}", puzzle)).unwrap()).unwrap();
    decoded.data
}<commit_msg>Replace green with todo.<commit_after>use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};

use std::collections::{HashMap, HashSet};
use std::{fmt, fs};

const SIN: [i32; 4] = [0, 1, 0, -1];
const COS: [i32; 4] = [1, 0, -1, 0];

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct PuzzleDense {
    data: [[[i32; 3]; 3]; 3],
}

impl fmt::Display for PuzzleDense {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.data[0])?;
        writeln!(f, "{:?}", self.data[1])?;
        writeln!(f, "{:?}", self.data[2])
    }
}

pub type Piece = Vec<[i32; 3]>;

#[derive(Debug, Deserialize, Serialize)]
pub struct Pieces {
    pub data: Puzzle,
}

pub type Puzzle = Vec<Piece>;

pub fn solve(puzzle: Puzzle) {
    let pieces = push_to_zero(puzzle);
    for piece in &pieces {
        for part in piece {
            println!("{:?}", part);
        }
        println!();
    }

    let zero = vec![PuzzleDense { data: zeros() }];

    let mut solutions = Vec::new();
    for (i, piece) in pieces.iter().enumerate() {
        if i == 0 {
            solutions = all_puts(zero.clone(), (i + 1) as i32, piece);
        } else {
            solutions = all_rotations_and_puts(solutions.clone(), (i + 1) as i32, piece);
        }
    }

    let solutions = unique_pieces(solutions);
    for solution in solutions {
        println!("{:}", solution);
    }
}

fn unique_pieces(puzzles: Vec<PuzzleDense>) -> Vec<PuzzleDense> {
    let mut puzzles_unique = HashSet::new();
    for mut puzzle in puzzles {
        let mut puzzle_unique: HashMap<i32, i32> = HashMap::new();
        let mut piece_count = 0;
        for x in 0..3 {
            for y in 0..3 {
                for z in 0..3 {
                    let value = puzzle.data[x][y][z];
                    if puzzle_unique.contains_key(&value) {
                        puzzle.data[x][y][z] = puzzle_unique[&value]
                    } else {
                        piece_count += 1;
                        puzzle_unique.insert(value, piece_count);
                        puzzle.data[x][y][z] = puzzle_unique[&value]
                    }
                }
            }
        }
        puzzles_unique.insert(puzzle);
    }

    let mut all_puzzles = Vec::new();
    for puzzle in puzzles_unique {
        all_puzzles.push(puzzle);
    }
    all_puzzles
}

fn all_rotations_and_puts(
    already_placed: Vec<PuzzleDense>,
    piece_count: i32,
    piece: &Piece,
) -> Vec<PuzzleDense> {
    let mut solutions = Vec::new();
    for rotation in all_rotations(piece) {
        for s in all_puts(already_placed.clone(), piece_count, &rotation) {
            solutions.push(s);
        }
    }
    solutions
}

fn all_rotations(piece: &Piece) -> Vec<Vec<[i32; 3]>> {
    let mut all_rots = Vec::new();
    for theta in 0..4 {
        let mut rotations = Vec::new();
        for [x, y, z] in piece {
            let rotated_z = [
                x * COS[theta] - y * SIN[theta],
                x * SIN[theta] + y * COS[theta],
                *z,
            ];
            rotations.push(rotated_z);
        }
        all_rots.push(rotations);
    }

    let mut all_rotss = all_rots.clone();
    for piece in &all_rots {
        for theta in 0..4 {
            let mut rotations = Vec::new();
            for [x, y, z] in piece {
                let rotated_yz = [
                    x * COS[theta] + z * SIN[theta],
                    *y,
                    -x * SIN[theta] + z * COS[theta],
                ];
                rotations.push(rotated_yz);
            }
            all_rotss.push(rotations);
        }
    }

    let mut all_rotsss = all_rotss.clone();
    for piece in &all_rotss {
        for theta in 0..4 {
            let mut rotations = Vec::new();
            for [x, y, z] in piece {
                let rotated_xyz = [
                    *x,
                    y * COS[theta] - z * SIN[theta],
                    y * SIN[theta] + z * COS[theta],
                ];
                rotations.push(rotated_xyz);
            }
            all_rotsss.push(rotations)
        }
    }

    let mut unique_solutions = HashSet::new();
    let rots = push_to_zero(all_rotsss);
    for mut solution in rots {
        solution.sort();
        unique_solutions.insert(solution);
    }

    let mut rotations = Vec::new();
    for solution in unique_solutions {
        rotations.push(solution);
    }
    rotations
}

fn max_xyz(piece: &Piece) -> (i32, i32, i32) {
    let mut max_x = -1;
    let mut max_y = -1;
    let mut max_z = -1;

    for [x, y, z] in piece {
        if x > &max_x {
            max_x = *x;
        }
        if y > &max_y {
            max_y = *y;
        }
        if z > &max_z {
            max_z = *z;
        }
    }
    (max_x, max_y, max_z)
}

fn all_puts(already_placed: Vec<PuzzleDense>, piece_count: i32, piece: &Piece) -> Vec<PuzzleDense> {
    let mut all_solutions = Vec::new();
    let (max_x, max_y, max_z) = max_xyz(piece);

    for x_step in 0..3 - max_x {
        for y_step in 0..3 - max_y {
            for z_step in 0..3 - max_z {
                let already_placed = already_placed.clone();
                'next_piece: for mut puzzle in already_placed {
                    for [x, y, z] in piece {
                        if puzzle.data[(x + x_step) as usize][(y + y_step) as usize]
                            [(z + z_step) as usize]
                            > 0
                        {
                            continue 'next_piece;
                        }
                    }

                    for [x, y, z] in piece {
                        puzzle.data[(x + x_step) as usize][(y + y_step) as usize]
                            [(z + z_step) as usize] = piece_count;
                    }

                    all_solutions.push(puzzle);
                }
            }
        }
    }

    all_solutions
}

fn zeros() -> [[[i32; 3]; 3]; 3] {
    [
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
        [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
    ]
}

fn push_to_zero(puzzle: Puzzle) -> Puzzle {
    let mut pieces = Vec::new();

    for part in &puzzle {
        let mut piece = Vec::new();
        let mut min_x = 99;
        let mut min_y = 99;
        let mut min_z = 99;

        for [x, y, z] in part {
            if x < &min_x {
                min_x = *x;
            }
            if y < &min_y {
                min_y = *y;
            }
            if z < &min_z {
                min_z = *z;
            }
        }
        for [x, y, z] in part {
            piece.push([x - min_x, y - min_y, z - min_z]);
        }

        pieces.push(piece);
    }

    pieces
}

/// Program to display the 3x3 cube solution(s).
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    /// What puzzle to solve.
    #[arg(value_enum, default_value_t = PuzzleOption::Minotaur)]
    puzzle: PuzzleOption,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum PuzzleOption {
    /// blue
    Blue,
    /// green
    Green,
    /// minotaur
    Minotaur,
    /// orange
    Orange,
    /// red
    Red,
    /// white
    White,
    /// yellow
    Yellow,
}

pub fn choose_puzzle() -> Puzzle {
    let cli = Cli::parse();

    let name = match cli.puzzle {
        PuzzleOption::Blue => "blue",
        PuzzleOption::Green => todo!(),
        PuzzleOption::Minotaur => "minotaur",
        PuzzleOption::Orange => "orange",
        PuzzleOption::Red => "red",
        PuzzleOption::White => "white",
        PuzzleOption::Yellow => "yellow",
    };

    let decoded: Pieces = bincode::deserialize(&fs::read(format!("puzzles/{}", name)).unwrap()).unwrap();
    decoded.data
}

pub fn get_puzzle(puzzle: &str) -> Puzzle {
    let decoded: Pieces = bincode::deserialize(&fs::read(format!("puzzles/{}", puzzle)).unwrap()).unwrap();
    decoded.data
}<|endoftext|>


<commit_before>use protobuf::Message;

use protobuf_test_common::*;

use super::test_fmt_text_format_pb::*;
use protobuf::text_format::print_to_string;
use protobuf::prelude::MessageField;

#[test]
fn test_show() {
    let mut m = TestTypes::new();
    m.set_bool_singular(true);
    assert_eq!("bool_singular: true", &*format!("{:?}", m));
}

#[test]
fn test_pretty() {
    let mut tm = TestMessage::new();
    tm.set_value(23);
    let mut m = TestTypes::new();
    m.set_test_message_singular(tm);
    m.set_string_singular("abc".to_string());
    m.mut_string_repeated().push("def".to_string());
    m.mut_string_repeated().push("ghi".to_string());
    assert_eq!(
        "string_singular: \"abc\"\ntest_message_singular {\n  value: 23\n}\nstring_repeated: \"def\"\nstring_repeated: \"ghi\"\n",
        &*format!("{:#?}", m)
    );
}

#[test]
fn test_rust_identifier() {
    let mut m = TestTextFormatRustIdentifier::new();
    m.set_field_const(true);
    assert_eq!("const: true", &*format!("{:?}", m));
}

#[test]
fn test_empty() {
    test_text_format_str_descriptor("", TestTypes::descriptor_static());
}

#[test]
fn test_enum() {
    test_text_format_str_descriptor("test_enum_singular: DARK", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_enum_repeated: DARK test_enum_repeated: LIGHT test_enum_repeated: LIGHT",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_int() {
    test_text_format_str_descriptor("uint32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("uint64_singular: 100", TestTypes::descriptor_static());

    test_text_format_str_descriptor("int32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int32_singular: -98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int64_singular: -100", TestTypes::descriptor_static());

    test_text_format_str_descriptor("fixed32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("fixed64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed32_singular: -98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed64_singular: -100", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "int32_repeated: 98 int32_repeated: -99",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_parse_float() {
    test_text_format_str_descriptor("float_singular: 98.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("float_singular: -99.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("float_singular: -99", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: 98.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: -99.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: 99", TestTypes::descriptor_static());
}

#[test]
fn test_bool() {
    test_text_format_str_descriptor("bool_singular: true", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bool_singular: false", TestTypes::descriptor_static());
    test_text_format_str_descriptor(
        "bool_repeated: false bool_repeated: false bool_repeated: true",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_string_bytes() {
    test_text_format_str_descriptor("string_singular: \"\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("string_singular: \"a b\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("string_singular: \"a\\nb\"", TestTypes::descriptor_static());

    test_text_format_str_descriptor("bytes_singular: \"\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bytes_singular: \"a b\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bytes_singular: \"a\\nb\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor(
        "bytes_singular: \"a\\xfeb\"",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "string_repeated: \"ab\" bytes_repeated: \"cd\" string_repeated: \"ef\"",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "string_singular: \"quote\\\"newline\\nbackslash\\\\del\\177\"",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_message() {
    test_text_format_str_descriptor("test_message_singular {}", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_message_singular { value: 10 }",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "test_message_repeated { value: 10 } test_message_repeated { value: 20 }",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor("test_message_singular <>", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_message_singular < value: 10 >",
        TestTypes::descriptor_static()
    );
}

#[test]
fn test_map_keys_sorted() {
    // TODO
    // When generating text format for a .proto, maps are sorted by key.
    // Numeric keys are sorted numerically.
}

#[test]
fn test_reflect() {
    for m in special_messages_typed::<TestTypes>() {
        test_text_format_message(&m);
        // This slow test is equivalent to the fast test below.
        // Do just one iteration as smoke test.
        // `break` statement can be commented out for easier debugging.
        break;
    }

    let mut l = TestTypesList::new();
    // TODO: make `ts` field public in codegen
    l.set_ts(special_messages_typed().into());
    test_text_format_message(&l);
}

#[test]
fn test_parse_error() {
    let e = protobuf::text_format::parse_from_str::<TestTypes>("nonexistent: 42").unwrap_err();
    let _error: &dyn std::error::Error = &e;
    assert_eq!(e.to_string(), "1:1: UnknownField(\"nonexistent\")");
}

fn t<F: FnMut(&mut TestTypes)>(expected: &str, mut setter: F) {
    let mut m = TestTypes::new();
    setter(&mut m);
    assert_eq!(&*print_to_string(&m), expected);
}

#[test]
fn test_singular() {
    t("int32_singular: 99", |m| m.set_int32_singular(99));
    t("double_singular: 99", |m| m.set_double_singular(99.0));
    t("float_singular: 99", |m| m.set_float_singular(99.0));
    t("int32_singular: 99", |m| m.set_int32_singular(99));
    t("int64_singular: 99", |m| m.set_int64_singular(99));
    t("uint32_singular: 99", |m| m.set_uint32_singular(99));
    t("uint64_singular: 99", |m| m.set_uint64_singular(99));
    t("sint32_singular: 99", |m| m.set_sint32_singular(99));
    t("sint64_singular: 99", |m| m.set_sint64_singular(99));
    t("fixed32_singular: 99", |m| m.set_fixed32_singular(99));
    t("fixed64_singular: 99", |m| m.set_fixed64_singular(99));
    t("sfixed32_singular: 99", |m| m.set_sfixed32_singular(99));
    t("sfixed64_singular: 99", |m| m.set_sfixed64_singular(99));
    t("bool_singular: true", |m| m.set_bool_singular(true));
    t("string_singular: \"abc\"", |m| {
        m.set_string_singular("abc".to_string())
    });
    t("bytes_singular: \"def\"", |m| {
        m.set_bytes_singular(b"def".to_vec())
    });
    t("test_enum_singular: DARK", |m| {
        m.set_test_enum_singular(TestEnum::DARK)
    });
    t("test_message_singular {}", |m| {
        m.test_message_singular.set_default();
    });
}

#[test]
fn test_repeated_one() {
    t("int32_repeated: 99", |m| m.int32_repeated.push(99));
    t("double_repeated: 99", |m| m.double_repeated.push(99.0));
    t("float_repeated: 99", |m| m.float_repeated.push(99.0));
    t("int32_repeated: 99", |m| m.int32_repeated.push(99));
    t("int64_repeated: 99", |m| m.int64_repeated.push(99));
    t("uint32_repeated: 99", |m| m.uint32_repeated.push(99));
    t("uint64_repeated: 99", |m| m.uint64_repeated.push(99));
    t("sint32_repeated: 99", |m| m.sint32_repeated.push(99));
    t("sint64_repeated: 99", |m| m.sint64_repeated.push(99));
    t("fixed32_repeated: 99", |m| m.fixed32_repeated.push(99));
    t("fixed64_repeated: 99", |m| m.fixed64_repeated.push(99));
    t("sfixed32_repeated: 99", |m| m.sfixed32_repeated.push(99));
    t("sfixed64_repeated: 99", |m| m.sfixed64_repeated.push(99));
    t("bool_repeated: false", |m| m.bool_repeated.push(false));
    t("string_repeated: \"abc\"", |m| {
        m.string_repeated.push("abc".to_string())
    });
    t("bytes_repeated: \"def\"", |m| {
        m.bytes_repeated.push(b"def".to_vec())
    });
    t("test_enum_repeated: DARK", |m| {
        m.test_enum_repeated.push(TestEnum::DARK.into())
    });
    t("test_message_repeated {}", |m| {
        m.test_message_repeated.push(Default::default());
    });
}

#[test]
fn test_repeated_multiple() {
    t(
        "uint32_singular: 30 int32_repeated: 10 int32_repeated: -20",
        |m| {
            m.set_uint32_singular(30);
            m.int32_repeated.push(10);
            m.int32_repeated.push(-20);
        },
    );
}

#[test]
fn test_complex_message() {
    t("test_message_singular {value: 30}", |m| {
        m.test_message_singular.mut_message().set_value(30)
    });
}

#[test]
fn test_string_escaped() {
    let mut m = TestTypes::new();
    m.set_string_singular("quote\"newline\nbackslash\\del\x7f".to_string());
    assert_eq!(
        "string_singular: \"quote\\\"newline\\nbackslash\\\\del\\177\"",
        &*format!("{:?}", m)
    );
}
<commit_msg>Add tests for mismatched message open and close symbols<commit_after>use protobuf::Message;

use protobuf_test_common::*;

use super::test_fmt_text_format_pb::*;
use protobuf::text_format::print_to_string;
use protobuf::prelude::MessageField;

#[test]
fn test_show() {
    let mut m = TestTypes::new();
    m.set_bool_singular(true);
    assert_eq!("bool_singular: true", &*format!("{:?}", m));
}

#[test]
fn test_pretty() {
    let mut tm = TestMessage::new();
    tm.set_value(23);
    let mut m = TestTypes::new();
    m.set_test_message_singular(tm);
    m.set_string_singular("abc".to_string());
    m.mut_string_repeated().push("def".to_string());
    m.mut_string_repeated().push("ghi".to_string());
    assert_eq!(
        "string_singular: \"abc\"\ntest_message_singular {\n  value: 23\n}\nstring_repeated: \"def\"\nstring_repeated: \"ghi\"\n",
        &*format!("{:#?}", m)
    );
}

#[test]
fn test_rust_identifier() {
    let mut m = TestTextFormatRustIdentifier::new();
    m.set_field_const(true);
    assert_eq!("const: true", &*format!("{:?}", m));
}

#[test]
fn test_empty() {
    test_text_format_str_descriptor("", TestTypes::descriptor_static());
}

#[test]
fn test_enum() {
    test_text_format_str_descriptor("test_enum_singular: DARK", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_enum_repeated: DARK test_enum_repeated: LIGHT test_enum_repeated: LIGHT",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_int() {
    test_text_format_str_descriptor("uint32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("uint64_singular: 100", TestTypes::descriptor_static());

    test_text_format_str_descriptor("int32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int32_singular: -98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("int64_singular: -100", TestTypes::descriptor_static());

    test_text_format_str_descriptor("fixed32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("fixed64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed32_singular: 98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed64_singular: 100", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed32_singular: -98", TestTypes::descriptor_static());
    test_text_format_str_descriptor("sfixed64_singular: -100", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "int32_repeated: 98 int32_repeated: -99",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_parse_float() {
    test_text_format_str_descriptor("float_singular: 98.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("float_singular: -99.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("float_singular: -99", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: 98.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: -99.5", TestTypes::descriptor_static());
    test_text_format_str_descriptor("double_singular: 99", TestTypes::descriptor_static());
}

#[test]
fn test_bool() {
    test_text_format_str_descriptor("bool_singular: true", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bool_singular: false", TestTypes::descriptor_static());
    test_text_format_str_descriptor(
        "bool_repeated: false bool_repeated: false bool_repeated: true",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_string_bytes() {
    test_text_format_str_descriptor("string_singular: \"\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("string_singular: \"a b\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("string_singular: \"a\\nb\"", TestTypes::descriptor_static());

    test_text_format_str_descriptor("bytes_singular: \"\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bytes_singular: \"a b\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor("bytes_singular: \"a\\nb\"", TestTypes::descriptor_static());
    test_text_format_str_descriptor(
        "bytes_singular: \"a\\xfeb\"",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "string_repeated: \"ab\" bytes_repeated: \"cd\" string_repeated: \"ef\"",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "string_singular: \"quote\\\"newline\\nbackslash\\\\del\\177\"",
        TestTypes::descriptor_static(),
    );
}

#[test]
fn test_message() {
    test_text_format_str_descriptor("test_message_singular {}", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_message_singular { value: 10 }",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor(
        "test_message_repeated { value: 10 } test_message_repeated { value: 20 }",
        TestTypes::descriptor_static(),
    );

    test_text_format_str_descriptor("test_message_singular <>", TestTypes::descriptor_static());

    test_text_format_str_descriptor(
        "test_message_singular < value: 10 >",
        TestTypes::descriptor_static(),
    );

    assert!(
        parse_using_rust_protobuf(
            "test_message_singular < value: 10 }",
            TestTypes::descriptor_static()
        )
        .is_err(),
        "Parsing a message with mismatched message start and terminator symbols should fail."
    );

    assert!(
        parse_using_rust_protobuf(
            "test_message_singular { value: 10 >",
            TestTypes::descriptor_static()
        )
        .is_err(),
        "Parsing a message with mismatched message start and terminator symbols should fail."
    );
}

#[test]
fn test_map_keys_sorted() {
    // TODO
    // When generating text format for a .proto, maps are sorted by key.
    // Numeric keys are sorted numerically.
}

#[test]
fn test_reflect() {
    for m in special_messages_typed::<TestTypes>() {
        test_text_format_message(&m);
        // This slow test is equivalent to the fast test below.
        // Do just one iteration as smoke test.
        // `break` statement can be commented out for easier debugging.
        break;
    }

    let mut l = TestTypesList::new();
    // TODO: make `ts` field public in codegen
    l.set_ts(special_messages_typed().into());
    test_text_format_message(&l);
}

#[test]
fn test_parse_error() {
    let e = protobuf::text_format::parse_from_str::<TestTypes>("nonexistent: 42").unwrap_err();
    let _error: &dyn std::error::Error = &e;
    assert_eq!(e.to_string(), "1:1: UnknownField(\"nonexistent\")");
}

fn t<F: FnMut(&mut TestTypes)>(expected: &str, mut setter: F) {
    let mut m = TestTypes::new();
    setter(&mut m);
    assert_eq!(&*print_to_string(&m), expected);
}

#[test]
fn test_singular() {
    t("int32_singular: 99", |m| m.set_int32_singular(99));
    t("double_singular: 99", |m| m.set_double_singular(99.0));
    t("float_singular: 99", |m| m.set_float_singular(99.0));
    t("int32_singular: 99", |m| m.set_int32_singular(99));
    t("int64_singular: 99", |m| m.set_int64_singular(99));
    t("uint32_singular: 99", |m| m.set_uint32_singular(99));
    t("uint64_singular: 99", |m| m.set_uint64_singular(99));
    t("sint32_singular: 99", |m| m.set_sint32_singular(99));
    t("sint64_singular: 99", |m| m.set_sint64_singular(99));
    t("fixed32_singular: 99", |m| m.set_fixed32_singular(99));
    t("fixed64_singular: 99", |m| m.set_fixed64_singular(99));
    t("sfixed32_singular: 99", |m| m.set_sfixed32_singular(99));
    t("sfixed64_singular: 99", |m| m.set_sfixed64_singular(99));
    t("bool_singular: true", |m| m.set_bool_singular(true));
    t("string_singular: \"abc\"", |m| {
        m.set_string_singular("abc".to_string())
    });
    t("bytes_singular: \"def\"", |m| {
        m.set_bytes_singular(b"def".to_vec())
    });
    t("test_enum_singular: DARK", |m| {
        m.set_test_enum_singular(TestEnum::DARK)
    });
    t("test_message_singular {}", |m| {
        m.test_message_singular.set_default();
    });
}

#[test]
fn test_repeated_one() {
    t("int32_repeated: 99", |m| m.int32_repeated.push(99));
    t("double_repeated: 99", |m| m.double_repeated.push(99.0));
    t("float_repeated: 99", |m| m.float_repeated.push(99.0));
    t("int32_repeated: 99", |m| m.int32_repeated.push(99));
    t("int64_repeated: 99", |m| m.int64_repeated.push(99));
    t("uint32_repeated: 99", |m| m.uint32_repeated.push(99));
    t("uint64_repeated: 99", |m| m.uint64_repeated.push(99));
    t("sint32_repeated: 99", |m| m.sint32_repeated.push(99));
    t("sint64_repeated: 99", |m| m.sint64_repeated.push(99));
    t("fixed32_repeated: 99", |m| m.fixed32_repeated.push(99));
    t("fixed64_repeated: 99", |m| m.fixed64_repeated.push(99));
    t("sfixed32_repeated: 99", |m| m.sfixed32_repeated.push(99));
    t("sfixed64_repeated: 99", |m| m.sfixed64_repeated.push(99));
    t("bool_repeated: false", |m| m.bool_repeated.push(false));
    t("string_repeated: \"abc\"", |m| {
        m.string_repeated.push("abc".to_string())
    });
    t("bytes_repeated: \"def\"", |m| {
        m.bytes_repeated.push(b"def".to_vec())
    });
    t("test_enum_repeated: DARK", |m| {
        m.test_enum_repeated.push(TestEnum::DARK.into())
    });
    t("test_message_repeated {}", |m| {
        m.test_message_repeated.push(Default::default());
    });
}

#[test]
fn test_repeated_multiple() {
    t(
        "uint32_singular: 30 int32_repeated: 10 int32_repeated: -20",
        |m| {
            m.set_uint32_singular(30);
            m.int32_repeated.push(10);
            m.int32_repeated.push(-20);
        },
    );
}

#[test]
fn test_complex_message() {
    t("test_message_singular {value: 30}", |m| {
        m.test_message_singular.mut_message().set_value(30)
    });
}

#[test]
fn test_string_escaped() {
    let mut m = TestTypes::new();
    m.set_string_singular("quote\"newline\nbackslash\\del\x7f".to_string());
    assert_eq!(
        "string_singular: \"quote\\\"newline\\nbackslash\\\\del\\177\"",
        &*format!("{:?}", m)
    );
}
<|endoftext|>


<commit_before>// Test that we don't duplicate storage for a variable that is moved to another
// binding. This used to happen in the presence of unwind and drop edges (see
// `complex` below.)
//
// The exact sizes here can change (we'd like to know when they do). What we
// don't want to see is the `complex` generator size being upwards of 2048 bytes
// (which would indicate it is reserving space for two copies of Foo.)
//
// See issue #59123 for a full explanation.

// edition:2018

#![feature(generators, generator_trait)]

use std::ops::Generator;

const FOO_SIZE: usize = 1024;
struct Foo([u8; FOO_SIZE]);

impl Drop for Foo {
    fn drop(&mut self) {}
}

fn move_before_yield() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        let _second = first;
        yield;
        // _second dropped here
    }
}

fn noop() {}

fn move_before_yield_with_noop() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        noop();
        let _second = first;
        yield;
        // _second dropped here
    }
}

// Today we don't have NRVO (we allocate space for both `first` and `second`,)
// but we can overlap `first` with `_third`.
fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        yield;
        let second = first;
        yield;
        let _third = second;
        yield;
    }
}

fn main() {
    assert_eq!(1028, std::mem::size_of_val(&move_before_yield()));
    assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop()));
    assert_eq!(2056, std::mem::size_of_val(&overlap_move_points()));
}
<commit_msg>Add tests for overlapping explicitly dropped locals in generators<commit_after>// Test that we don't duplicate storage for a variable that is moved to another
// binding. This used to happen in the presence of unwind and drop edges (see
// `complex` below.)
//
// The exact sizes here can change (we'd like to know when they do). What we
// don't want to see is the `complex` generator size being upwards of 2048 bytes
// (which would indicate it is reserving space for two copies of Foo.)
//
// See issue #59123 for a full explanation.

// edition:2018

#![feature(generators, generator_trait)]

use std::ops::Generator;

const FOO_SIZE: usize = 1024;
struct Foo([u8; FOO_SIZE]);

impl Drop for Foo {
    fn drop(&mut self) {}
}

fn move_before_yield() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        let _second = first;
        yield;
        // _second dropped here
    }
}

fn noop() {}

fn move_before_yield_with_noop() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        noop();
        let _second = first;
        yield;
        // _second dropped here
    }
}

// Today we don't have NRVO (we allocate space for both `first` and `second`,)
// but we can overlap `first` with `_third`.
fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
    static || {
        let first = Foo([0; FOO_SIZE]);
        yield;
        let second = first;
        yield;
        let _third = second;
        yield;
    }
}

fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()>{
    static || {
        let x = [0u8; 1024];
        yield;
        drop(x);
        let y = [0u8;1024];
        yield;
        drop(y);
    }
}

fn main() {
    assert_eq!(1028, std::mem::size_of_val(&move_before_yield()));
    assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop()));
    assert_eq!(2056, std::mem::size_of_val(&overlap_move_points()));
    assert_eq!(2052, std::mem::size_of_val(&overlap_x_and_y()));
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>Made test function for cd<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "cd"	=>  { self.changeDir(cmd_line); }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    //Justin's function for cd
    fn changeDir(&mut self, cmd_line: &str) {
	let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let pstring: ~str = argv.remove(1);
            println!("You want to change cwd to {:s}", pstring);
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>use hir::PerNs;
use ra_text_edit::{
    AtomTextEdit,
    TextEdit,
};

use crate::completion::completion_context::CompletionContext;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion.
    completion_kind: CompletionKind,
    label: String,
    kind: Option<CompletionItemKind>,
    detail: Option<String>,
    lookup: Option<String>,
    /// The format of the insert text. The format applies to both the `insert_text` property
    /// and the `insert` property of a provided `text_edit`.
    insert_text_format: InsertTextFormat,
    /// An edit which is applied to a document when selecting this completion. When an edit is
    /// provided the value of `insert_text` is ignored.
    ///
    /// *Note:* The range of the edit must be a single line range and it must contain the position
    /// at which completion has been requested.
    ///
    /// *Note:* If sending a range that overlaps a string, the string should match the relevant
    /// part of the replacement text, or be filtered out.
    text_edit: Option<AtomTextEdit>,
    /// An optional array of additional text edits that are applied when
    /// selecting this completion. Edits must not overlap (including the same insert position)
    /// with the main edit nor with themselves.
    ///
    /// Additional text edits should be used to change text unrelated to the current cursor position
    /// (for example adding an import statement at the top of the file if the completion item will
    /// insert an unqualified type).
    additional_text_edits: Option<TextEdit>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
    Static,
    Const,
    Trait,
    TypeAlias,
    Method,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new<'a>(
        completion_kind: CompletionKind,
        ctx: &'a CompletionContext,
        label: impl Into<String>,
    ) -> Builder<'a> {
        let label = label.into();
        Builder {
            ctx,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            lookup: None,
            kind: None,
            text_edit: None,
            additional_text_edits: None,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_ref().map(|it| it.as_str())
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format.clone()
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }
    pub fn text_edit(&mut self) -> Option<&AtomTextEdit> {
        self.text_edit.as_ref()
    }
    pub fn take_additional_text_edits(&mut self) -> Option<TextEdit> {
        self.additional_text_edits.take()
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder<'a> {
    ctx: &'a CompletionContext<'a>,
    completion_kind: CompletionKind,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<AtomTextEdit>,
    additional_text_edits: Option<TextEdit>,
}

impl<'a> Builder<'a> {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        let self_text_edit = self.text_edit;
        let self_insert_text = self.insert_text;
        let text_edit = match (self_text_edit, self_insert_text) {
            (Some(text_edit), ..) => Some(text_edit),
            (None, Some(insert_text)) => {
                Some(AtomTextEdit::replace(self.ctx.leaf_range(), insert_text))
            }
            _ => None,
        };

        CompletionItem {
            label: self.label,
            detail: self.detail,
            insert_text_format: self.insert_text_format,
            lookup: self.lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            text_edit,
            additional_text_edits: self.additional_text_edits,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder<'a> {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder<'a> {
        self.insert_text = Some(insert_text.into());
        self
    }
    pub(crate) fn insert_text_format(
        mut self,
        insert_text_format: InsertTextFormat,
    ) -> Builder<'a> {
        self.insert_text_format = insert_text_format;
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder<'a> {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder<'a> {
        self.kind = Some(kind);
        self
    }
    pub(crate) fn text_edit(mut self, text_edit: AtomTextEdit) -> Builder<'a> {
        self.text_edit = Some(text_edit);
        self
    }
    pub(crate) fn additional_text_edits(mut self, additional_text_edits: TextEdit) -> Builder<'a> {
        self.additional_text_edits = Some(additional_text_edits);
        self
    }
    #[allow(unused)]
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder<'a> {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder<'a> {
        self.detail = detail.map(Into::into);
        self
    }
    pub(super) fn from_resolution(
        mut self,
        ctx: &CompletionContext,
        resolution: &hir::Resolution,
    ) -> Builder<'a> {
        let resolved = resolution.def_id.map(|d| d.resolve(ctx.db));
        let kind = match resolved {
            PerNs {
                types: Some(hir::Def::Module(..)),
                ..
            } => CompletionItemKind::Module,
            PerNs {
                types: Some(hir::Def::Struct(..)),
                ..
            } => CompletionItemKind::Struct,
            PerNs {
                types: Some(hir::Def::Enum(..)),
                ..
            } => CompletionItemKind::Enum,
            PerNs {
                types: Some(hir::Def::Trait(..)),
                ..
            } => CompletionItemKind::Trait,
            PerNs {
                types: Some(hir::Def::Type(..)),
                ..
            } => CompletionItemKind::TypeAlias,
            PerNs {
                values: Some(hir::Def::Const(..)),
                ..
            } => CompletionItemKind::Const,
            PerNs {
                values: Some(hir::Def::Static(..)),
                ..
            } => CompletionItemKind::Static,
            PerNs {
                values: Some(hir::Def::Function(function)),
                ..
            } => return self.from_function(ctx, function),
            _ => return self,
        };
        self.kind = Some(kind);
        self
    }

    pub(super) fn from_function(
        mut self,
        ctx: &CompletionContext,
        function: hir::Function,
    ) -> Builder<'a> {
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none() && !ctx.is_call {
            if function.signature(ctx.db).params().is_empty() {
                self.insert_text = Some(format!("{}()$0", self.label));
            } else {
                self.insert_text = Some(format!("{}($0)", self.label));
            }
            self.insert_text_format = InsertTextFormat::Snippet;
        }
        self.kind = Some(CompletionItemKind::Function);
        self
    }
}

impl<'a> Into<CompletionItem> for Builder<'a> {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}

#[cfg(test)]
pub(crate) fn check_completion(test_name: &str, code: &str, kind: CompletionKind) {
    use crate::mock_analysis::{single_file_with_position, analysis_and_position};
    use crate::completion::completions;
    use insta::assert_debug_snapshot_matches;
    let (analysis, position) = if code.contains("//-") {
        analysis_and_position(code)
    } else {
        single_file_with_position(code)
    };
    let completions = completions(&analysis.db, position).unwrap();
    let completion_items: Vec<CompletionItem> = completions.into();
    let kind_completions: Vec<CompletionItem> = completion_items
        .into_iter()
        .filter(|c| c.completion_kind == kind)
        .collect();
    assert_debug_snapshot_matches!(test_name, kind_completions);
}
<commit_msg>ignore unused methods<commit_after>use hir::PerNs;
use ra_text_edit::{
    AtomTextEdit,
    TextEdit,
};

use crate::completion::completion_context::CompletionContext;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion.
    completion_kind: CompletionKind,
    label: String,
    kind: Option<CompletionItemKind>,
    detail: Option<String>,
    lookup: Option<String>,
    /// The format of the insert text. The format applies to both the `insert_text` property
    /// and the `insert` property of a provided `text_edit`.
    insert_text_format: InsertTextFormat,
    /// An edit which is applied to a document when selecting this completion. When an edit is
    /// provided the value of `insert_text` is ignored.
    ///
    /// *Note:* The range of the edit must be a single line range and it must contain the position
    /// at which completion has been requested.
    ///
    /// *Note:* If sending a range that overlaps a string, the string should match the relevant
    /// part of the replacement text, or be filtered out.
    text_edit: Option<AtomTextEdit>,
    /// An optional array of additional text edits that are applied when
    /// selecting this completion. Edits must not overlap (including the same insert position)
    /// with the main edit nor with themselves.
    ///
    /// Additional text edits should be used to change text unrelated to the current cursor position
    /// (for example adding an import statement at the top of the file if the completion item will
    /// insert an unqualified type).
    additional_text_edits: Option<TextEdit>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    Snippet,
    Keyword,
    Module,
    Function,
    Struct,
    Enum,
    EnumVariant,
    Binding,
    Field,
    Static,
    Const,
    Trait,
    TypeAlias,
    Method,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new<'a>(
        completion_kind: CompletionKind,
        ctx: &'a CompletionContext,
        label: impl Into<String>,
    ) -> Builder<'a> {
        let label = label.into();
        Builder {
            ctx,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            lookup: None,
            kind: None,
            text_edit: None,
            additional_text_edits: None,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_ref().map(|it| it.as_str())
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format.clone()
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }
    pub fn text_edit(&mut self) -> Option<&AtomTextEdit> {
        self.text_edit.as_ref()
    }
    pub fn take_additional_text_edits(&mut self) -> Option<TextEdit> {
        self.additional_text_edits.take()
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder<'a> {
    ctx: &'a CompletionContext<'a>,
    completion_kind: CompletionKind,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<AtomTextEdit>,
    additional_text_edits: Option<TextEdit>,
}

impl<'a> Builder<'a> {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        let self_text_edit = self.text_edit;
        let self_insert_text = self.insert_text;
        let text_edit = match (self_text_edit, self_insert_text) {
            (Some(text_edit), ..) => Some(text_edit),
            (None, Some(insert_text)) => {
                Some(AtomTextEdit::replace(self.ctx.leaf_range(), insert_text))
            }
            _ => None,
        };

        CompletionItem {
            label: self.label,
            detail: self.detail,
            insert_text_format: self.insert_text_format,
            lookup: self.lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            text_edit,
            additional_text_edits: self.additional_text_edits,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder<'a> {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder<'a> {
        self.insert_text = Some(insert_text.into());
        self
    }
    #[allow(unused)]
    pub(crate) fn insert_text_format(
        mut self,
        insert_text_format: InsertTextFormat,
    ) -> Builder<'a> {
        self.insert_text_format = insert_text_format;
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder<'a> {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder<'a> {
        self.kind = Some(kind);
        self
    }
    #[allow(unused)]
    pub(crate) fn text_edit(mut self, text_edit: AtomTextEdit) -> Builder<'a> {
        self.text_edit = Some(text_edit);
        self
    }
    #[allow(unused)]
    pub(crate) fn additional_text_edits(mut self, additional_text_edits: TextEdit) -> Builder<'a> {
        self.additional_text_edits = Some(additional_text_edits);
        self
    }
    #[allow(unused)]
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder<'a> {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder<'a> {
        self.detail = detail.map(Into::into);
        self
    }
    pub(super) fn from_resolution(
        mut self,
        ctx: &CompletionContext,
        resolution: &hir::Resolution,
    ) -> Builder<'a> {
        let resolved = resolution.def_id.map(|d| d.resolve(ctx.db));
        let kind = match resolved {
            PerNs {
                types: Some(hir::Def::Module(..)),
                ..
            } => CompletionItemKind::Module,
            PerNs {
                types: Some(hir::Def::Struct(..)),
                ..
            } => CompletionItemKind::Struct,
            PerNs {
                types: Some(hir::Def::Enum(..)),
                ..
            } => CompletionItemKind::Enum,
            PerNs {
                types: Some(hir::Def::Trait(..)),
                ..
            } => CompletionItemKind::Trait,
            PerNs {
                types: Some(hir::Def::Type(..)),
                ..
            } => CompletionItemKind::TypeAlias,
            PerNs {
                values: Some(hir::Def::Const(..)),
                ..
            } => CompletionItemKind::Const,
            PerNs {
                values: Some(hir::Def::Static(..)),
                ..
            } => CompletionItemKind::Static,
            PerNs {
                values: Some(hir::Def::Function(function)),
                ..
            } => return self.from_function(ctx, function),
            _ => return self,
        };
        self.kind = Some(kind);
        self
    }

    pub(super) fn from_function(
        mut self,
        ctx: &CompletionContext,
        function: hir::Function,
    ) -> Builder<'a> {
        // If not an import, add parenthesis automatically.
        if ctx.use_item_syntax.is_none() && !ctx.is_call {
            if function.signature(ctx.db).params().is_empty() {
                self.insert_text = Some(format!("{}()$0", self.label));
            } else {
                self.insert_text = Some(format!("{}($0)", self.label));
            }
            self.insert_text_format = InsertTextFormat::Snippet;
        }
        self.kind = Some(CompletionItemKind::Function);
        self
    }
}

impl<'a> Into<CompletionItem> for Builder<'a> {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}

#[cfg(test)]
pub(crate) fn check_completion(test_name: &str, code: &str, kind: CompletionKind) {
    use crate::mock_analysis::{single_file_with_position, analysis_and_position};
    use crate::completion::completions;
    use insta::assert_debug_snapshot_matches;
    let (analysis, position) = if code.contains("//-") {
        analysis_and_position(code)
    } else {
        single_file_with_position(code)
    };
    let completions = completions(&analysis.db, position).unwrap();
    let completion_items: Vec<CompletionItem> = completions.into();
    let kind_completions: Vec<CompletionItem> = completion_items
        .into_iter()
        .filter(|c| c.completion_kind == kind)
        .collect();
    assert_debug_snapshot_matches!(test_name, kind_completions);
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display, Write};
use std::ffi::NulError;

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidCString(NulError),
    DatabaseError(String),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Debug)]
pub enum ConnectionError {
    InvalidCString(NulError),
    BadConnection(String),
}

#[derive(Debug, PartialEq)]
pub enum TransactionError<E> {
    CouldntCreateTransaction(Error),
    UserReturnedError(E),
}

pub type QueryResult<T> = Result<T, Error>;
pub type ConnectionResult<T> = Result<T, ConnectionError>;
pub type TransactionResult<T, E> = Result<T, TransactionError<E>>;

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl<E> From<Error> for TransactionError<E> {
    fn from(e: Error) -> Self {
        TransactionError::CouldntCreateTransaction(e)
    }
}

impl From<TransactionError<Error>> for Error {
    fn from(e: TransactionError<Error>) -> Self {
        match e {
            TransactionError::CouldntCreateTransaction(e) => e,
            TransactionError::UserReturnedError(e) => e,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &Error::DatabaseError(ref s) => write!(f, "{}", &s),
            &Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.description(),
            &Error::DatabaseError(ref s) => &s,
            &Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &ConnectionError::BadConnection(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            &ConnectionError::BadConnection(ref s) => &s,
        }
    }
}

impl<E: Display> Display for TransactionError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.fmt(f),
            &TransactionError::UserReturnedError(ref e) => e.fmt(f),
        }
    }
}

impl<E: StdError> StdError for TransactionError<E> {
    fn description(&self) -> &str {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.description(),
            &TransactionError::UserReturnedError(ref e) => e.description(),
        }
    }
}
<commit_msg>Mention that `Error` is intended to be extensible in the docs<commit_after>use std::convert::From;
use std::error::Error as StdError;
use std::fmt::{self, Display, Write};
use std::ffi::NulError;

#[derive(Debug, PartialEq)]
/// The generic "things can fail in a myriad of ways" enum. This type is not
/// indended to be exhaustively matched, and new variants may be added in the
/// future without a major version bump.
pub enum Error {
    InvalidCString(NulError),
    DatabaseError(String),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Debug)]
pub enum ConnectionError {
    InvalidCString(NulError),
    BadConnection(String),
}

#[derive(Debug, PartialEq)]
pub enum TransactionError<E> {
    CouldntCreateTransaction(Error),
    UserReturnedError(E),
}

pub type QueryResult<T> = Result<T, Error>;
pub type ConnectionResult<T> = Result<T, ConnectionError>;
pub type TransactionResult<T, E> = Result<T, TransactionError<E>>;

impl From<NulError> for ConnectionError {
    fn from(e: NulError) -> Self {
        ConnectionError::InvalidCString(e)
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Self {
        Error::InvalidCString(e)
    }
}

impl<E> From<Error> for TransactionError<E> {
    fn from(e: Error) -> Self {
        TransactionError::CouldntCreateTransaction(e)
    }
}

impl From<TransactionError<Error>> for Error {
    fn from(e: TransactionError<Error>) -> Self {
        match e {
            TransactionError::CouldntCreateTransaction(e) => e,
            TransactionError::UserReturnedError(e) => e,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &Error::DatabaseError(ref s) => write!(f, "{}", &s),
            &Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidCString(ref nul_err) => nul_err.description(),
            &Error::DatabaseError(ref s) => &s,
            &Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl Display for ConnectionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.fmt(f),
            &ConnectionError::BadConnection(ref s) => write!(f, "{}", &s),
        }
    }
}

impl StdError for ConnectionError {
    fn description(&self) -> &str {
        match self {
            &ConnectionError::InvalidCString(ref nul_err) => nul_err.description(),
            &ConnectionError::BadConnection(ref s) => &s,
        }
    }
}

impl<E: Display> Display for TransactionError<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.fmt(f),
            &TransactionError::UserReturnedError(ref e) => e.fmt(f),
        }
    }
}

impl<E: StdError> StdError for TransactionError<E> {
    fn description(&self) -> &str {
        match self {
            &TransactionError::CouldntCreateTransaction(ref e) => e.description(),
            &TransactionError::UserReturnedError(ref e) => e.description(),
        }
    }
}
<|endoftext|>