<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::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}
<commit_msg>embedding: cef_string_multimap_value()<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::slice_to_str;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_multimap_t,cef_string_t};

fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
    smm as *mut TreeMap<String, Vec<*mut cef_string_t>>
}

//cef_string_multimap

#[no_mangle]
pub extern "C" fn cef_string_multimap_alloc() -> *mut cef_string_multimap_t {
    unsafe {
         let smm: Box<TreeMap<String, Vec<*mut cef_string_t>>> = box TreeMap::new();
         mem::transmute(smm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_size(smm: *mut cef_string_multimap_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let mut c: c_int = 0;
        let v = string_multimap_to_treemap(smm);
        for (_, val) in (*v).iter() {
            c = c + (*val).len() as c_int;
        }
        c
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_find_count(smm: *mut cef_string_multimap_t, key: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    s.len() as c_int
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_append(smm: *mut cef_string_multimap_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            let s = String::from_str(result);
            let csv = cef_string_userfree_utf8_alloc();
            cef_string_utf8_set((*value).str as *const u8, (*value).length, csv, 1);
            match (*v).find_mut(&s) {
                Some(vc) => {
                    (*vc).push(csv);
                    1
                }
                None => {
                    let vc = vec!(csv);
                    (*v).insert(s, vc);
                    1
                }
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_enumerate(smm: *mut cef_string_multimap_t, key: *const cef_string_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        slice_to_str((*key).str as *const u8, (*key).length as uint, |result| {
            match (*v).find(&String::from_str(result)) {
                Some(s) => {
                    if (*s).len() <= index as uint {
                        return 0;
                    }
                    let cs = (*s)[index as uint];
                    cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1)
                }
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_key(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (key, val) in (*v).iter() {
            if rem < (*val).len() {
                return cef_string_utf8_set((*key).as_bytes().as_ptr(), (*key).len() as u64, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_multimap_value(smm: *mut cef_string_multimap_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || smm.is_null() { return 0; }
        let v = string_multimap_to_treemap(smm);
        let mut rem = index as uint;

        for (_, val) in (*v).values().enumerate() {
            if rem < (*val).len() {
                let cs = (*val)[rem as uint];
                return cef_string_utf8_set((*cs).str as *const u8, (*cs).length, value, 1);
            } else {
                rem = rem - (*val).len();
            }
        }
    }
    0
}
<|endoftext|>


<commit_before>#[cfg_attr(rustfmt, rustfmt_skip)]
static RUST_KEYWORDS: &'static [&'static str] = &[
    "as",
    "break",
    "crate",
    "else",
    "enum",
    "extern",
    "false",
    "fn",
    "for",
    "if",
    "impl",
    "in",
    "let",
    "loop",
    "match",
    "mod",
    "move",
    "mut",
    "pub",
    "ref",
    "return",
    "static",
    "self",
    "Self",
    "struct",
    "super",
    "true",
    "trait",
    "type",
    "unsafe",
    "use",
    "while",
    "continue",
    "box",
    "const",
    "where",
    "virtual",
    "proc",
    "alignof",
    "become",
    "offsetof",
    "priv",
    "pure",
    "sizeof",
    "typeof",
    "unsized",
    "yield",
    "do",
    "abstract",
    "final",
    "override",
    "macro",
];

pub fn is_rust_keyword(ident: &str) -> bool {
    RUST_KEYWORDS.contains(&ident)
}

fn hex_digit(value: u32) -> char {
    if value < 10 {
        (b'0' + value as u8) as char
    } else if value < 0x10 {
        (b'a' + value as u8 - 10) as char
    } else {
        unreachable!()
    }
}

pub fn quote_escape_str(s: &str) -> String {
    let mut buf = String::new();
    buf.push('"');
    buf.extend(s.chars().flat_map(|c| c.escape_default()));
    buf.push('"');
    buf
}

pub fn quote_escape_bytes(bytes: &[u8]) -> String {
    let mut buf = String::new();
    buf.push('b');
    buf.push('"');
    for &b in bytes {
        match b {
            b'\n' => buf.push_str(r"\n"),
            b'\r' => buf.push_str(r"\r"),
            b'\t' => buf.push_str(r"\t"),
            b'"' => buf.push_str("\\\""),
            b'\\' => buf.push_str(r"\\"),
            b'\x20'..=b'\x7e' => buf.push(b as char),
            _ => {
                buf.push_str(r"\x");
                buf.push(hex_digit((b as u32) >> 4));
                buf.push(hex_digit((b as u32) & 0x0f));
            }
        }
    }
    buf.push('"');
    buf
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_quote_escape_bytes() {
        assert_eq!("b\"\"", quote_escape_bytes(b""));
        assert_eq!("b\"xyZW\"", quote_escape_bytes(b"xyZW"));
        assert_eq!("b\"aa\\\"bb\"", quote_escape_bytes(b"aa\"bb"));
        assert_eq!("b\"aa\\r\\n\\tbb\"", quote_escape_bytes(b"aa\r\n\tbb"));
        assert_eq!(
            "b\"\\x00\\x01\\x12\\xfe\\xff\"",
            quote_escape_bytes(b"\x00\x01\x12\xfe\xff")
        );
    }
}
<commit_msg>add async/await to RUST_KEYWORDS<commit_after>#[cfg_attr(rustfmt, rustfmt_skip)]
static RUST_KEYWORDS: &'static [&'static str] = &[
    "as",
    "async",
    "await",
    "break",
    "crate",
    "else",
    "enum",
    "extern",
    "false",
    "fn",
    "for",
    "if",
    "impl",
    "in",
    "let",
    "loop",
    "match",
    "mod",
    "move",
    "mut",
    "pub",
    "ref",
    "return",
    "static",
    "self",
    "Self",
    "struct",
    "super",
    "true",
    "trait",
    "type",
    "unsafe",
    "use",
    "while",
    "continue",
    "box",
    "const",
    "where",
    "virtual",
    "proc",
    "alignof",
    "become",
    "offsetof",
    "priv",
    "pure",
    "sizeof",
    "typeof",
    "unsized",
    "yield",
    "do",
    "abstract",
    "final",
    "override",
    "macro",
];

pub fn is_rust_keyword(ident: &str) -> bool {
    RUST_KEYWORDS.contains(&ident)
}

fn hex_digit(value: u32) -> char {
    if value < 10 {
        (b'0' + value as u8) as char
    } else if value < 0x10 {
        (b'a' + value as u8 - 10) as char
    } else {
        unreachable!()
    }
}

pub fn quote_escape_str(s: &str) -> String {
    let mut buf = String::new();
    buf.push('"');
    buf.extend(s.chars().flat_map(|c| c.escape_default()));
    buf.push('"');
    buf
}

pub fn quote_escape_bytes(bytes: &[u8]) -> String {
    let mut buf = String::new();
    buf.push('b');
    buf.push('"');
    for &b in bytes {
        match b {
            b'\n' => buf.push_str(r"\n"),
            b'\r' => buf.push_str(r"\r"),
            b'\t' => buf.push_str(r"\t"),
            b'"' => buf.push_str("\\\""),
            b'\\' => buf.push_str(r"\\"),
            b'\x20'..=b'\x7e' => buf.push(b as char),
            _ => {
                buf.push_str(r"\x");
                buf.push(hex_digit((b as u32) >> 4));
                buf.push(hex_digit((b as u32) & 0x0f));
            }
        }
    }
    buf.push('"');
    buf
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_quote_escape_bytes() {
        assert_eq!("b\"\"", quote_escape_bytes(b""));
        assert_eq!("b\"xyZW\"", quote_escape_bytes(b"xyZW"));
        assert_eq!("b\"aa\\\"bb\"", quote_escape_bytes(b"aa\"bb"));
        assert_eq!("b\"aa\\r\\n\\tbb\"", quote_escape_bytes(b"aa\r\n\tbb"));
        assert_eq!(
            "b\"\\x00\\x01\\x12\\xfe\\xff\"",
            quote_escape_bytes(b"\x00\x01\x12\xfe\xff")
        );
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use crate::alloc::{GlobalAlloc, Layout, System};
use crate::cmp;
use crate::ptr;

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(
    target_arch = "x86",
    target_arch = "arm",
    target_arch = "mips",
    target_arch = "powerpc",
    target_arch = "powerpc64",
    target_arch = "asmjs",
    target_arch = "wasm32",
    target_arch = "hexagon"
)))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(
    target_arch = "x86_64",
    target_arch = "aarch64",
    target_arch = "mips64",
    target_arch = "s390x",
    target_arch = "sparc64",
    target_arch = "riscv64"
)))]
pub const MIN_ALIGN: usize = 16;

pub unsafe fn realloc_fallback(
    alloc: &System,
    ptr: *mut u8,
    old_layout: Layout,
    new_size: usize,
) -> *mut u8 {
    // Docs for GlobalAlloc::realloc require this to be valid:
    let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());

    let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
    if !new_ptr.is_null() {
        let size = cmp::min(old_layout.size(), new_size);
        ptr::copy_nonoverlapping(ptr, new_ptr, size);
        GlobalAlloc::dealloc(alloc, ptr, old_layout);
    }
    new_ptr
}
<commit_msg>library/std: sys_common: Add support for RISC-V 32-bit<commit_after>#![allow(dead_code)]

use crate::alloc::{GlobalAlloc, Layout, System};
use crate::cmp;
use crate::ptr;

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(
    target_arch = "x86",
    target_arch = "arm",
    target_arch = "mips",
    target_arch = "powerpc",
    target_arch = "powerpc64",
    target_arch = "asmjs",
    target_arch = "wasm32",
    target_arch = "hexagon",
    target_arch = "riscv32"
)))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(
    target_arch = "x86_64",
    target_arch = "aarch64",
    target_arch = "mips64",
    target_arch = "s390x",
    target_arch = "sparc64",
    target_arch = "riscv64"
)))]
pub const MIN_ALIGN: usize = 16;

pub unsafe fn realloc_fallback(
    alloc: &System,
    ptr: *mut u8,
    old_layout: Layout,
    new_size: usize,
) -> *mut u8 {
    // Docs for GlobalAlloc::realloc require this to be valid:
    let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());

    let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
    if !new_ptr.is_null() {
        let size = cmp::min(old_layout.size(), new_size);
        ptr::copy_nonoverlapping(ptr, new_ptr, size);
        GlobalAlloc::dealloc(alloc, ptr, old_layout);
    }
    new_ptr
}
<|endoftext|>


<commit_before>generate_error_module!(
    generate_error_types!(ListError, ListErrorKind,
        FormatError    => "FormatError",
        EntryError     => "EntryError",
        IterationError => "IterationError",
        CLIError       => "No CLI subcommand for listing entries"
    );
);

pub use self::error::ListError;
pub use self::error::ListErrorKind;

<commit_msg>Add error type: IOError<commit_after>generate_error_module!(
    generate_error_types!(ListError, ListErrorKind,
        IOError        => "IO Error",
        FormatError    => "FormatError",
        EntryError     => "EntryError",
        IterationError => "IterationError",
        CLIError       => "No CLI subcommand for listing entries"
    );
);

pub use self::error::ListError;
pub use self::error::ListErrorKind;

<|endoftext|>


<commit_before>//! Legalization of heaps.
//!
//! This module exports the `expand_heap_addr` function which transforms a `heap_addr`
//! instruction into code that depends on the kind of heap referenced.

use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::condcodes::IntCC;
use ir::{self, InstBuilder};
use isa::TargetIsa;

/// Expand a `heap_addr` instruction according to the definition of the heap.
pub fn expand_heap_addr(
    inst: ir::Inst,
    func: &mut ir::Function,
    cfg: &mut ControlFlowGraph,
    _isa: &TargetIsa,
) {
    // Unpack the instruction.
    let (heap, offset, size) = match func.dfg[inst] {
        ir::InstructionData::HeapAddr {
            opcode,
            heap,
            arg,
            imm,
        } => {
            debug_assert_eq!(opcode, ir::Opcode::HeapAddr);
            (heap, arg, imm.into())
        }
        _ => panic!("Wanted heap_addr: {}", func.dfg.display_inst(inst, None)),
    };

    match func.heaps[heap].style {
        ir::HeapStyle::Dynamic { bound_gv } => {
            dynamic_addr(inst, heap, offset, size, bound_gv, func)
        }
        ir::HeapStyle::Static { bound } => {
            static_addr(inst, heap, offset, size, bound.into(), func, cfg)
        }
    }
}

/// Expand a `heap_addr` for a dynamic heap.
fn dynamic_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound_gv: ir::GlobalValue,
    func: &mut ir::Function,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let min_size = func.heaps[heap].min_size.into();
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    let bound = pos.ins().global_value(addr_ty, bound_gv);

    let oob;
    if size == 1 {
        // `offset > bound - 1` is the same as `offset >= bound`.
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThanOrEqual, offset, bound);
    } else if size <= min_size {
        // We know that bound >= min_size, so here we can compare `offset > bound - size` without
        // wrapping.
        let adj_bound = pos.ins().iadd_imm(bound, -size);
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThan, offset, adj_bound);
    } else {
        // We need an overflow check for the adjusted offset.
        let size_val = pos.ins().iconst(offset_ty, size);
        let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val);
        pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThan, adj_offset, bound);
    }
    pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Expand a `heap_addr` for a static heap.
fn static_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound: i64,
    func: &mut ir::Function,
    cfg: &mut ControlFlowGraph,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    if size > bound {
        // This will simply always trap since `offset >= 0`.
        pos.ins().trap(ir::TrapCode::HeapOutOfBounds);
        pos.func.dfg.replace(inst).iconst(addr_ty, 0);

        // Split Ebb, as the trap is a terminator instruction.
        let curr_ebb = pos.current_ebb().expect("Cursor is not in an ebb");
        let new_ebb = pos.func.dfg.make_ebb();
        pos.insert_ebb(new_ebb);
        cfg.recompute_ebb(pos.func, curr_ebb);
        cfg.recompute_ebb(pos.func, new_ebb);
        return;
    }

    // Check `offset > limit` which is now known non-negative.
    let limit = bound - size;

    // We may be able to omit the check entirely for 32-bit offsets if the heap bound is 4 GB or
    // more.
    if offset_ty != ir::types::I32 || limit < 0xffff_ffff {
        let oob = if limit & 1 == 1 {
            // Prefer testing `offset >= limit - 1` when limit is odd because an even number is
            // likely to be a convenient constant on ARM and other RISC architectures.
            pos.ins()
                .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, offset, limit - 1)
        } else {
            pos.ins()
                .icmp_imm(IntCC::UnsignedGreaterThan, offset, limit)
        };
        pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
    }

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Emit code for the base address computation of a `heap_addr` instruction.
///
///
fn offset_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    addr_ty: ir::Type,
    mut offset: ir::Value,
    offset_ty: ir::Type,
    func: &mut ir::Function,
) {
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Convert `offset` to `addr_ty`.
    if offset_ty != addr_ty {
        offset = pos.ins().uextend(addr_ty, offset);
    }

    // Add the heap base address base
    match pos.func.heaps[heap].base {
        ir::HeapBase::ReservedReg => unimplemented!(),
        ir::HeapBase::GlobalValue(base_gv) => {
            let base = pos.ins().global_value(addr_ty, base_gv);
            pos.func.dfg.replace(inst).iadd(base, offset);
        }
    }
}
<commit_msg>Fix breaking change<commit_after>//! Legalization of heaps.
//!
//! This module exports the `expand_heap_addr` function which transforms a `heap_addr`
//! instruction into code that depends on the kind of heap referenced.

use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::condcodes::IntCC;
use ir::{self, InstBuilder, MemFlags};
use isa::TargetIsa;

/// Expand a `heap_addr` instruction according to the definition of the heap.
pub fn expand_heap_addr(
    inst: ir::Inst,
    func: &mut ir::Function,
    cfg: &mut ControlFlowGraph,
    _isa: &TargetIsa,
) {
    // Unpack the instruction.
    let (heap, offset, size) = match func.dfg[inst] {
        ir::InstructionData::HeapAddr {
            opcode,
            heap,
            arg,
            imm,
        } => {
            debug_assert_eq!(opcode, ir::Opcode::HeapAddr);
            (heap, arg, imm.into())
        }
        _ => panic!("Wanted heap_addr: {}", func.dfg.display_inst(inst, None)),
    };

    match func.heaps[heap].style {
        ir::HeapStyle::Dynamic { bound_gv } => {
            dynamic_addr(inst, heap, offset, size, bound_gv, func)
        }
        ir::HeapStyle::Static { bound } => {
            static_addr(inst, heap, offset, size, bound.into(), func, cfg)
        }
    }
}

/// Expand a `heap_addr` for a dynamic heap.
fn dynamic_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound_gv: ir::GlobalValue,
    func: &mut ir::Function,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let min_size = func.heaps[heap].min_size.into();
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    let bound_addr = pos.ins().global_value(addr_ty, bound_gv);
    let mut mflags = MemFlags::new();
    // The bound variable is requied to be accessible and aligned.
    mflags.set_notrap();
    mflags.set_aligned();
    let bound = pos.ins().load(offset_ty, mflags, bound_addr, 0);

    let oob;
    if size == 1 {
        // `offset > bound - 1` is the same as `offset >= bound`.
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThanOrEqual, offset, bound);
    } else if size <= min_size {
        // We know that bound >= min_size, so here we can compare `offset > bound - size` without
        // wrapping.
        let adj_bound = pos.ins().iadd_imm(bound, -size);
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThan, offset, adj_bound);
    } else {
        // We need an overflow check for the adjusted offset.
        let size_val = pos.ins().iconst(offset_ty, size);
        let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val);
        pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
        oob = pos.ins()
            .icmp(IntCC::UnsignedGreaterThan, adj_offset, bound);
    }
    pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Expand a `heap_addr` for a static heap.
fn static_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound: i64,
    func: &mut ir::Function,
    cfg: &mut ControlFlowGraph,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    if size > bound {
        // This will simply always trap since `offset >= 0`.
        pos.ins().trap(ir::TrapCode::HeapOutOfBounds);
        pos.func.dfg.replace(inst).iconst(addr_ty, 0);

        // Split Ebb, as the trap is a terminator instruction.
        let curr_ebb = pos.current_ebb().expect("Cursor is not in an ebb");
        let new_ebb = pos.func.dfg.make_ebb();
        pos.insert_ebb(new_ebb);
        cfg.recompute_ebb(pos.func, curr_ebb);
        cfg.recompute_ebb(pos.func, new_ebb);
        return;
    }

    // Check `offset > limit` which is now known non-negative.
    let limit = bound - size;

    // We may be able to omit the check entirely for 32-bit offsets if the heap bound is 4 GB or
    // more.
    if offset_ty != ir::types::I32 || limit < 0xffff_ffff {
        let oob = if limit & 1 == 1 {
            // Prefer testing `offset >= limit - 1` when limit is odd because an even number is
            // likely to be a convenient constant on ARM and other RISC architectures.
            pos.ins()
                .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, offset, limit - 1)
        } else {
            pos.ins()
                .icmp_imm(IntCC::UnsignedGreaterThan, offset, limit)
        };
        pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
    }

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Emit code for the base address computation of a `heap_addr` instruction.
///
///
fn offset_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    addr_ty: ir::Type,
    mut offset: ir::Value,
    offset_ty: ir::Type,
    func: &mut ir::Function,
) {
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Convert `offset` to `addr_ty`.
    if offset_ty != addr_ty {
        offset = pos.ins().uextend(addr_ty, offset);
    }

    // Add the heap base address base
    match pos.func.heaps[heap].base {
        ir::HeapBase::ReservedReg => unimplemented!(),
        ir::HeapBase::GlobalValue(base_gv) => {
            let base_addr = pos.ins().global_value(addr_ty, base_gv);
            let mut mflags = MemFlags::new();
            // The base address variable is requied to be accessible and aligned.
            mflags.set_notrap();
            mflags.set_aligned();
            let base = pos.ins().load(addr_ty, mflags, base_addr, 0);
            pos.func.dfg.replace(inst).iadd(base, offset);
        }
    }
}
<|endoftext|>


<commit_before>//! Implementation of `std::os` functionality for Windows.

#![allow(nonstandard_style)]

#[cfg(test)]
mod tests;

use crate::os::windows::prelude::*;

use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::os::windows::ffi::EncodeWide;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};

use super::to_u16s;

pub fn errno() -> i32 {
    unsafe { c::GetLastError() as i32 }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(mut errnum: i32) -> String {
    // This value is calculated from the macro
    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
    let langId = 0x0800 as c::DWORD;

    let mut buf = [0 as c::WCHAR; 2048];

    unsafe {
        let mut module = ptr::null_mut();
        let mut flags = 0;

        // NTSTATUS errors may be encoded as HRESULT, which may returned from
        // GetLastError. For more information about Windows error codes, see
        // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
            // format according to https://support.microsoft.com/en-us/help/259693
            const NTDLL_DLL: &[u16] = &[
                'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
                'L' as _, 0,
            ];
            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());

            if !module.is_null() {
                errnum ^= c::FACILITY_NT_BIT as i32;
                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
            }
        }

        let res = c::FormatMessageW(
            flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
            module,
            errnum as c::DWORD,
            langId,
            buf.as_mut_ptr(),
            buf.len() as c::DWORD,
            ptr::null(),
        ) as usize;
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
            let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
        }

        match String::from_utf16(&buf[..res]) {
            Ok(mut msg) => {
                // Trim trailing CRLF inserted by FormatMessageW
                let len = msg.trim_end().len();
                msg.truncate(len);
                msg
            }
            Err(..) => format!(
                "OS Error {} (FormatMessageW() returned \
                 invalid UTF-16)",
                errnum
            ),
        }
    }
}

pub struct Env {
    base: c::LPWCH,
    cur: c::LPWCH,
}

impl Iterator for Env {
    type Item = (OsString, OsString);

    fn next(&mut self) -> Option<(OsString, OsString)> {
        loop {
            unsafe {
                if *self.cur == 0 {
                    return None;
                }
                let p = self.cur as *const u16;
                let mut len = 0;
                while *p.offset(len) != 0 {
                    len += 1;
                }
                let s = slice::from_raw_parts(p, len as usize);
                self.cur = self.cur.offset(len + 1);

                // Windows allows environment variables to start with an equals
                // symbol (in any other position, this is the separator between
                // variable name and value). Since`s` has at least length 1 at
                // this point (because the empty string terminates the array of
                // environment variables), we can safely slice.
                let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) {
                    Some(p) => p,
                    None => continue,
                };
                return Some((
                    OsStringExt::from_wide(&s[..pos]),
                    OsStringExt::from_wide(&s[pos + 1..]),
                ));
            }
        }
    }
}

impl Drop for Env {
    fn drop(&mut self) {
        unsafe {
            c::FreeEnvironmentStringsW(self.base);
        }
    }
}

pub fn env() -> Env {
    unsafe {
        let ch = c::GetEnvironmentStringsW();
        if ch as usize == 0 {
            panic!("failure getting env string from OS: {}", io::Error::last_os_error());
        }
        Env { base: ch, cur: ch }
    }
}

pub struct SplitPaths<'a> {
    data: EncodeWide<'a>,
    must_yield: bool,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    SplitPaths { data: unparsed.encode_wide(), must_yield: true }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> {
        // On Windows, the PATH environment variable is semicolon separated.
        // Double quotes are used as a way of introducing literal semicolons
        // (since c:\some;dir is a valid Windows path). Double quotes are not
        // themselves permitted in path names, so there is no way to escape a
        // double quote.  Quoted regions can appear in arbitrary locations, so
        //
        //   c:\foo;c:\som"e;di"r;c:\bar
        //
        // Should parse as [c:\foo, c:\some;dir, c:\bar].
        //
        // (The above is based on testing; there is no clear reference available
        // for the grammar.)

        let must_yield = self.must_yield;
        self.must_yield = false;

        let mut in_progress = Vec::new();
        let mut in_quote = false;
        for b in self.data.by_ref() {
            if b == '"' as u16 {
                in_quote = !in_quote;
            } else if b == ';' as u16 && !in_quote {
                self.must_yield = true;
                break;
            } else {
                in_progress.push(b)
            }
        }

        if !must_yield && in_progress.is_empty() {
            None
        } else {
            Some(super::os2path(&in_progress))
        }
    }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where
    I: Iterator<Item = T>,
    T: AsRef<OsStr>,
{
    let mut joined = Vec::new();
    let sep = b';' as u16;

    for (i, path) in paths.enumerate() {
        let path = path.as_ref();
        if i > 0 {
            joined.push(sep)
        }
        let v = path.encode_wide().collect::<Vec<u16>>();
        if v.contains(&(b'"' as u16)) {
            return Err(JoinPathsError);
        } else if v.contains(&sep) {
            joined.push(b'"' as u16);
            joined.extend_from_slice(&v[..]);
            joined.push(b'"' as u16);
        } else {
            joined.extend_from_slice(&v[..]);
        }
    }

    Ok(OsStringExt::from_wide(&joined[..]))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains `\"`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        "failed to join paths"
    }
}

pub fn current_exe() -> io::Result<PathBuf> {
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
        super::os2path,
    )
}

pub fn getcwd() -> io::Result<PathBuf> {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let mut p = p.encode_wide().collect::<Vec<_>>();
    p.push(0);

    cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
    let k = to_u16s(k).ok()?;
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
        |buf| OsStringExt::from_wide(buf),
    )
    .ok()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = to_u16s(k)?;
    let v = to_u16s(v)?;

    cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(drop)
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let v = to_u16s(n)?;
    cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(drop)
}

pub fn temp_dir() -> PathBuf {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
}

#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
    unsafe {
        use crate::sys::handle::Handle;

        let me = c::GetCurrentProcess();
        let mut token = ptr::null_mut();
        if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
            return None;
        }
        let _handle = Handle::from_raw_handle(token);
        super::fill_utf16_buf(
            |buf, mut sz| {
                match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
                    0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
                    0 => sz,
                    _ => sz - 1, // sz includes the null terminator
                }
            },
            super::os2path,
        )
        .ok()
    }
}

#[cfg(target_vendor = "uwp")]
fn home_dir_crt() -> Option<PathBuf> {
    None
}

pub fn home_dir() -> Option<PathBuf> {
    crate::env::var_os("HOME")
        .or_else(|| crate::env::var_os("USERPROFILE"))
        .map(PathBuf::from)
        .or_else(|| home_dir_crt())
}

pub fn exit(code: i32) -> ! {
    unsafe { c::ExitProcess(code as c::UINT) }
}

pub fn getpid() -> u32 {
    unsafe { c::GetCurrentProcessId() as u32 }
}
<commit_msg>Add comment documenting why we can't use a simpler solution<commit_after>//! Implementation of `std::os` functionality for Windows.

#![allow(nonstandard_style)]

#[cfg(test)]
mod tests;

use crate::os::windows::prelude::*;

use crate::error::Error as StdError;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::os::windows::ffi::EncodeWide;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::sys::{c, cvt};

use super::to_u16s;

pub fn errno() -> i32 {
    unsafe { c::GetLastError() as i32 }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(mut errnum: i32) -> String {
    // This value is calculated from the macro
    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
    let langId = 0x0800 as c::DWORD;

    let mut buf = [0 as c::WCHAR; 2048];

    unsafe {
        let mut module = ptr::null_mut();
        let mut flags = 0;

        // NTSTATUS errors may be encoded as HRESULT, which may returned from
        // GetLastError. For more information about Windows error codes, see
        // `[MS-ERREF]`: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a
        if (errnum & c::FACILITY_NT_BIT as i32) != 0 {
            // format according to https://support.microsoft.com/en-us/help/259693
            const NTDLL_DLL: &[u16] = &[
                'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
                'L' as _, 0,
            ];
            module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());

            if !module.is_null() {
                errnum ^= c::FACILITY_NT_BIT as i32;
                flags = c::FORMAT_MESSAGE_FROM_HMODULE;
            }
        }

        let res = c::FormatMessageW(
            flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS,
            module,
            errnum as c::DWORD,
            langId,
            buf.as_mut_ptr(),
            buf.len() as c::DWORD,
            ptr::null(),
        ) as usize;
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g., system doesn't like langId,
            let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
        }

        match String::from_utf16(&buf[..res]) {
            Ok(mut msg) => {
                // Trim trailing CRLF inserted by FormatMessageW
                let len = msg.trim_end().len();
                msg.truncate(len);
                msg
            }
            Err(..) => format!(
                "OS Error {} (FormatMessageW() returned \
                 invalid UTF-16)",
                errnum
            ),
        }
    }
}

pub struct Env {
    base: c::LPWCH,
    cur: c::LPWCH,
}

impl Iterator for Env {
    type Item = (OsString, OsString);

    fn next(&mut self) -> Option<(OsString, OsString)> {
        loop {
            unsafe {
                if *self.cur == 0 {
                    return None;
                }
                let p = self.cur as *const u16;
                let mut len = 0;
                while *p.offset(len) != 0 {
                    len += 1;
                }
                let s = slice::from_raw_parts(p, len as usize);
                self.cur = self.cur.offset(len + 1);

                // Windows allows environment variables to start with an equals
                // symbol (in any other position, this is the separator between
                // variable name and value). Since`s` has at least length 1 at
                // this point (because the empty string terminates the array of
                // environment variables), we can safely slice.
                let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) {
                    Some(p) => p,
                    None => continue,
                };
                return Some((
                    OsStringExt::from_wide(&s[..pos]),
                    OsStringExt::from_wide(&s[pos + 1..]),
                ));
            }
        }
    }
}

impl Drop for Env {
    fn drop(&mut self) {
        unsafe {
            c::FreeEnvironmentStringsW(self.base);
        }
    }
}

pub fn env() -> Env {
    unsafe {
        let ch = c::GetEnvironmentStringsW();
        if ch as usize == 0 {
            panic!("failure getting env string from OS: {}", io::Error::last_os_error());
        }
        Env { base: ch, cur: ch }
    }
}

pub struct SplitPaths<'a> {
    data: EncodeWide<'a>,
    must_yield: bool,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    SplitPaths { data: unparsed.encode_wide(), must_yield: true }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> {
        // On Windows, the PATH environment variable is semicolon separated.
        // Double quotes are used as a way of introducing literal semicolons
        // (since c:\some;dir is a valid Windows path). Double quotes are not
        // themselves permitted in path names, so there is no way to escape a
        // double quote.  Quoted regions can appear in arbitrary locations, so
        //
        //   c:\foo;c:\som"e;di"r;c:\bar
        //
        // Should parse as [c:\foo, c:\some;dir, c:\bar].
        //
        // (The above is based on testing; there is no clear reference available
        // for the grammar.)

        let must_yield = self.must_yield;
        self.must_yield = false;

        let mut in_progress = Vec::new();
        let mut in_quote = false;
        for b in self.data.by_ref() {
            if b == '"' as u16 {
                in_quote = !in_quote;
            } else if b == ';' as u16 && !in_quote {
                self.must_yield = true;
                break;
            } else {
                in_progress.push(b)
            }
        }

        if !must_yield && in_progress.is_empty() {
            None
        } else {
            Some(super::os2path(&in_progress))
        }
    }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where
    I: Iterator<Item = T>,
    T: AsRef<OsStr>,
{
    let mut joined = Vec::new();
    let sep = b';' as u16;

    for (i, path) in paths.enumerate() {
        let path = path.as_ref();
        if i > 0 {
            joined.push(sep)
        }
        let v = path.encode_wide().collect::<Vec<u16>>();
        if v.contains(&(b'"' as u16)) {
            return Err(JoinPathsError);
        } else if v.contains(&sep) {
            joined.push(b'"' as u16);
            joined.extend_from_slice(&v[..]);
            joined.push(b'"' as u16);
        } else {
            joined.extend_from_slice(&v[..]);
        }
    }

    Ok(OsStringExt::from_wide(&joined[..]))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains `\"`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    #[allow(deprecated)]
    fn description(&self) -> &str {
        "failed to join paths"
    }
}

pub fn current_exe() -> io::Result<PathBuf> {
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
        super::os2path,
    )
}

pub fn getcwd() -> io::Result<PathBuf> {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let mut p = p.encode_wide().collect::<Vec<_>>();
    p.push(0);

    cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop)
}

pub fn getenv(k: &OsStr) -> Option<OsString> {
    let k = to_u16s(k).ok()?;
    super::fill_utf16_buf(
        |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
        |buf| OsStringExt::from_wide(buf),
    )
    .ok()
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = to_u16s(k)?;
    let v = to_u16s(v)?;

    cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(drop)
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let v = to_u16s(n)?;
    cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(drop)
}

pub fn temp_dir() -> PathBuf {
    super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
}

#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
    unsafe {
        // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
        // instead of us having to go through these multiple steps to get a token. However this is
        // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
        // we can simplify this code. See #90144 for details.
        use crate::sys::handle::Handle;

        let me = c::GetCurrentProcess();
        let mut token = ptr::null_mut();
        if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
            return None;
        }
        let _handle = Handle::from_raw_handle(token);
        super::fill_utf16_buf(
            |buf, mut sz| {
                match c::GetUserProfileDirectoryW(token, buf, &mut sz) {
                    0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0,
                    0 => sz,
                    _ => sz - 1, // sz includes the null terminator
                }
            },
            super::os2path,
        )
        .ok()
    }
}

#[cfg(target_vendor = "uwp")]
fn home_dir_crt() -> Option<PathBuf> {
    None
}

pub fn home_dir() -> Option<PathBuf> {
    crate::env::var_os("HOME")
        .or_else(|| crate::env::var_os("USERPROFILE"))
        .map(PathBuf::from)
        .or_else(|| home_dir_crt())
}

pub fn exit(code: i32) -> ! {
    unsafe { c::ExitProcess(code as c::UINT) }
}

pub fn getpid() -> u32 {
    unsafe { c::GetCurrentProcessId() as u32 }
}
<|endoftext|>


<commit_before>use crate::sys::time;

#[inline]
pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
    inner::monotonize(raw)
}

#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
pub mod inner {
    use crate::sync::atomic::AtomicU64;
    use crate::sync::atomic::Ordering::*;
    use crate::sys::time;
    use crate::time::Duration;

    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();

    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
    const UNINITIALIZED: u64 = 0b11 << 30;
    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);

    #[inline]
    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
        monotonize_impl(&MONO, raw)
    }

    #[inline]
    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
        let delta = raw.checked_sub_instant(&ZERO).unwrap();
        let secs = delta.as_secs();
        // occupies no more than 30 bits (10^9 seconds)
        let nanos = delta.subsec_nanos() as u64;

        // This wraps around every 136 years (2^32 seconds).
        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
        // than 2^31 seconds as expected and everything else as a backslide which will be
        // monotonized.
        // This could be a problem for programs that call instants at intervals greater
        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
        let packed = (secs << 32) | nanos;
        let old = mono.load(Relaxed);

        if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
            mono.store(packed, Relaxed);
            raw
        } else {
            // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
            // passed in value and the 64bits loaded from the atomic
            let seconds_lower = old >> 32;
            let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
            if secs & 0xffff_ffff > seconds_lower {
                // Backslide caused the lower 32bit of the seconds part to wrap.
                // This must be the case because the seconds part is larger even though
                // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
                //
                // We assume that backslides are smaller than 2^32 seconds
                // which means we need to add 1 to the upper half to restore it.
                //
                // Example:
                // most recent observed time: 0xA1_0000_0000_0000_0000u128
                // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
                // backslide by 1s
                // caller time is             0xA0_ffff_ffff_0000_0000u128
                // -> we can fix up the upper half time by adding 1 << 32
                seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
            }
            let secs = seconds_upper | seconds_lower;
            let nanos = old as u32;
            ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
        }
    }
}

#[cfg(target_has_atomic = "128")]
pub mod inner {
    use crate::sync::atomic::AtomicU128;
    use crate::sync::atomic::Ordering::*;
    use crate::sys::time;
    use crate::time::Duration;

    const ZERO: time::Instant = time::Instant::zero();
    static MONO: AtomicU128 = AtomicU128::new(0);

    #[inline]
    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
        let delta = raw.checked_sub_instant(&ZERO).unwrap();
        // Split into seconds and nanos since Duration doesn't have a
        // constructor that takes a u128
        let secs = delta.as_secs() as u128;
        let nanos = delta.subsec_nanos() as u128;
        let timestamp: u128 = secs << 64 | nanos;
        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
        let secs = (timestamp >> 64) as u64;
        let nanos = timestamp as u32;
        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
    }
}

#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
pub mod inner {
    use crate::cmp;
    use crate::sys::time;
    use crate::sys_common::mutex::StaticMutex;

    #[inline]
    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
        static LOCK: StaticMutex = StaticMutex::new();
        static mut LAST_NOW: time::Instant = time::Instant::zero();
        unsafe {
            let _lock = LOCK.lock();
            let now = cmp::max(LAST_NOW, os_now);
            LAST_NOW = now;
            now
        }
    }
}
<commit_msg>fix potential race in AtomicU64 time monotonizer<commit_after>use crate::sys::time;

#[inline]
pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
    inner::monotonize(raw)
}

#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
pub mod inner {
    use crate::sync::atomic::AtomicU64;
    use crate::sync::atomic::Ordering::*;
    use crate::sys::time;
    use crate::time::Duration;

    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();

    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
    const UNINITIALIZED: u64 = 0b11 << 30;
    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);

    #[inline]
    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
        monotonize_impl(&MONO, raw)
    }

    #[inline]
    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
        let delta = raw.checked_sub_instant(&ZERO).unwrap();
        let secs = delta.as_secs();
        // occupies no more than 30 bits (10^9 seconds)
        let nanos = delta.subsec_nanos() as u64;

        // This wraps around every 136 years (2^32 seconds).
        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
        // than 2^31 seconds as expected and everything else as a backslide which will be
        // monotonized.
        // This could be a problem for programs that call instants at intervals greater
        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
        let packed = (secs << 32) | nanos;
        let mut old = mono.load(Relaxed);
        loop {
            if old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2 {
                match mono.compare_exchange_weak(old, packed, Relaxed, Relaxed) {
                    Ok(_) => return raw,
                    Err(x) => {
                        old = x;
                        continue;
                    }
                }
            } else {
                // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
                // passed in value and the 64bits loaded from the atomic
                let seconds_lower = old >> 32;
                let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
                if secs & 0xffff_ffff > seconds_lower {
                    // Backslide caused the lower 32bit of the seconds part to wrap.
                    // This must be the case because the seconds part is larger even though
                    // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
                    //
                    // We assume that backslides are smaller than 2^32 seconds
                    // which means we need to add 1 to the upper half to restore it.
                    //
                    // Example:
                    // most recent observed time: 0xA1_0000_0000_0000_0000u128
                    // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
                    // backslide by 1s
                    // caller time is             0xA0_ffff_ffff_0000_0000u128
                    // -> we can fix up the upper half time by adding 1 << 32
                    seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
                }
                let secs = seconds_upper | seconds_lower;
                let nanos = old as u32;
                return ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap();
            }
        }
    }
}

#[cfg(target_has_atomic = "128")]
pub mod inner {
    use crate::sync::atomic::AtomicU128;
    use crate::sync::atomic::Ordering::*;
    use crate::sys::time;
    use crate::time::Duration;

    const ZERO: time::Instant = time::Instant::zero();
    static MONO: AtomicU128 = AtomicU128::new(0);

    #[inline]
    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
        let delta = raw.checked_sub_instant(&ZERO).unwrap();
        // Split into seconds and nanos since Duration doesn't have a
        // constructor that takes a u128
        let secs = delta.as_secs() as u128;
        let nanos = delta.subsec_nanos() as u128;
        let timestamp: u128 = secs << 64 | nanos;
        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
        let secs = (timestamp >> 64) as u64;
        let nanos = timestamp as u32;
        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
    }
}

#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
pub mod inner {
    use crate::cmp;
    use crate::sys::time;
    use crate::sys_common::mutex::StaticMutex;

    #[inline]
    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
        static LOCK: StaticMutex = StaticMutex::new();
        static mut LAST_NOW: time::Instant = time::Instant::zero();
        unsafe {
            let _lock = LOCK.lock();
            let now = cmp::max(LAST_NOW, os_now);
            LAST_NOW = now;
            now
        }
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use ra_parser::Token as PToken;
use ra_parser::TokenSource;

use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize};

pub(crate) struct TextTokenSource<'t> {
    text: &'t str,
    /// start position of each token(expect whitespace and comment)
    /// ```non-rust
    ///  struct Foo;
    /// ^------^---
    /// |      |  ^-
    /// 0      7  10
    /// ```
    /// (token, start_offset): `[(struct, 0), (Foo, 7), (;, 10)]`
    start_offsets: Vec<TextSize>,
    /// non-whitespace/comment tokens
    /// ```non-rust
    /// struct Foo {}
    /// ^^^^^^ ^^^ ^^
    /// ```
    /// tokens: `[struct, Foo, {, }]`
    tokens: Vec<Token>,

    /// Current token and position
    curr: (PToken, usize),
}

impl<'t> TokenSource for TextTokenSource<'t> {
    fn current(&self) -> PToken {
        self.curr.0
    }

    fn lookahead_nth(&self, n: usize) -> PToken {
        mk_token(self.curr.1 + n, &self.start_offsets, &self.tokens)
    }

    fn bump(&mut self) {
        if self.curr.0.kind == EOF {
            return;
        }

        let pos = self.curr.1 + 1;
        self.curr = (mk_token(pos, &self.start_offsets, &self.tokens), pos);
    }

    fn is_keyword(&self, kw: &str) -> bool {
        let pos = self.curr.1;
        if pos >= self.tokens.len() {
            return false;
        }
        let range = TextRange::at(self.start_offsets[pos], self.tokens[pos].len);
        self.text[range] == *kw
    }
}

fn mk_token(pos: usize, start_offsets: &[TextSize], tokens: &[Token]) -> PToken {
    let kind = tokens.get(pos).map(|t| t.kind).unwrap_or(EOF);
    let is_jointed_to_next = if pos + 1 < start_offsets.len() {
        start_offsets[pos] + tokens[pos].len == start_offsets[pos + 1]
    } else {
        false
    };

    PToken { kind, is_jointed_to_next }
}

impl<'t> TextTokenSource<'t> {
    /// Generate input from tokens(expect comment and whitespace).
    pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> {
        let mut tokens = Vec::new();
        let mut start_offsets = Vec::new();
        let mut len = 0.into();
        for &token in raw_tokens.iter() {
            if !token.kind.is_trivia() {
                tokens.push(token);
                start_offsets.push(len);
            }
            len += token.len;
        }

        let first = mk_token(0, &start_offsets, &tokens);
        TextTokenSource { text, start_offsets, tokens, curr: (first, 0) }
    }
}
<commit_msg>Reduce the usage of bare subscript operator<commit_after>//! See `TextTokenSource` docs.

use ra_parser::TokenSource;

use crate::{parsing::lexer::Token, SyntaxKind::EOF, TextRange, TextSize};

/// Implementation of `ra_parser::TokenSource` that takes tokens from source code text.
pub(crate) struct TextTokenSource<'t> {
    text: &'t str,
    /// token and its start position (non-whitespace/comment tokens)
    /// ```non-rust
    ///  struct Foo;
    ///  ^------^--^-
    ///  |      |    \________
    ///  |      \____         \
    ///  |           \         |
    ///  (struct, 0) (Foo, 7) (;, 10)
    /// ```
    /// `[(struct, 0), (Foo, 7), (;, 10)]`
    token_offset_pairs: Vec<(Token, TextSize)>,

    /// Current token and position
    curr: (ra_parser::Token, usize),
}

impl<'t> TokenSource for TextTokenSource<'t> {
    fn current(&self) -> ra_parser::Token {
        self.curr.0
    }

    fn lookahead_nth(&self, n: usize) -> ra_parser::Token {
        mk_token(self.curr.1 + n, &self.token_offset_pairs)
    }

    fn bump(&mut self) {
        if self.curr.0.kind == EOF {
            return;
        }

        let pos = self.curr.1 + 1;
        self.curr = (mk_token(pos, &self.token_offset_pairs), pos);
    }

    fn is_keyword(&self, kw: &str) -> bool {
        self.token_offset_pairs
            .get(self.curr.1)
            .map(|(token, offset)| &self.text[TextRange::at(*offset, token.len)] == kw)
            .unwrap_or(false)
    }
}

fn mk_token(pos: usize, token_offset_pairs: &[(Token, TextSize)]) -> ra_parser::Token {
    let (kind, is_jointed_to_next) = match token_offset_pairs.get(pos) {
        Some((token, offset)) => (
            token.kind,
            token_offset_pairs
                .get(pos + 1)
                .map(|(_, next_offset)| offset + token.len == *next_offset)
                .unwrap_or(false),
        ),
        None => (EOF, false),
    };
    ra_parser::Token { kind, is_jointed_to_next }
}

impl<'t> TextTokenSource<'t> {
    /// Generate input from tokens(expect comment and whitespace).
    pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> TextTokenSource<'t> {
        let token_offset_pairs: Vec<_> = raw_tokens
            .iter()
            .filter_map({
                let mut len = 0.into();
                move |token| {
                    let pair = if token.kind.is_trivia() { None } else { Some((*token, len)) };
                    len += token.len;
                    pair
                }
            })
            .collect();

        let first = mk_token(0, &token_offset_pairs);
        TextTokenSource { text, token_offset_pairs, curr: (first, 0) }
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2018 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Functionality to help Oak Nodes interact with gRPC.

pub use crate::proto::code::Code;
use crate::{proto, OakError, OakStatus, ReadHandle};
use log::{info, warn};
use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use protobuf::{Message, ProtobufEnum};

mod invocation;
pub use invocation::Invocation;

/// Result type that uses a [`proto::status::Status`] type for error values.
pub type Result<T> = std::result::Result<T, proto::status::Status>;

/// Helper to create a gRPC status object.
pub fn build_status(code: Code, msg: &str) -> proto::status::Status {
    let mut status = proto::status::Status::new();
    status.set_code(code.value());
    status.set_message(msg.to_string());
    status
}

impl crate::io::Encodable for GrpcRequest {
    fn encode(&self) -> std::result::Result<crate::io::Message, crate::OakError> {
        let bytes = self.write_to_bytes()?;
        let handles = Vec::new();
        Ok(crate::io::Message { bytes, handles })
    }
}

impl crate::io::Decodable for GrpcRequest {
    fn decode(message: &crate::io::Message) -> std::result::Result<Self, crate::OakError> {
        let value = protobuf::parse_from_bytes(&message.bytes)?;
        Ok(value)
    }
}

/// Channel-holding object that encapsulates response messages into
/// `GrpcResponse` wrapper messages and writes serialized versions to a send
/// channel.
pub struct ChannelResponseWriter {
    sender: crate::io::Sender<GrpcResponse>,
}

impl crate::io::Encodable for GrpcResponse {
    fn encode(&self) -> std::result::Result<crate::io::Message, crate::OakError> {
        let bytes = self.write_to_bytes()?;
        let handles = Vec::new();
        Ok(crate::io::Message { bytes, handles })
    }
}

/// Indicate whether a write method should leave the current gRPC method
/// invocation open or close it.
#[derive(PartialEq, Clone, Debug)]
pub enum WriteMode {
    KeepOpen,
    Close,
}

impl ChannelResponseWriter {
    pub fn new(sender: crate::io::Sender<GrpcResponse>) -> Self {
        ChannelResponseWriter { sender }
    }

    /// Retrieve the Oak handle underlying the writer object.
    pub fn handle(self) -> crate::WriteHandle {
        self.sender.handle
    }

    /// Write out a gRPC response and optionally close out the method
    /// invocation.  Any errors from the channel are silently dropped.
    pub fn write<T: protobuf::Message>(
        &mut self,
        rsp: &T,
        mode: WriteMode,
    ) -> std::result::Result<(), OakError> {
        // Put the serialized response into a GrpcResponse message wrapper and
        // serialize it into the channel.
        let mut grpc_rsp = GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value)?;
        grpc_rsp.set_rsp_msg(any);
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Write an empty gRPC response and optionally close out the method
    /// invocation. Any errors from the channel are silently dropped.
    pub fn write_empty(&mut self, mode: WriteMode) -> std::result::Result<(), OakError> {
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_rsp_msg(protobuf::well_known_types::Any::new());
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Close out the gRPC method invocation with the given final result.
    pub fn close(&mut self, result: Result<()>) -> std::result::Result<(), OakError> {
        // Build a final GrpcResponse message wrapper and serialize it into the
        // channel.
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_last(true);
        if let Err(status) = result {
            grpc_rsp.set_status(status);
        }
        self.sender.send(&grpc_rsp)?;
        self.sender.close()?;
        Ok(())
    }
}

/// Trait for Oak Nodes that act as a gRPC services.
///
/// An `OakNode` instance is normally passed to [`event_loop`], to allow
/// repeated invocation of its `invoke()` method.
pub trait OakNode {
    /// Construct the (single) instance of the node.
    ///
    /// This method may choose to initialize logging by invoking
    /// [`oak_log::init()`].
    ///
    /// [`oak_log::init()`]: ../../oak_log/fn.init.html
    fn new() -> Self
    where
        Self: Sized;

    /// Process a single gRPC method invocation.
    ///
    /// The method name is provided by `method` and the incoming serialized gRPC
    /// request is held in `req`.  Response messages should be written using
    /// `writer.write`, followed by `writer.close`.
    fn invoke(&mut self, method: &str, req: &[u8], writer: ChannelResponseWriter);
}

/// Encapsulate a protocol buffer message in a GrpcRequest wrapper using the
/// given method name.
pub fn encap_request<T: protobuf::Message>(req: T, method_name: &str) -> Option<GrpcRequest> {
    // Put the request in a GrpcRequest wrapper and serialize it.
    let mut grpc_req = GrpcRequest::new();
    grpc_req.set_method_name(method_name.to_string());
    let mut any = protobuf::well_known_types::Any::new();
    if let Err(e) = req.write_to_writer(&mut any.value) {
        warn!("failed to serialize gRPC request: {}", e);
        return None;
    };
    grpc_req.set_req_msg(any);
    grpc_req.set_last(true);
    Some(grpc_req)
}

/// Perform a gRPC event loop for a Node.
///
/// Invoking the given `node`'s [`invoke`] method for each incoming request that
/// arrives on the inbound channel as a serialized [`GrpcRequest`] message,
/// giving the [`invoke`] method the outbound channel for encapsulated responses
/// to be written to.
///
/// [`invoke`]: OakNode::invoke
/// [`GrpcRequest`]: crate::proto::grpc_encap::GrpcRequest
pub fn event_loop<T: OakNode>(
    mut node: T,
    grpc_in_handle: ReadHandle,
) -> std::result::Result<(), crate::OakStatus> {
    info!("start event loop for node with handle {:?}", grpc_in_handle);
    if !grpc_in_handle.handle.is_valid() {
        return Err(OakStatus::ERR_CHANNEL_CLOSED);
    }
    let invocation_receiver = crate::io::Receiver::new(grpc_in_handle);
    loop {
        // Explicitly call `wait` and then `try_receive` here because calling `receive` would hide
        // any `OakStatus::ERR_TERMINATED` errors that may occur in the `wait` phase, since they
        // would be wrapped in a `OakError` value that would then always be unwrapped and panic.
        invocation_receiver.wait()?;
        let invocation: Invocation = invocation_receiver.try_receive().unwrap_or_else(|err| {
            panic!("could not receive gRPC invocation: {}", err);
        });

        // Read a single encapsulated request message from the read half.
        let req: GrpcRequest = invocation.request_receiver.receive().unwrap_or_else(|err| {
            panic!("could not read gRPC request: {:?}", err);
        });
        // Since we are expecting a single message, close the channel immediately.
        // This will change when we implement client streaming (#97).
        invocation.request_receiver.close().unwrap_or_else(|err| {
            panic!("could not close gRPC request channel: {:?}", err);
        });
        if !req.last {
            // TODO(#97): Implement client streaming.
            panic!("Support for streaming requests not yet implemented");
        }
        node.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            ChannelResponseWriter::new(invocation.response_sender),
        );
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request/response pair.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(R) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    let result = match node_fn(r) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request and streams responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(R, ChannelResponseWriter),
    R: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    node_fn(r, writer)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a response.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    let result = match node_fn(rr) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a stream of responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>, ChannelResponseWriter),
    R: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    node_fn(rr, writer)
}
<commit_msg>sdk: implement Decodable for GrpcResponse<commit_after>//
// Copyright 2018 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Functionality to help Oak Nodes interact with gRPC.

pub use crate::proto::code::Code;
use crate::{proto, OakError, OakStatus, ReadHandle};
use log::{info, warn};
use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use protobuf::{Message, ProtobufEnum};

mod invocation;
pub use invocation::Invocation;

/// Result type that uses a [`proto::status::Status`] type for error values.
pub type Result<T> = std::result::Result<T, proto::status::Status>;

/// Helper to create a gRPC status object.
pub fn build_status(code: Code, msg: &str) -> proto::status::Status {
    let mut status = proto::status::Status::new();
    status.set_code(code.value());
    status.set_message(msg.to_string());
    status
}

impl crate::io::Encodable for GrpcRequest {
    fn encode(&self) -> std::result::Result<crate::io::Message, crate::OakError> {
        let bytes = self.write_to_bytes()?;
        let handles = Vec::new();
        Ok(crate::io::Message { bytes, handles })
    }
}

impl crate::io::Decodable for GrpcRequest {
    fn decode(message: &crate::io::Message) -> std::result::Result<Self, crate::OakError> {
        let value = protobuf::parse_from_bytes(&message.bytes)?;
        Ok(value)
    }
}

/// Channel-holding object that encapsulates response messages into
/// `GrpcResponse` wrapper messages and writes serialized versions to a send
/// channel.
pub struct ChannelResponseWriter {
    sender: crate::io::Sender<GrpcResponse>,
}

impl crate::io::Encodable for GrpcResponse {
    fn encode(&self) -> std::result::Result<crate::io::Message, crate::OakError> {
        let bytes = self.write_to_bytes()?;
        let handles = Vec::new();
        Ok(crate::io::Message { bytes, handles })
    }
}

impl crate::io::Decodable for GrpcResponse {
    fn decode(message: &crate::io::Message) -> std::result::Result<Self, crate::OakError> {
        let value = protobuf::parse_from_bytes(&message.bytes)?;
        Ok(value)
    }
}

/// Indicate whether a write method should leave the current gRPC method
/// invocation open or close it.
#[derive(PartialEq, Clone, Debug)]
pub enum WriteMode {
    KeepOpen,
    Close,
}

impl ChannelResponseWriter {
    pub fn new(sender: crate::io::Sender<GrpcResponse>) -> Self {
        ChannelResponseWriter { sender }
    }

    /// Retrieve the Oak handle underlying the writer object.
    pub fn handle(self) -> crate::WriteHandle {
        self.sender.handle
    }

    /// Write out a gRPC response and optionally close out the method
    /// invocation.  Any errors from the channel are silently dropped.
    pub fn write<T: protobuf::Message>(
        &mut self,
        rsp: &T,
        mode: WriteMode,
    ) -> std::result::Result<(), OakError> {
        // Put the serialized response into a GrpcResponse message wrapper and
        // serialize it into the channel.
        let mut grpc_rsp = GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value)?;
        grpc_rsp.set_rsp_msg(any);
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Write an empty gRPC response and optionally close out the method
    /// invocation. Any errors from the channel are silently dropped.
    pub fn write_empty(&mut self, mode: WriteMode) -> std::result::Result<(), OakError> {
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_rsp_msg(protobuf::well_known_types::Any::new());
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Close out the gRPC method invocation with the given final result.
    pub fn close(&mut self, result: Result<()>) -> std::result::Result<(), OakError> {
        // Build a final GrpcResponse message wrapper and serialize it into the
        // channel.
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_last(true);
        if let Err(status) = result {
            grpc_rsp.set_status(status);
        }
        self.sender.send(&grpc_rsp)?;
        self.sender.close()?;
        Ok(())
    }
}

/// Trait for Oak Nodes that act as a gRPC services.
///
/// An `OakNode` instance is normally passed to [`event_loop`], to allow
/// repeated invocation of its `invoke()` method.
pub trait OakNode {
    /// Construct the (single) instance of the node.
    ///
    /// This method may choose to initialize logging by invoking
    /// [`oak_log::init()`].
    ///
    /// [`oak_log::init()`]: ../../oak_log/fn.init.html
    fn new() -> Self
    where
        Self: Sized;

    /// Process a single gRPC method invocation.
    ///
    /// The method name is provided by `method` and the incoming serialized gRPC
    /// request is held in `req`.  Response messages should be written using
    /// `writer.write`, followed by `writer.close`.
    fn invoke(&mut self, method: &str, req: &[u8], writer: ChannelResponseWriter);
}

/// Encapsulate a protocol buffer message in a GrpcRequest wrapper using the
/// given method name.
pub fn encap_request<T: protobuf::Message>(req: T, method_name: &str) -> Option<GrpcRequest> {
    // Put the request in a GrpcRequest wrapper and serialize it.
    let mut grpc_req = GrpcRequest::new();
    grpc_req.set_method_name(method_name.to_string());
    let mut any = protobuf::well_known_types::Any::new();
    if let Err(e) = req.write_to_writer(&mut any.value) {
        warn!("failed to serialize gRPC request: {}", e);
        return None;
    };
    grpc_req.set_req_msg(any);
    grpc_req.set_last(true);
    Some(grpc_req)
}

/// Perform a gRPC event loop for a Node.
///
/// Invoking the given `node`'s [`invoke`] method for each incoming request that
/// arrives on the inbound channel as a serialized [`GrpcRequest`] message,
/// giving the [`invoke`] method the outbound channel for encapsulated responses
/// to be written to.
///
/// [`invoke`]: OakNode::invoke
/// [`GrpcRequest`]: crate::proto::grpc_encap::GrpcRequest
pub fn event_loop<T: OakNode>(
    mut node: T,
    grpc_in_handle: ReadHandle,
) -> std::result::Result<(), crate::OakStatus> {
    info!("start event loop for node with handle {:?}", grpc_in_handle);
    if !grpc_in_handle.handle.is_valid() {
        return Err(OakStatus::ERR_CHANNEL_CLOSED);
    }
    let invocation_receiver = crate::io::Receiver::new(grpc_in_handle);
    loop {
        // Explicitly call `wait` and then `try_receive` here because calling `receive` would hide
        // any `OakStatus::ERR_TERMINATED` errors that may occur in the `wait` phase, since they
        // would be wrapped in a `OakError` value that would then always be unwrapped and panic.
        invocation_receiver.wait()?;
        let invocation: Invocation = invocation_receiver.try_receive().unwrap_or_else(|err| {
            panic!("could not receive gRPC invocation: {}", err);
        });

        // Read a single encapsulated request message from the read half.
        let req: GrpcRequest = invocation.request_receiver.receive().unwrap_or_else(|err| {
            panic!("could not read gRPC request: {:?}", err);
        });
        // Since we are expecting a single message, close the channel immediately.
        // This will change when we implement client streaming (#97).
        invocation.request_receiver.close().unwrap_or_else(|err| {
            panic!("could not close gRPC request channel: {:?}", err);
        });
        if !req.last {
            // TODO(#97): Implement client streaming.
            panic!("Support for streaming requests not yet implemented");
        }
        node.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            ChannelResponseWriter::new(invocation.response_sender),
        );
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request/response pair.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(R) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    let result = match node_fn(r) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request and streams responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(R, ChannelResponseWriter),
    R: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    node_fn(r, writer)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a response.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    let result = match node_fn(rr) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a stream of responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>, ChannelResponseWriter),
    R: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    node_fn(rr, writer)
}
<|endoftext|>


<commit_before>use axum::{body, http::StatusCode, response::Response};
use shakmaty::{san::SanError, uci::IllegalUciError, variant::VariantPosition, PositionError};
use thiserror::Error;

use crate::model::GameId;

#[derive(Error, Debug)]
pub enum Error {
    #[error("bad request: {0}")]
    PositionError(#[from] PositionError<VariantPosition>),
    #[error("bad request: {0}")]
    IllegalUciError(#[from] IllegalUciError),
    #[error("bad request: {0}")]
    SanError(#[from] SanError),
    #[error("duplicate game {0}")]
    DuplicateGame(GameId),
    #[error("rejected import of {0}")]
    RejectedImport(GameId),
}

impl axum::response::IntoResponse for Error {
    fn into_response(self) -> Response {
        Response::builder()
            .status(StatusCode::BAD_REQUEST)
            .body(body::boxed(body::Full::from(self.to_string())))
            .unwrap()
    }
}
<commit_msg>simplify error body building<commit_after>use axum::{http::StatusCode, response::Response};
use shakmaty::{san::SanError, uci::IllegalUciError, variant::VariantPosition, PositionError};
use thiserror::Error;

use crate::model::GameId;

#[derive(Error, Debug)]
pub enum Error {
    #[error("bad request: {0}")]
    PositionError(#[from] PositionError<VariantPosition>),
    #[error("bad request: {0}")]
    IllegalUciError(#[from] IllegalUciError),
    #[error("bad request: {0}")]
    SanError(#[from] SanError),
    #[error("duplicate game {0}")]
    DuplicateGame(GameId),
    #[error("rejected import of {0}")]
    RejectedImport(GameId),
}

impl axum::response::IntoResponse for Error {
    fn into_response(self) -> Response {
        (StatusCode::BAD_REQUEST, self.to_string()).into_response()
    }
}
<|endoftext|>